Home | History | Annotate | Download | only in hxge
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <hxge_impl.h>
     27 #include <hxge_vmac.h>
     28 #include <hxge_pfc.h>
     29 #include <hpi_pfc.h>
     30 
     31 static hxge_status_t hxge_get_mac_addr_properties(p_hxge_t);
     32 static void hxge_use_cfg_hydra_properties(p_hxge_t);
     33 static void hxge_use_cfg_dma_config(p_hxge_t);
     34 static void hxge_use_cfg_class_config(p_hxge_t);
     35 static void hxge_set_hw_dma_config(p_hxge_t);
     36 static void hxge_set_hw_class_config(p_hxge_t);
     37 static void hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
     38 	uint8_t endldg, int *ngrps);
     39 
     40 extern uint16_t hxge_rcr_timeout;
     41 extern uint16_t hxge_rcr_threshold;
     42 
     43 extern uint32_t hxge_rbr_size;
     44 extern uint32_t hxge_rcr_size;
     45 
     46 extern uint_t hxge_rx_intr();
     47 extern uint_t hxge_tx_intr();
     48 extern uint_t hxge_vmac_intr();
     49 extern uint_t hxge_syserr_intr();
     50 extern uint_t hxge_pfc_intr();
     51 
     52 /*
     53  * Entry point to populate configuration parameters into the master hxge
     54  * data structure and to update the NDD parameter list.
     55  */
     56 hxge_status_t
     57 hxge_get_config_properties(p_hxge_t hxgep)
     58 {
     59 	hxge_status_t		status = HXGE_OK;
     60 
     61 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " ==> hxge_get_config_properties"));
     62 
     63 	if (hxgep->hxge_hw_p == NULL) {
     64 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
     65 		    " hxge_get_config_properties: common hardware not set"));
     66 		return (HXGE_ERROR);
     67 	}
     68 
     69 	hxgep->classifier.tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
     70 
     71 	status = hxge_get_mac_addr_properties(hxgep);
     72 	if (status != HXGE_OK) {
     73 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
     74 		    " hxge_get_config_properties: mac addr properties failed"));
     75 		return (status);
     76 	}
     77 
     78 	HXGE_DEBUG_MSG((hxgep, VPD_CTL,
     79 	    " ==> hxge_get_config_properties: Hydra"));
     80 
     81 	hxge_use_cfg_hydra_properties(hxgep);
     82 
     83 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " <== hxge_get_config_properties"));
     84 	return (HXGE_OK);
     85 }
     86 
     87 
     88 static void
     89 hxge_set_hw_vlan_class_config(p_hxge_t hxgep)
     90 {
     91 	int			i;
     92 	p_hxge_param_t		param_arr;
     93 	uint_t			vlan_cnt;
     94 	int			*vlan_cfg_val;
     95 	hxge_param_map_t	*vmap;
     96 	char			*prop;
     97 	p_hxge_class_pt_cfg_t 	p_class_cfgp;
     98 	uint32_t		good_cfg[32];
     99 	int			good_count = 0;
    100 	hxge_mv_cfg_t		*vlan_tbl;
    101 
    102 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_vlan_config"));
    103 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
    104 
    105 	param_arr = hxgep->param_arr;
    106 	prop = param_arr[param_vlan_ids].fcode_name;
    107 
    108 	/*
    109 	 * uint32_t array, each array entry specifying a VLAN id
    110 	 */
    111 	for (i = 0; i <= VLAN_ID_MAX; i++) {
    112 		p_class_cfgp->vlan_tbl[i].flag = 0;
    113 	}
    114 
    115 	vlan_tbl = (hxge_mv_cfg_t *)&p_class_cfgp->vlan_tbl[0];
    116 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
    117 	    &vlan_cfg_val, &vlan_cnt) != DDI_PROP_SUCCESS) {
    118 		return;
    119 	}
    120 
    121 	for (i = 0; i < vlan_cnt; i++) {
    122 		vmap = (hxge_param_map_t *)&vlan_cfg_val[i];
    123 		if ((vmap->param_id) && (vmap->param_id <= VLAN_ID_MAX)) {
    124 			HXGE_DEBUG_MSG((hxgep, CFG2_CTL,
    125 			    " hxge_vlan_config vlan id %d", vmap->param_id));
    126 
    127 			good_cfg[good_count] = vlan_cfg_val[i];
    128 			if (vlan_tbl[vmap->param_id].flag == 0)
    129 				good_count++;
    130 
    131 			vlan_tbl[vmap->param_id].flag = 1;
    132 		}
    133 	}
    134 
    135 	ddi_prop_free(vlan_cfg_val);
    136 	if (good_count != vlan_cnt) {
    137 		(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
    138 		    hxgep->dip, prop, (int *)good_cfg, good_count);
    139 	}
    140 
    141 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_vlan_config"));
    142 }
    143 
    144 
    145 /*
    146  * Read param_vlan_ids and param_implicit_vlan_id properties from either
    147  * hxge.conf or OBP. Update the soft properties. Populate these
    148  * properties into the hxge data structure.
    149  */
    150 static void
    151 hxge_use_cfg_vlan_class_config(p_hxge_t hxgep)
    152 {
    153 	uint_t		vlan_cnt;
    154 	int		*vlan_cfg_val;
    155 	int		status;
    156 	p_hxge_param_t	param_arr;
    157 	char		*prop;
    158 	uint32_t	implicit_vlan_id = 0;
    159 	int		*int_prop_val;
    160 	uint_t		prop_len;
    161 	p_hxge_param_t	pa;
    162 
    163 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_vlan_config"));
    164 	param_arr = hxgep->param_arr;
    165 	prop = param_arr[param_vlan_ids].fcode_name;
    166 
    167 	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
    168 	    &vlan_cfg_val, &vlan_cnt);
    169 	if (status == DDI_PROP_SUCCESS) {
    170 		status = ddi_prop_update_int_array(DDI_DEV_T_NONE,
    171 		    hxgep->dip, prop, vlan_cfg_val, vlan_cnt);
    172 		ddi_prop_free(vlan_cfg_val);
    173 	}
    174 
    175 	pa = &param_arr[param_implicit_vlan_id];
    176 	prop = pa->fcode_name;
    177 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
    178 	    &int_prop_val, &prop_len) == DDI_PROP_SUCCESS) {
    179 		implicit_vlan_id = (uint32_t)*int_prop_val;
    180 		if ((implicit_vlan_id >= pa->minimum) ||
    181 		    (implicit_vlan_id <= pa->maximum)) {
    182 			status = ddi_prop_update_int(DDI_DEV_T_NONE, hxgep->dip,
    183 			    prop, (int)implicit_vlan_id);
    184 		}
    185 		ddi_prop_free(int_prop_val);
    186 	}
    187 
    188 	hxge_set_hw_vlan_class_config(hxgep);
    189 
    190 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_vlan_config"));
    191 }
    192 
    193 /*
    194  * Read in the configuration parameters from either hxge.conf or OBP and
    195  * populate the master data structure hxge.
    196  * Use these parameters to update the soft properties and the ndd array.
    197  */
    198 static void
    199 hxge_use_cfg_hydra_properties(p_hxge_t hxgep)
    200 {
    201 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_hydra_properties"));
    202 
    203 	(void) hxge_use_cfg_dma_config(hxgep);
    204 	(void) hxge_use_cfg_vlan_class_config(hxgep);
    205 	(void) hxge_use_cfg_class_config(hxgep);
    206 
    207 	/*
    208 	 * Read in the hardware (fcode) properties and use these properties
    209 	 * to update the ndd array.
    210 	 */
    211 	(void) hxge_get_param_soft_properties(hxgep);
    212 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_hydra_properties"));
    213 }
    214 
    215 
    216 /*
    217  * Read param_accept_jumbo, param_rxdma_intr_time, and param_rxdma_intr_pkts
    218  * from either hxge.conf or OBP.
    219  * Update the soft properties.
    220  * Populate these properties into the hxge data structure for latter use.
    221  */
    222 static void
    223 hxge_use_cfg_dma_config(p_hxge_t hxgep)
    224 {
    225 	int			tx_ndmas, rx_ndmas;
    226 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
    227 	p_hxge_hw_pt_cfg_t	p_cfgp;
    228 	dev_info_t		*dip;
    229 	p_hxge_param_t		param_arr;
    230 	char			*prop;
    231 	int 			*prop_val;
    232 	uint_t 			prop_len;
    233 
    234 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_dma_config"));
    235 	param_arr = hxgep->param_arr;
    236 
    237 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
    238 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
    239 	dip = hxgep->dip;
    240 
    241 	tx_ndmas = 4;
    242 	p_cfgp->start_tdc = 0;
    243 	p_cfgp->max_tdcs =  hxgep->max_tdcs = tx_ndmas;
    244 	hxgep->tdc_mask = (tx_ndmas - 1);
    245 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
    246 	    "p_cfgp 0x%llx max_tdcs %d hxgep->max_tdcs %d",
    247 	    p_cfgp, p_cfgp->max_tdcs, hxgep->max_tdcs));
    248 
    249 	rx_ndmas = 4;
    250 	p_cfgp->start_rdc = 0;
    251 	p_cfgp->max_rdcs =  hxgep->max_rdcs = rx_ndmas;
    252 
    253 	p_cfgp->start_ldg = 0;
    254 	p_cfgp->max_ldgs = HXGE_INT_MAX_LDG;
    255 
    256 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_default_dma_config: "
    257 	    "p_cfgp 0x%llx max_rdcs %d hxgep->max_rdcs %d",
    258 	    p_cfgp, p_cfgp->max_rdcs, hxgep->max_rdcs));
    259 
    260 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
    261 	    "p_cfgp 0x%016llx start_ldg %d hxgep->max_ldgs %d ",
    262 	    p_cfgp, p_cfgp->start_ldg,  p_cfgp->max_ldgs));
    263 
    264 	/*
    265 	 * add code for individual rdc properties
    266 	 */
    267 	prop = param_arr[param_accept_jumbo].fcode_name;
    268 
    269 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
    270 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
    271 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
    272 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
    273 			    hxgep->dip, prop, prop_val, prop_len);
    274 		}
    275 		ddi_prop_free(prop_val);
    276 	}
    277 
    278 	prop = param_arr[param_rxdma_intr_time].fcode_name;
    279 
    280 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
    281 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
    282 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
    283 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
    284 			    hxgep->dip, prop, prop_val, prop_len);
    285 		}
    286 		ddi_prop_free(prop_val);
    287 	}
    288 
    289 	prop = param_arr[param_rxdma_intr_pkts].fcode_name;
    290 
    291 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
    292 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
    293 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
    294 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
    295 			    hxgep->dip, prop, prop_val, prop_len);
    296 		}
    297 		ddi_prop_free(prop_val);
    298 	}
    299 
    300 	hxge_set_hw_dma_config(hxgep);
    301 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "<== hxge_use_cfg_dma_config"));
    302 }
    303 
    304 static void
    305 hxge_use_cfg_class_config(p_hxge_t hxgep)
    306 {
    307 	hxge_set_hw_class_config(hxgep);
    308 }
    309 
    310 static void
    311 hxge_set_hw_dma_config(p_hxge_t hxgep)
    312 {
    313 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
    314 	p_hxge_hw_pt_cfg_t	p_cfgp;
    315 
    316 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_set_hw_dma_config"));
    317 
    318 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
    319 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
    320 
    321 	/* Transmit DMA Channels */
    322 	hxgep->ntdc = p_cfgp->max_tdcs;
    323 
    324 	/* Receive DMA Channels */
    325 	hxgep->nrdc = p_cfgp->max_rdcs;
    326 
    327 	p_dma_cfgp->rbr_size = hxge_rbr_size;
    328 	if (hxge_rcr_size > HXGE_RCR_MAX)
    329 		hxge_rcr_size = HXGE_RCR_MAX;
    330 	p_dma_cfgp->rcr_size = hxge_rcr_size;
    331 
    332 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_dma_config"));
    333 }
    334 
    335 
    336 boolean_t
    337 hxge_check_rxdma_port_member(p_hxge_t hxgep, uint8_t rdc)
    338 {
    339 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
    340 	p_hxge_hw_pt_cfg_t	p_cfgp;
    341 	int			status = B_TRUE;
    342 
    343 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_rxdma_port_member"));
    344 
    345 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
    346 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
    347 
    348 	/* Receive DMA Channels */
    349 	if (rdc < p_cfgp->max_rdcs)
    350 		status = B_TRUE;
    351 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_rxdma_port_member"));
    352 
    353 	return (status);
    354 }
    355 
    356 boolean_t
    357 hxge_check_txdma_port_member(p_hxge_t hxgep, uint8_t tdc)
    358 {
    359 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
    360 	p_hxge_hw_pt_cfg_t	p_cfgp;
    361 	int			status = B_FALSE;
    362 
    363 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_txdma_port_member"));
    364 
    365 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
    366 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
    367 
    368 	/* Receive DMA Channels */
    369 	if (tdc < p_cfgp->max_tdcs)
    370 		status = B_TRUE;
    371 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_txdma_port_member"));
    372 
    373 	return (status);
    374 }
    375 
    376 
    377 /*
    378  * Read the L2 classes, L3 classes, and initial hash from either hxge.conf
    379  * or OBP. Populate these properties into the hxge data structure for latter
    380  * use. Note that we are not updating these soft properties.
    381  */
    382 static void
    383 hxge_set_hw_class_config(p_hxge_t hxgep)
    384 {
    385 	int			i, j;
    386 	p_hxge_param_t		param_arr;
    387 	int			*int_prop_val;
    388 	uint32_t		cfg_value;
    389 	char			*prop;
    390 	p_hxge_class_pt_cfg_t	p_class_cfgp;
    391 	int			start_prop, end_prop;
    392 	uint_t			prop_cnt;
    393 
    394 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_class_config"));
    395 
    396 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
    397 
    398 	param_arr = hxgep->param_arr;
    399 
    400 	/*
    401 	 * L2 class configuration. User configurable ether types
    402 	 */
    403 	start_prop =  param_class_cfg_ether_usr1;
    404 	end_prop = param_class_cfg_ether_usr2;
    405 
    406 	for (i = start_prop; i <= end_prop; i++) {
    407 		prop = param_arr[i].fcode_name;
    408 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
    409 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
    410 			cfg_value =  (uint32_t)*int_prop_val;
    411 			ddi_prop_free(int_prop_val);
    412 		} else {
    413 			cfg_value = (uint32_t)param_arr[i].value;
    414 		}
    415 
    416 		j = (i - start_prop) + TCAM_CLASS_ETYPE_1;
    417 		p_class_cfgp->class_cfg[j] = cfg_value;
    418 	}
    419 
    420 	/*
    421 	 * Use properties from either .conf or the NDD param array. Only bits
    422 	 * 2 and 3 are significant
    423 	 */
    424 	start_prop =  param_class_opt_ipv4_tcp;
    425 	end_prop = param_class_opt_ipv6_sctp;
    426 
    427 	for (i = start_prop; i <= end_prop; i++) {
    428 		prop = param_arr[i].fcode_name;
    429 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
    430 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
    431 			cfg_value =  (uint32_t)*int_prop_val;
    432 			ddi_prop_free(int_prop_val);
    433 		} else {
    434 			cfg_value = (uint32_t)param_arr[i].value;
    435 		}
    436 
    437 		j = (i - start_prop) + TCAM_CLASS_TCP_IPV4;
    438 		p_class_cfgp->class_cfg[j] = cfg_value;
    439 	}
    440 
    441 	prop = param_arr[param_hash_init_value].fcode_name;
    442 
    443 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
    444 	    &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
    445 		cfg_value =  (uint32_t)*int_prop_val;
    446 		ddi_prop_free(int_prop_val);
    447 	} else {
    448 		cfg_value = (uint32_t)param_arr[param_hash_init_value].value;
    449 	}
    450 
    451 	p_class_cfgp->init_hash = (uint32_t)cfg_value;
    452 
    453 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_class_config"));
    454 }
    455 
    456 
    457 /*
    458  * Interrupts related interface functions.
    459  */
    460 hxge_status_t
    461 hxge_ldgv_init(p_hxge_t hxgep, int *navail_p, int *nrequired_p)
    462 {
    463 	uint8_t			ldv, i, maxldvs, maxldgs, start, end, nldvs;
    464 	int			ldg, endldg, ngrps;
    465 	uint8_t			channel;
    466 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
    467 	p_hxge_hw_pt_cfg_t	p_cfgp;
    468 	p_hxge_ldgv_t		ldgvp;
    469 	p_hxge_ldg_t		ldgp, ptr;
    470 	p_hxge_ldv_t		ldvp;
    471 	hxge_status_t		status = HXGE_OK;
    472 	peu_intr_mask_t		parity_err_mask;
    473 
    474 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_init"));
    475 	if (!*navail_p) {
    476 		*nrequired_p = 0;
    477 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    478 		    "<== hxge_ldgv_init:no avail"));
    479 		return (HXGE_ERROR);
    480 	}
    481 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
    482 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
    483 
    484 	/* each DMA channels */
    485 	nldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
    486 
    487 	/* vmac */
    488 	nldvs++;
    489 
    490 	/* pfc */
    491 	nldvs++;
    492 
    493 	/* system error interrupts. */
    494 	nldvs++;
    495 
    496 	maxldvs = nldvs;
    497 	maxldgs = p_cfgp->max_ldgs;
    498 
    499 	if (!maxldvs || !maxldgs) {
    500 		/* No devices configured. */
    501 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_ldgv_init: "
    502 		    "no logical devices or groups configured."));
    503 		return (HXGE_ERROR);
    504 	}
    505 	ldgvp = hxgep->ldgvp;
    506 	if (ldgvp == NULL) {
    507 		ldgvp = KMEM_ZALLOC(sizeof (hxge_ldgv_t), KM_SLEEP);
    508 		hxgep->ldgvp = ldgvp;
    509 		ldgvp->maxldgs = maxldgs;
    510 		ldgvp->maxldvs = maxldvs;
    511 		ldgp = ldgvp->ldgp =
    512 		    KMEM_ZALLOC(sizeof (hxge_ldg_t) * maxldgs, KM_SLEEP);
    513 		ldvp = ldgvp->ldvp =
    514 		    KMEM_ZALLOC(sizeof (hxge_ldv_t) * maxldvs, KM_SLEEP);
    515 	}
    516 
    517 	ldgvp->ndma_ldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
    518 	ldgvp->tmres = HXGE_TIMER_RESO;
    519 
    520 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    521 	    "==> hxge_ldgv_init: maxldvs %d maxldgs %d nldvs %d",
    522 	    maxldvs, maxldgs, nldvs));
    523 
    524 	ldg = p_cfgp->start_ldg;
    525 	ptr = ldgp;
    526 	for (i = 0; i < maxldgs; i++) {
    527 		ptr->arm = B_TRUE;
    528 		ptr->vldg_index = i;
    529 		ptr->ldg_timer = HXGE_TIMER_LDG;
    530 		ptr->ldg = ldg++;
    531 		ptr->sys_intr_handler = hxge_intr;
    532 		ptr->nldvs = 0;
    533 		ptr->hxgep = hxgep;
    534 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    535 		    "==> hxge_ldgv_init: maxldvs %d maxldgs %d ldg %d",
    536 		    maxldvs, maxldgs, ptr->ldg));
    537 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    538 		    "==> hxge_ldv_init: timer %d", ptr->ldg_timer));
    539 		ptr++;
    540 	}
    541 
    542 	ldg = p_cfgp->start_ldg;
    543 	if (maxldgs > *navail_p) {
    544 		ngrps = *navail_p;
    545 	} else {
    546 		ngrps = maxldgs;
    547 	}
    548 	endldg = ldg + ngrps;
    549 
    550 	/*
    551 	 * Receive DMA channels.
    552 	 */
    553 	channel = p_cfgp->start_rdc;
    554 	start = p_cfgp->start_rdc + HXGE_RDMA_LD_START;
    555 	end = start + p_cfgp->max_rdcs;
    556 	nldvs = 0;
    557 	ldgvp->nldvs = 0;
    558 	ldgp->ldvp = NULL;
    559 	*nrequired_p = 0;
    560 	ptr = ldgp;
    561 
    562 	/*
    563 	 * Start with RDC to configure logical devices for each group.
    564 	 */
    565 	for (i = 0, ldv = start; ldv < end; i++, ldv++) {
    566 		ldvp->is_rxdma = B_TRUE;
    567 		ldvp->ldv = ldv;
    568 
    569 		/*
    570 		 * If non-seq needs to change the following code
    571 		 */
    572 		ldvp->channel = channel++;
    573 		ldvp->vdma_index = i;
    574 		ldvp->ldv_intr_handler = hxge_rx_intr;
    575 		ldvp->ldv_ldf_masks = 0;
    576 		ldvp->use_timer = B_FALSE;
    577 		ldvp->hxgep = hxgep;
    578 		hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
    579 		nldvs++;
    580 	}
    581 
    582 	/*
    583 	 * Transmit DMA channels.
    584 	 */
    585 	channel = p_cfgp->start_tdc;
    586 	start = p_cfgp->start_tdc + HXGE_TDMA_LD_START;
    587 	end = start + p_cfgp->max_tdcs;
    588 	for (i = 0, ldv = start; ldv < end; i++, ldv++) {
    589 		ldvp->is_txdma = B_TRUE;
    590 		ldvp->ldv = ldv;
    591 		ldvp->channel = channel++;
    592 		ldvp->vdma_index = i;
    593 		ldvp->ldv_intr_handler = hxge_tx_intr;
    594 		ldvp->ldv_ldf_masks = 0;
    595 		ldvp->use_timer = B_FALSE;
    596 		ldvp->hxgep = hxgep;
    597 		hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
    598 		nldvs++;
    599 	}
    600 
    601 	/*
    602 	 * VMAC
    603 	 */
    604 	ldvp->is_vmac = B_TRUE;
    605 	ldvp->ldv_intr_handler = hxge_vmac_intr;
    606 	ldvp->ldv_ldf_masks = 0;
    607 	ldv = HXGE_VMAC_LD;
    608 	ldvp->ldv = ldv;
    609 	ldvp->use_timer = B_FALSE;
    610 	ldvp->hxgep = hxgep;
    611 	hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
    612 	nldvs++;
    613 
    614 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    615 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
    616 	    nldvs, *navail_p, *nrequired_p));
    617 
    618 	/*
    619 	 * PFC
    620 	 */
    621 	ldvp->is_pfc = B_TRUE;
    622 	ldvp->ldv_intr_handler = hxge_pfc_intr;
    623 	ldvp->ldv_ldf_masks = 0;
    624 	ldv = HXGE_PFC_LD;
    625 	ldvp->ldv = ldv;
    626 	ldvp->use_timer = B_FALSE;
    627 	ldvp->hxgep = hxgep;
    628 	hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
    629 	nldvs++;
    630 
    631 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    632 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
    633 	    nldvs, *navail_p, *nrequired_p));
    634 
    635 	/*
    636 	 * System error interrupts.
    637 	 */
    638 	ldv = HXGE_SYS_ERROR_LD;
    639 	ldvp->ldv = ldv;
    640 	ldvp->is_syserr = B_TRUE;
    641 	ldvp->ldv_intr_handler = hxge_syserr_intr;
    642 	ldvp->ldv_ldf_masks = 0;
    643 	ldvp->hxgep = hxgep;
    644 	ldvp->use_timer = B_FALSE;
    645 	ldgvp->ldvp_syserr = ldvp;
    646 
    647 	/* Reset PEU error mask to allow PEU error interrupts */
    648 	/*
    649 	 * Keep the msix parity error mask here and remove it
    650 	 * after ddi_intr_enable call to avoid a msix par err
    651 	 */
    652 	parity_err_mask.value = 0;
    653 	parity_err_mask.bits.eic_msix_parerr_mask = 1;
    654 	HXGE_REG_WR32(hxgep->hpi_handle, PEU_INTR_MASK, parity_err_mask.value);
    655 
    656 	/*
    657 	 * Unmask the system interrupt states.
    658 	 */
    659 	(void) hxge_fzc_sys_err_mask_set(hxgep, B_FALSE);
    660 	(void) hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
    661 	nldvs++;
    662 
    663 	ldgvp->ldg_intrs = *nrequired_p;
    664 
    665 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    666 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
    667 	    nldvs, *navail_p, *nrequired_p));
    668 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_init"));
    669 	return (status);
    670 }
    671 
    672 hxge_status_t
    673 hxge_ldgv_uninit(p_hxge_t hxgep)
    674 {
    675 	p_hxge_ldgv_t		ldgvp;
    676 
    677 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_uninit"));
    678 	ldgvp = hxgep->ldgvp;
    679 	if (ldgvp == NULL) {
    680 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    681 		    "<== hxge_ldgv_uninit: no logical group configured."));
    682 		return (HXGE_OK);
    683 	}
    684 
    685 	if (ldgvp->ldgp) {
    686 		KMEM_FREE(ldgvp->ldgp, sizeof (hxge_ldg_t) * ldgvp->maxldgs);
    687 	}
    688 	if (ldgvp->ldvp) {
    689 		KMEM_FREE(ldgvp->ldvp, sizeof (hxge_ldv_t) * ldgvp->maxldvs);
    690 	}
    691 
    692 	KMEM_FREE(ldgvp, sizeof (hxge_ldgv_t));
    693 	hxgep->ldgvp = NULL;
    694 
    695 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_uninit"));
    696 	return (HXGE_OK);
    697 }
    698 
    699 hxge_status_t
    700 hxge_intr_ldgv_init(p_hxge_t hxgep)
    701 {
    702 	hxge_status_t	status = HXGE_OK;
    703 
    704 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_ldgv_init"));
    705 	/*
    706 	 * Configure the logical device group numbers, state vectors
    707 	 * and interrupt masks for each logical device.
    708 	 */
    709 	status = hxge_fzc_intr_init(hxgep);
    710 
    711 	/*
    712 	 * Configure logical device masks and timers.
    713 	 */
    714 	status = hxge_intr_mask_mgmt(hxgep);
    715 
    716 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_ldgv_init"));
    717 	return (status);
    718 }
    719 
    720 hxge_status_t
    721 hxge_intr_mask_mgmt(p_hxge_t hxgep)
    722 {
    723 	p_hxge_ldgv_t	ldgvp;
    724 	p_hxge_ldg_t	ldgp;
    725 	p_hxge_ldv_t	ldvp;
    726 	hpi_handle_t	handle;
    727 	int		i, j;
    728 	hpi_status_t	rs = HPI_SUCCESS;
    729 
    730 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_mask_mgmt"));
    731 
    732 	if ((ldgvp = hxgep->ldgvp) == NULL) {
    733 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    734 		    "<== hxge_intr_mask_mgmt: Null ldgvp"));
    735 		return (HXGE_ERROR);
    736 	}
    737 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
    738 	ldgp = ldgvp->ldgp;
    739 	ldvp = ldgvp->ldvp;
    740 	if (ldgp == NULL || ldvp == NULL) {
    741 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    742 		    "<== hxge_intr_mask_mgmt: Null ldgp or ldvp"));
    743 		return (HXGE_ERROR);
    744 	}
    745 
    746 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    747 	    "==> hxge_intr_mask_mgmt: # of intrs %d ", ldgvp->ldg_intrs));
    748 	/* Initialize masks. */
    749 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    750 	    "==> hxge_intr_mask_mgmt(Hydra): # intrs %d ", ldgvp->ldg_intrs));
    751 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
    752 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    753 		    "==> hxge_intr_mask_mgmt(Hydra): # ldv %d in group %d",
    754 		    ldgp->nldvs, ldgp->ldg));
    755 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
    756 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
    757 			    "==> hxge_intr_mask_mgmt: set ldv # %d "
    758 			    "for ldg %d", ldvp->ldv, ldgp->ldg));
    759 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
    760 			    ldvp->ldv_ldf_masks);
    761 			if (rs != HPI_SUCCESS) {
    762 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    763 				    "<== hxge_intr_mask_mgmt: set mask failed "
    764 				    " rs 0x%x ldv %d mask 0x%x",
    765 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
    766 				return (HXGE_ERROR | rs);
    767 			}
    768 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
    769 			    "==> hxge_intr_mask_mgmt: set mask OK "
    770 			    " rs 0x%x ldv %d mask 0x%x",
    771 			    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
    772 		}
    773 	}
    774 
    775 	ldgp = ldgvp->ldgp;
    776 	/* Configure timer and arm bit */
    777 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
    778 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
    779 		    ldgp->arm, ldgp->ldg_timer);
    780 		if (rs != HPI_SUCCESS) {
    781 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    782 			    "<== hxge_intr_mask_mgmt: set timer failed "
    783 			    " rs 0x%x dg %d timer 0x%x",
    784 			    rs, ldgp->ldg, ldgp->ldg_timer));
    785 			return (HXGE_ERROR | rs);
    786 		}
    787 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    788 		    "==> hxge_intr_mask_mgmt: set timer OK "
    789 		    " rs 0x%x ldg %d timer 0x%x",
    790 		    rs, ldgp->ldg, ldgp->ldg_timer));
    791 	}
    792 
    793 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_mask_mgmt"));
    794 	return (HXGE_OK);
    795 }
    796 
    797 hxge_status_t
    798 hxge_intr_mask_mgmt_set(p_hxge_t hxgep, boolean_t on)
    799 {
    800 	p_hxge_ldgv_t	ldgvp;
    801 	p_hxge_ldg_t	ldgp;
    802 	p_hxge_ldv_t	ldvp;
    803 	hpi_handle_t	handle;
    804 	int		i, j;
    805 	hpi_status_t	rs = HPI_SUCCESS;
    806 
    807 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
    808 	    "==> hxge_intr_mask_mgmt_set (%d)", on));
    809 
    810 	if ((ldgvp = hxgep->ldgvp) == NULL) {
    811 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    812 		    "==> hxge_intr_mask_mgmt_set: Null ldgvp"));
    813 		return (HXGE_ERROR);
    814 	}
    815 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
    816 	ldgp = ldgvp->ldgp;
    817 	ldvp = ldgvp->ldvp;
    818 	if (ldgp == NULL || ldvp == NULL) {
    819 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    820 		    "<== hxge_intr_mask_mgmt_set: Null ldgp or ldvp"));
    821 		return (HXGE_ERROR);
    822 	}
    823 
    824 	/* set masks. */
    825 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
    826 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    827 		    "==> hxge_intr_mask_mgmt_set: flag %d ldg %d"
    828 		    "set mask nldvs %d", on, ldgp->ldg, ldgp->nldvs));
    829 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
    830 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
    831 			    "==> hxge_intr_mask_mgmt_set: "
    832 			    "for %d %d flag %d", i, j, on));
    833 			if (on) {
    834 				ldvp->ldv_ldf_masks = 0;
    835 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
    836 				    "==> hxge_intr_mask_mgmt_set: "
    837 				    "ON mask off"));
    838 			} else {
    839 				ldvp->ldv_ldf_masks = (uint8_t)LD_IM_MASK;
    840 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
    841 				    "==> hxge_intr_mask_mgmt_set:mask on"));
    842 			}
    843 
    844 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
    845 			    ldvp->ldv_ldf_masks);
    846 			if (rs != HPI_SUCCESS) {
    847 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    848 				    "==> hxge_intr_mask_mgmt_set: "
    849 				    "set mask failed rs 0x%x ldv %d mask 0x%x",
    850 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
    851 				return (HXGE_ERROR | rs);
    852 			}
    853 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
    854 			    "==> hxge_intr_mask_mgmt_set: flag %d"
    855 			    "set mask OK ldv %d mask 0x%x",
    856 			    on, ldvp->ldv, ldvp->ldv_ldf_masks));
    857 		}
    858 	}
    859 
    860 	ldgp = ldgvp->ldgp;
    861 	/* set the arm bit */
    862 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
    863 		if (on && !ldgp->arm) {
    864 			ldgp->arm = B_TRUE;
    865 		} else if (!on && ldgp->arm) {
    866 			ldgp->arm = B_FALSE;
    867 		}
    868 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
    869 		    ldgp->arm, ldgp->ldg_timer);
    870 		if (rs != HPI_SUCCESS) {
    871 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
    872 			    "<== hxge_intr_mask_mgmt_set: "
    873 			    "set timer failed rs 0x%x ldg %d timer 0x%x",
    874 			    rs, ldgp->ldg, ldgp->ldg_timer));
    875 			return (HXGE_ERROR | rs);
    876 		}
    877 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
    878 		    "==> hxge_intr_mask_mgmt_set: OK (flag %d) "
    879 		    "set timer ldg %d timer 0x%x",
    880 		    on, ldgp->ldg, ldgp->ldg_timer));
    881 	}
    882 
    883 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_mask_mgmt_set"));
    884 	return (HXGE_OK);
    885 }
    886 
    887 /*
    888  * For Big Endian systems, the mac address will be from OBP. For Little
    889  * Endian (x64) systems, it will be retrieved from the card since it cannot
    890  * be programmed into PXE.
    891  * This function also populates the MMAC parameters.
    892  */
    893 static hxge_status_t
    894 hxge_get_mac_addr_properties(p_hxge_t hxgep)
    895 {
    896 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_get_mac_addr_properties "));
    897 
    898 	(void) hxge_pfc_mac_addrs_get(hxgep);
    899 	hxgep->ouraddr = hxgep->factaddr;
    900 
    901 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_get_mac_addr_properties "));
    902 	return (HXGE_OK);
    903 }
    904 
    905 static void
    906 hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
    907 	uint8_t endldg, int *ngrps)
    908 {
    909 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup"));
    910 	/* Assign the group number for each device. */
    911 	(*ldvp)->ldg_assigned = (*ldgp)->ldg;
    912 	(*ldvp)->ldgp = *ldgp;
    913 	(*ldvp)->ldv = ldv;
    914 
    915 	HXGE_DEBUG_MSG((NULL, INT_CTL,
    916 	    "==> hxge_ldgv_setup: ldv %d endldg %d ldg %d, ldvp $%p",
    917 	    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
    918 
    919 	(*ldgp)->nldvs++;
    920 	if ((*ldgp)->ldg == (endldg - 1)) {
    921 		if ((*ldgp)->ldvp == NULL) {
    922 			(*ldgp)->ldvp = *ldvp;
    923 			*ngrps += 1;
    924 			HXGE_DEBUG_MSG((NULL, INT_CTL,
    925 			    "==> hxge_ldgv_setup: ngrps %d", *ngrps));
    926 		}
    927 		HXGE_DEBUG_MSG((NULL, INT_CTL,
    928 		    "==> hxge_ldgv_setup: ldvp $%p ngrps %d",
    929 		    *ldvp, *ngrps));
    930 		++*ldvp;
    931 	} else {
    932 		(*ldgp)->ldvp = *ldvp;
    933 		*ngrps += 1;
    934 		HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup(done): "
    935 		    "ldv %d endldg %d ldg %d, ldvp $%p",
    936 		    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
    937 		(*ldvp) = ++*ldvp;
    938 		(*ldgp) = ++*ldgp;
    939 		HXGE_DEBUG_MSG((NULL, INT_CTL,
    940 		    "==> hxge_ldgv_setup: new ngrps %d", *ngrps));
    941 	}
    942 
    943 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup: "
    944 	    "ldg %d nldvs %d ldv %d ldvp $%p endldg %d ngrps %d",
    945 	    (*ldgp)->ldg, (*ldgp)->nldvs, ldv, ldvp, endldg, *ngrps));
    946 
    947 	HXGE_DEBUG_MSG((NULL, INT_CTL, "<== hxge_ldgv_setup"));
    948 }
    949