xref: /titanic_44/usr/src/uts/common/io/hxge/hxge_virtual.c (revision aecfc01d1bad84e66649703f7fc2926ef70b34ba)
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 static hxge_status_t hxge_mmac_init(p_hxge_t);
40 
41 extern uint16_t hxge_rcr_timeout;
42 extern uint16_t hxge_rcr_threshold;
43 
44 extern uint32_t hxge_rbr_size;
45 extern uint32_t hxge_rcr_size;
46 
47 extern uint_t hxge_rx_intr();
48 extern uint_t hxge_tx_intr();
49 extern uint_t hxge_vmac_intr();
50 extern uint_t hxge_syserr_intr();
51 extern uint_t hxge_pfc_intr();
52 
53 /*
54  * Entry point to populate configuration parameters into the master hxge
55  * data structure and to update the NDD parameter list.
56  */
57 hxge_status_t
58 hxge_get_config_properties(p_hxge_t hxgep)
59 {
60 	hxge_status_t		status = HXGE_OK;
61 
62 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " ==> hxge_get_config_properties"));
63 
64 	if (hxgep->hxge_hw_p == NULL) {
65 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
66 		    " hxge_get_config_properties: common hardware not set"));
67 		return (HXGE_ERROR);
68 	}
69 
70 	hxgep->classifier.tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
71 
72 	status = hxge_get_mac_addr_properties(hxgep);
73 	if (status != HXGE_OK) {
74 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
75 		    " hxge_get_config_properties: mac addr properties failed"));
76 		return (status);
77 	}
78 
79 	HXGE_DEBUG_MSG((hxgep, VPD_CTL,
80 	    " ==> hxge_get_config_properties: Hydra"));
81 
82 	hxge_use_cfg_hydra_properties(hxgep);
83 
84 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " <== hxge_get_config_properties"));
85 	return (HXGE_OK);
86 }
87 
88 
89 static void
90 hxge_set_hw_vlan_class_config(p_hxge_t hxgep)
91 {
92 	int			i;
93 	p_hxge_param_t		param_arr;
94 	uint_t			vlan_cnt;
95 	int			*vlan_cfg_val;
96 	hxge_param_map_t	*vmap;
97 	char			*prop;
98 	p_hxge_class_pt_cfg_t 	p_class_cfgp;
99 	uint32_t		good_cfg[32];
100 	int			good_count = 0;
101 	hxge_mv_cfg_t		*vlan_tbl;
102 
103 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_vlan_config"));
104 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
105 
106 	param_arr = hxgep->param_arr;
107 	prop = param_arr[param_vlan_ids].fcode_name;
108 
109 	/*
110 	 * uint32_t array, each array entry specifying a VLAN id
111 	 */
112 	for (i = 0; i <= VLAN_ID_MAX; i++) {
113 		p_class_cfgp->vlan_tbl[i].flag = 0;
114 	}
115 
116 	vlan_tbl = (hxge_mv_cfg_t *)&p_class_cfgp->vlan_tbl[0];
117 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
118 	    &vlan_cfg_val, &vlan_cnt) != DDI_PROP_SUCCESS) {
119 		return;
120 	}
121 
122 	for (i = 0; i < vlan_cnt; i++) {
123 		vmap = (hxge_param_map_t *)&vlan_cfg_val[i];
124 		if ((vmap->param_id) && (vmap->param_id <= VLAN_ID_MAX)) {
125 			HXGE_DEBUG_MSG((hxgep, CFG2_CTL,
126 			    " hxge_vlan_config vlan id %d", vmap->param_id));
127 
128 			good_cfg[good_count] = vlan_cfg_val[i];
129 			if (vlan_tbl[vmap->param_id].flag == 0)
130 				good_count++;
131 
132 			vlan_tbl[vmap->param_id].flag = 1;
133 		}
134 	}
135 
136 	ddi_prop_free(vlan_cfg_val);
137 	if (good_count != vlan_cnt) {
138 		(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
139 		    hxgep->dip, prop, (int *)good_cfg, good_count);
140 	}
141 
142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_vlan_config"));
143 }
144 
145 
146 /*
147  * Read param_vlan_ids and param_implicit_vlan_id properties from either
148  * hxge.conf or OBP. Update the soft properties. Populate these
149  * properties into the hxge data structure.
150  */
151 static void
152 hxge_use_cfg_vlan_class_config(p_hxge_t hxgep)
153 {
154 	uint_t		vlan_cnt;
155 	int		*vlan_cfg_val;
156 	int		status;
157 	p_hxge_param_t	param_arr;
158 	char		*prop;
159 	uint32_t	implicit_vlan_id = 0;
160 	int		*int_prop_val;
161 	uint_t		prop_len;
162 	p_hxge_param_t	pa;
163 
164 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_vlan_config"));
165 	param_arr = hxgep->param_arr;
166 	prop = param_arr[param_vlan_ids].fcode_name;
167 
168 	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
169 	    &vlan_cfg_val, &vlan_cnt);
170 	if (status == DDI_PROP_SUCCESS) {
171 		status = ddi_prop_update_int_array(DDI_DEV_T_NONE,
172 		    hxgep->dip, prop, vlan_cfg_val, vlan_cnt);
173 		ddi_prop_free(vlan_cfg_val);
174 	}
175 
176 	pa = &param_arr[param_implicit_vlan_id];
177 	prop = pa->fcode_name;
178 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
179 	    &int_prop_val, &prop_len) == DDI_PROP_SUCCESS) {
180 		implicit_vlan_id = (uint32_t)*int_prop_val;
181 		if ((implicit_vlan_id >= pa->minimum) ||
182 		    (implicit_vlan_id <= pa->maximum)) {
183 			status = ddi_prop_update_int(DDI_DEV_T_NONE, hxgep->dip,
184 			    prop, (int)implicit_vlan_id);
185 		}
186 		ddi_prop_free(int_prop_val);
187 	}
188 
189 	hxge_set_hw_vlan_class_config(hxgep);
190 
191 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_vlan_config"));
192 }
193 
194 /*
195  * Read in the configuration parameters from either hxge.conf or OBP and
196  * populate the master data structure hxge.
197  * Use these parameters to update the soft properties and the ndd array.
198  */
199 static void
200 hxge_use_cfg_hydra_properties(p_hxge_t hxgep)
201 {
202 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_hydra_properties"));
203 
204 	(void) hxge_use_cfg_dma_config(hxgep);
205 	(void) hxge_use_cfg_vlan_class_config(hxgep);
206 	(void) hxge_use_cfg_class_config(hxgep);
207 
208 	/*
209 	 * Read in the hardware (fcode) properties and use these properties
210 	 * to update the ndd array.
211 	 */
212 	(void) hxge_get_param_soft_properties(hxgep);
213 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_hydra_properties"));
214 }
215 
216 
217 /*
218  * Read param_accept_jumbo, param_rxdma_intr_time, and param_rxdma_intr_pkts
219  * from either hxge.conf or OBP.
220  * Update the soft properties.
221  * Populate these properties into the hxge data structure for latter use.
222  */
223 static void
224 hxge_use_cfg_dma_config(p_hxge_t hxgep)
225 {
226 	int			tx_ndmas, rx_ndmas;
227 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
228 	p_hxge_hw_pt_cfg_t	p_cfgp;
229 	dev_info_t		*dip;
230 	p_hxge_param_t		param_arr;
231 	char			*prop;
232 	int 			*prop_val;
233 	uint_t 			prop_len;
234 
235 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_dma_config"));
236 	param_arr = hxgep->param_arr;
237 
238 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
239 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
240 	dip = hxgep->dip;
241 
242 	tx_ndmas = 4;
243 	p_cfgp->start_tdc = 0;
244 	p_cfgp->max_tdcs =  hxgep->max_tdcs = tx_ndmas;
245 	hxgep->tdc_mask = (tx_ndmas - 1);
246 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
247 	    "p_cfgp 0x%llx max_tdcs %d hxgep->max_tdcs %d",
248 	    p_cfgp, p_cfgp->max_tdcs, hxgep->max_tdcs));
249 
250 	rx_ndmas = 4;
251 	p_cfgp->start_rdc = 0;
252 	p_cfgp->max_rdcs =  hxgep->max_rdcs = rx_ndmas;
253 
254 	p_cfgp->start_ldg = 0;
255 	p_cfgp->max_ldgs = HXGE_INT_MAX_LDG;
256 
257 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_default_dma_config: "
258 	    "p_cfgp 0x%llx max_rdcs %d hxgep->max_rdcs %d",
259 	    p_cfgp, p_cfgp->max_rdcs, hxgep->max_rdcs));
260 
261 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
262 	    "p_cfgp 0x%016llx start_ldg %d hxgep->max_ldgs %d ",
263 	    p_cfgp, p_cfgp->start_ldg,  p_cfgp->max_ldgs));
264 
265 	/*
266 	 * add code for individual rdc properties
267 	 */
268 	prop = param_arr[param_accept_jumbo].fcode_name;
269 
270 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
271 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
272 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
273 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
274 			    hxgep->dip, prop, prop_val, prop_len);
275 		}
276 		ddi_prop_free(prop_val);
277 	}
278 
279 	prop = param_arr[param_rxdma_intr_time].fcode_name;
280 
281 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
282 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
283 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
284 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
285 			    hxgep->dip, prop, prop_val, prop_len);
286 		}
287 		ddi_prop_free(prop_val);
288 	}
289 
290 	prop = param_arr[param_rxdma_intr_pkts].fcode_name;
291 
292 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
293 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
294 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
295 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
296 			    hxgep->dip, prop, prop_val, prop_len);
297 		}
298 		ddi_prop_free(prop_val);
299 	}
300 
301 	hxge_set_hw_dma_config(hxgep);
302 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "<== hxge_use_cfg_dma_config"));
303 }
304 
305 static void
306 hxge_use_cfg_class_config(p_hxge_t hxgep)
307 {
308 	hxge_set_hw_class_config(hxgep);
309 }
310 
311 static void
312 hxge_set_hw_dma_config(p_hxge_t hxgep)
313 {
314 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
315 	p_hxge_hw_pt_cfg_t	p_cfgp;
316 
317 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_set_hw_dma_config"));
318 
319 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
320 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
321 
322 	/* Transmit DMA Channels */
323 	hxgep->ntdc = p_cfgp->max_tdcs;
324 
325 	/* Receive DMA Channels */
326 	hxgep->nrdc = p_cfgp->max_rdcs;
327 
328 	p_dma_cfgp->rbr_size = hxge_rbr_size;
329 	if (hxge_rcr_size > HXGE_RCR_MAX)
330 		hxge_rcr_size = HXGE_RCR_MAX;
331 	p_dma_cfgp->rcr_size = hxge_rcr_size;
332 
333 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_dma_config"));
334 }
335 
336 
337 boolean_t
338 hxge_check_rxdma_port_member(p_hxge_t hxgep, uint8_t rdc)
339 {
340 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
341 	p_hxge_hw_pt_cfg_t	p_cfgp;
342 	int			status = B_TRUE;
343 
344 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_rxdma_port_member"));
345 
346 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
347 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
348 
349 	/* Receive DMA Channels */
350 	if (rdc < p_cfgp->max_rdcs)
351 		status = B_TRUE;
352 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_rxdma_port_member"));
353 
354 	return (status);
355 }
356 
357 boolean_t
358 hxge_check_txdma_port_member(p_hxge_t hxgep, uint8_t tdc)
359 {
360 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
361 	p_hxge_hw_pt_cfg_t	p_cfgp;
362 	int			status = B_FALSE;
363 
364 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_txdma_port_member"));
365 
366 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
367 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
368 
369 	/* Receive DMA Channels */
370 	if (tdc < p_cfgp->max_tdcs)
371 		status = B_TRUE;
372 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_txdma_port_member"));
373 
374 	return (status);
375 }
376 
377 
378 /*
379  * Read the L2 classes, L3 classes, and initial hash from either hxge.conf
380  * or OBP. Populate these properties into the hxge data structure for latter
381  * use. Note that we are not updating these soft properties.
382  */
383 static void
384 hxge_set_hw_class_config(p_hxge_t hxgep)
385 {
386 	int			i, j;
387 	p_hxge_param_t		param_arr;
388 	int			*int_prop_val;
389 	uint32_t		cfg_value;
390 	char			*prop;
391 	p_hxge_class_pt_cfg_t	p_class_cfgp;
392 	int			start_prop, end_prop;
393 	uint_t			prop_cnt;
394 
395 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_class_config"));
396 
397 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
398 
399 	param_arr = hxgep->param_arr;
400 
401 	/*
402 	 * L2 class configuration. User configurable ether types
403 	 */
404 	start_prop =  param_class_cfg_ether_usr1;
405 	end_prop = param_class_cfg_ether_usr2;
406 
407 	for (i = start_prop; i <= end_prop; i++) {
408 		prop = param_arr[i].fcode_name;
409 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
410 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
411 			cfg_value =  (uint32_t)*int_prop_val;
412 			ddi_prop_free(int_prop_val);
413 		} else {
414 			cfg_value = (uint32_t)param_arr[i].value;
415 		}
416 
417 		j = (i - start_prop) + TCAM_CLASS_ETYPE_1;
418 		p_class_cfgp->class_cfg[j] = cfg_value;
419 	}
420 
421 	/*
422 	 * Use properties from either .conf or the NDD param array. Only bits
423 	 * 2 and 3 are significant
424 	 */
425 	start_prop =  param_class_opt_ipv4_tcp;
426 	end_prop = param_class_opt_ipv6_sctp;
427 
428 	for (i = start_prop; i <= end_prop; i++) {
429 		prop = param_arr[i].fcode_name;
430 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
431 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
432 			cfg_value =  (uint32_t)*int_prop_val;
433 			ddi_prop_free(int_prop_val);
434 		} else {
435 			cfg_value = (uint32_t)param_arr[i].value;
436 		}
437 
438 		j = (i - start_prop) + TCAM_CLASS_TCP_IPV4;
439 		p_class_cfgp->class_cfg[j] = cfg_value;
440 	}
441 
442 	prop = param_arr[param_hash_init_value].fcode_name;
443 
444 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
445 	    &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
446 		cfg_value =  (uint32_t)*int_prop_val;
447 		ddi_prop_free(int_prop_val);
448 	} else {
449 		cfg_value = (uint32_t)param_arr[param_hash_init_value].value;
450 	}
451 
452 	p_class_cfgp->init_hash = (uint32_t)cfg_value;
453 
454 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_class_config"));
455 }
456 
457 
458 /*
459  * Interrupts related interface functions.
460  */
461 hxge_status_t
462 hxge_ldgv_init(p_hxge_t hxgep, int *navail_p, int *nrequired_p)
463 {
464 	uint8_t			ldv, i, maxldvs, maxldgs, start, end, nldvs;
465 	int			ldg, endldg, ngrps;
466 	uint8_t			channel;
467 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
468 	p_hxge_hw_pt_cfg_t	p_cfgp;
469 	p_hxge_ldgv_t		ldgvp;
470 	p_hxge_ldg_t		ldgp, ptr;
471 	p_hxge_ldv_t		ldvp;
472 	hxge_status_t		status = HXGE_OK;
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 	HXGE_REG_WR32(hxgep->hpi_handle, PEU_INTR_MASK, 0x0);
649 
650 	/*
651 	 * Unmask the system interrupt states.
652 	 */
653 	(void) hxge_fzc_sys_err_mask_set(hxgep, B_FALSE);
654 	(void) hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
655 	nldvs++;
656 
657 	ldgvp->ldg_intrs = *nrequired_p;
658 
659 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
660 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
661 	    nldvs, *navail_p, *nrequired_p));
662 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_init"));
663 	return (status);
664 }
665 
666 hxge_status_t
667 hxge_ldgv_uninit(p_hxge_t hxgep)
668 {
669 	p_hxge_ldgv_t		ldgvp;
670 
671 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_uninit"));
672 	ldgvp = hxgep->ldgvp;
673 	if (ldgvp == NULL) {
674 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
675 		    "<== hxge_ldgv_uninit: no logical group configured."));
676 		return (HXGE_OK);
677 	}
678 
679 	if (ldgvp->ldgp) {
680 		KMEM_FREE(ldgvp->ldgp, sizeof (hxge_ldg_t) * ldgvp->maxldgs);
681 	}
682 	if (ldgvp->ldvp) {
683 		KMEM_FREE(ldgvp->ldvp, sizeof (hxge_ldv_t) * ldgvp->maxldvs);
684 	}
685 
686 	KMEM_FREE(ldgvp, sizeof (hxge_ldgv_t));
687 	hxgep->ldgvp = NULL;
688 
689 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_uninit"));
690 	return (HXGE_OK);
691 }
692 
693 hxge_status_t
694 hxge_intr_ldgv_init(p_hxge_t hxgep)
695 {
696 	hxge_status_t	status = HXGE_OK;
697 
698 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_ldgv_init"));
699 	/*
700 	 * Configure the logical device group numbers, state vectors
701 	 * and interrupt masks for each logical device.
702 	 */
703 	status = hxge_fzc_intr_init(hxgep);
704 
705 	/*
706 	 * Configure logical device masks and timers.
707 	 */
708 	status = hxge_intr_mask_mgmt(hxgep);
709 
710 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_ldgv_init"));
711 	return (status);
712 }
713 
714 hxge_status_t
715 hxge_intr_mask_mgmt(p_hxge_t hxgep)
716 {
717 	p_hxge_ldgv_t	ldgvp;
718 	p_hxge_ldg_t	ldgp;
719 	p_hxge_ldv_t	ldvp;
720 	hpi_handle_t	handle;
721 	int		i, j;
722 	hpi_status_t	rs = HPI_SUCCESS;
723 
724 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_mask_mgmt"));
725 
726 	if ((ldgvp = hxgep->ldgvp) == NULL) {
727 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
728 		    "<== hxge_intr_mask_mgmt: Null ldgvp"));
729 		return (HXGE_ERROR);
730 	}
731 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
732 	ldgp = ldgvp->ldgp;
733 	ldvp = ldgvp->ldvp;
734 	if (ldgp == NULL || ldvp == NULL) {
735 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
736 		    "<== hxge_intr_mask_mgmt: Null ldgp or ldvp"));
737 		return (HXGE_ERROR);
738 	}
739 
740 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
741 	    "==> hxge_intr_mask_mgmt: # of intrs %d ", ldgvp->ldg_intrs));
742 	/* Initialize masks. */
743 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
744 	    "==> hxge_intr_mask_mgmt(Hydra): # intrs %d ", ldgvp->ldg_intrs));
745 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
746 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
747 		    "==> hxge_intr_mask_mgmt(Hydra): # ldv %d in group %d",
748 		    ldgp->nldvs, ldgp->ldg));
749 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
750 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
751 			    "==> hxge_intr_mask_mgmt: set ldv # %d "
752 			    "for ldg %d", ldvp->ldv, ldgp->ldg));
753 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
754 			    ldvp->ldv_ldf_masks);
755 			if (rs != HPI_SUCCESS) {
756 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
757 				    "<== hxge_intr_mask_mgmt: set mask failed "
758 				    " rs 0x%x ldv %d mask 0x%x",
759 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
760 				return (HXGE_ERROR | rs);
761 			}
762 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
763 			    "==> hxge_intr_mask_mgmt: set mask OK "
764 			    " rs 0x%x ldv %d mask 0x%x",
765 			    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
766 		}
767 	}
768 
769 	ldgp = ldgvp->ldgp;
770 	/* Configure timer and arm bit */
771 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
772 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
773 		    ldgp->arm, ldgp->ldg_timer);
774 		if (rs != HPI_SUCCESS) {
775 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
776 			    "<== hxge_intr_mask_mgmt: set timer failed "
777 			    " rs 0x%x dg %d timer 0x%x",
778 			    rs, ldgp->ldg, ldgp->ldg_timer));
779 			return (HXGE_ERROR | rs);
780 		}
781 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
782 		    "==> hxge_intr_mask_mgmt: set timer OK "
783 		    " rs 0x%x ldg %d timer 0x%x",
784 		    rs, ldgp->ldg, ldgp->ldg_timer));
785 	}
786 
787 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_mask_mgmt"));
788 	return (HXGE_OK);
789 }
790 
791 hxge_status_t
792 hxge_intr_mask_mgmt_set(p_hxge_t hxgep, boolean_t on)
793 {
794 	p_hxge_ldgv_t	ldgvp;
795 	p_hxge_ldg_t	ldgp;
796 	p_hxge_ldv_t	ldvp;
797 	hpi_handle_t	handle;
798 	int		i, j;
799 	hpi_status_t	rs = HPI_SUCCESS;
800 
801 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
802 	    "==> hxge_intr_mask_mgmt_set (%d)", on));
803 
804 	if ((ldgvp = hxgep->ldgvp) == NULL) {
805 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
806 		    "==> hxge_intr_mask_mgmt_set: Null ldgvp"));
807 		return (HXGE_ERROR);
808 	}
809 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
810 	ldgp = ldgvp->ldgp;
811 	ldvp = ldgvp->ldvp;
812 	if (ldgp == NULL || ldvp == NULL) {
813 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
814 		    "<== hxge_intr_mask_mgmt_set: Null ldgp or ldvp"));
815 		return (HXGE_ERROR);
816 	}
817 
818 	/* set masks. */
819 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
820 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
821 		    "==> hxge_intr_mask_mgmt_set: flag %d ldg %d"
822 		    "set mask nldvs %d", on, ldgp->ldg, ldgp->nldvs));
823 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
824 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
825 			    "==> hxge_intr_mask_mgmt_set: "
826 			    "for %d %d flag %d", i, j, on));
827 			if (on) {
828 				ldvp->ldv_ldf_masks = 0;
829 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
830 				    "==> hxge_intr_mask_mgmt_set: "
831 				    "ON mask off"));
832 			} else {
833 				ldvp->ldv_ldf_masks = (uint8_t)LD_IM_MASK;
834 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
835 				    "==> hxge_intr_mask_mgmt_set:mask on"));
836 			}
837 
838 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
839 			    ldvp->ldv_ldf_masks);
840 			if (rs != HPI_SUCCESS) {
841 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
842 				    "==> hxge_intr_mask_mgmt_set: "
843 				    "set mask failed rs 0x%x ldv %d mask 0x%x",
844 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
845 				return (HXGE_ERROR | rs);
846 			}
847 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
848 			    "==> hxge_intr_mask_mgmt_set: flag %d"
849 			    "set mask OK ldv %d mask 0x%x",
850 			    on, ldvp->ldv, ldvp->ldv_ldf_masks));
851 		}
852 	}
853 
854 	ldgp = ldgvp->ldgp;
855 	/* set the arm bit */
856 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
857 		if (on && !ldgp->arm) {
858 			ldgp->arm = B_TRUE;
859 		} else if (!on && ldgp->arm) {
860 			ldgp->arm = B_FALSE;
861 		}
862 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
863 		    ldgp->arm, ldgp->ldg_timer);
864 		if (rs != HPI_SUCCESS) {
865 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
866 			    "<== hxge_intr_mask_mgmt_set: "
867 			    "set timer failed rs 0x%x ldg %d timer 0x%x",
868 			    rs, ldgp->ldg, ldgp->ldg_timer));
869 			return (HXGE_ERROR | rs);
870 		}
871 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
872 		    "==> hxge_intr_mask_mgmt_set: OK (flag %d) "
873 		    "set timer ldg %d timer 0x%x",
874 		    on, ldgp->ldg, ldgp->ldg_timer));
875 	}
876 
877 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_mask_mgmt_set"));
878 	return (HXGE_OK);
879 }
880 
881 /*
882  * For Big Endian systems, the mac address will be from OBP. For Little
883  * Endian (x64) systems, it will be retrieved from the card since it cannot
884  * be programmed into PXE.
885  * This function also populates the MMAC parameters.
886  */
887 static hxge_status_t
888 hxge_get_mac_addr_properties(p_hxge_t hxgep)
889 {
890 	uint32_t	num_macs;
891 	hxge_status_t	status;
892 
893 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_get_mac_addr_properties "));
894 
895 	(void) hxge_pfc_mac_addrs_get(hxgep);
896 	hxgep->ouraddr = hxgep->factaddr;
897 
898 	/*
899 	 * Get the number of MAC addresses the Hydra supports per blade.
900 	 */
901 	if (hxge_pfc_num_macs_get(hxgep, &num_macs) == HXGE_OK) {
902 		hxgep->hxge_mmac_info.num_mmac = (uint8_t)num_macs;
903 	} else {
904 		HXGE_ERROR_MSG((NULL, HXGE_ERR_CTL,
905 		    "hxge_get_mac_addr_properties: get macs failed"));
906 		return (HXGE_ERROR);
907 	}
908 
909 	/*
910 	 * Initialize alt. mac addr. in the mac pool
911 	 */
912 	status = hxge_mmac_init(hxgep);
913 	if (status != HXGE_OK) {
914 		HXGE_ERROR_MSG((NULL, HXGE_ERR_CTL,
915 		    "hxge_get_mac_addr_properties: init mmac failed"));
916 		return (HXGE_ERROR);
917 	}
918 
919 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_get_mac_addr_properties "));
920 	return (HXGE_OK);
921 }
922 
923 static void
924 hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
925 	uint8_t endldg, int *ngrps)
926 {
927 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup"));
928 	/* Assign the group number for each device. */
929 	(*ldvp)->ldg_assigned = (*ldgp)->ldg;
930 	(*ldvp)->ldgp = *ldgp;
931 	(*ldvp)->ldv = ldv;
932 
933 	HXGE_DEBUG_MSG((NULL, INT_CTL,
934 	    "==> hxge_ldgv_setup: ldv %d endldg %d ldg %d, ldvp $%p",
935 	    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
936 
937 	(*ldgp)->nldvs++;
938 	if ((*ldgp)->ldg == (endldg - 1)) {
939 		if ((*ldgp)->ldvp == NULL) {
940 			(*ldgp)->ldvp = *ldvp;
941 			*ngrps += 1;
942 			HXGE_DEBUG_MSG((NULL, INT_CTL,
943 			    "==> hxge_ldgv_setup: ngrps %d", *ngrps));
944 		}
945 		HXGE_DEBUG_MSG((NULL, INT_CTL,
946 		    "==> hxge_ldgv_setup: ldvp $%p ngrps %d",
947 		    *ldvp, *ngrps));
948 		++*ldvp;
949 	} else {
950 		(*ldgp)->ldvp = *ldvp;
951 		*ngrps += 1;
952 		HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup(done): "
953 		    "ldv %d endldg %d ldg %d, ldvp $%p",
954 		    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
955 		(*ldvp) = ++*ldvp;
956 		(*ldgp) = ++*ldgp;
957 		HXGE_DEBUG_MSG((NULL, INT_CTL,
958 		    "==> hxge_ldgv_setup: new ngrps %d", *ngrps));
959 	}
960 
961 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup: "
962 	    "ldg %d nldvs %d ldv %d ldvp $%p endldg %d ngrps %d",
963 	    (*ldgp)->ldg, (*ldgp)->nldvs, ldv, ldvp, endldg, *ngrps));
964 
965 	HXGE_DEBUG_MSG((NULL, INT_CTL, "<== hxge_ldgv_setup"));
966 }
967 
968 /*
969  * Note: This function assumes the following distribution of mac
970  * addresses for a hydra blade:
971  *
972  *      -------------
973  *    0|            |0 - local-mac-address for blade
974  *      -------------
975  *     |            |1 - Start of alt. mac addr. for blade
976  *     |            |
977  *     |            |
978  *     |            |15
979  *     --------------
980  */
981 
982 static hxge_status_t
983 hxge_mmac_init(p_hxge_t hxgep)
984 {
985 	int slot;
986 	hxge_mmac_t *mmac_info;
987 
988 	mmac_info = (hxge_mmac_t *)&hxgep->hxge_mmac_info;
989 
990 	/* Set flags for unique MAC */
991 	mmac_info->mac_pool[0].flags |= MMAC_SLOT_USED | MMAC_VENDOR_ADDR;
992 	mmac_info->num_factory_mmac = 1;
993 
994 	/*
995 	 * Skip the factory/default address which is in slot 0.
996 	 * Initialze all other mac addr. to "AVAILABLE" state.
997 	 * Clear flags of all alternate MAC slots.
998 	 */
999 	for (slot = 1; slot < mmac_info->num_mmac; slot++) {
1000 		(void) hpi_pfc_clear_mac_address(hxgep->hpi_handle, slot);
1001 		mmac_info->mac_pool[slot].flags = 0;
1002 	}
1003 
1004 	/* Exclude the factory mac address */
1005 	mmac_info->naddrfree = mmac_info->num_mmac - 1;
1006 
1007 	/* Initialize the first two parameters for mmac kstat */
1008 	hxgep->statsp->mmac_stats.mmac_max_cnt = mmac_info->num_mmac;
1009 	hxgep->statsp->mmac_stats.mmac_avail_cnt = mmac_info->naddrfree;
1010 
1011 	return (HXGE_OK);
1012 }
1013