xref: /illumos-gate/usr/src/uts/common/io/bnx/bnxcfg.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * Copyright 2014-2017 Cavium, Inc.
3  * The contents of this file are subject to the terms of the Common Development
4  * and Distribution License, v.1,  (the "License").
5  *
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the License at available
9  * at http://opensource.org/licenses/CDDL-1.0
10  *
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 /*
16  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
17  * Copyright (c) 2019, Joyent, Inc.
18  */
19 
20 #include "bnxcfg.h"
21 
22 const bnx_lnk_cfg_t bnx_copper_config = {
23 	B_TRUE,  /* link_autoneg   */
24 	B_FALSE, /* param_2500fdx  */
25 	B_TRUE,  /* param_1000fdx  */
26 	B_TRUE,  /* param_1000hdx  */
27 	B_TRUE,  /* param_100fdx   */
28 	B_TRUE,  /* param_100hdx   */
29 	B_TRUE,  /* param_10fdx    */
30 	B_TRUE,  /* param_10hdx    */
31 	B_TRUE,  /* param_tx_pause */
32 	B_TRUE   /* param_rx_pause */
33 };
34 
35 const bnx_lnk_cfg_t bnx_serdes_config = {
36 	B_TRUE,  /* link_autoneg   */
37 	B_TRUE,  /* param_2500fdx  */
38 	B_TRUE,  /* param_1000fdx  */
39 	B_TRUE,  /* param_1000hdx  */
40 	B_FALSE, /* param_100fdx   */
41 	B_FALSE, /* param_100hdx   */
42 	B_FALSE, /* param_10fdx    */
43 	B_FALSE, /* param_10hdx    */
44 	B_TRUE,  /* param_tx_pause */
45 	B_TRUE   /* param_rx_pause */
46 };
47 
48 static void
49 bnx_cfg_readbool(dev_info_t *dip, char *paramname, boolean_t *paramval)
50 {
51 	int rc;
52 	int *option;
53 	uint_t num_options;
54 
55 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_NOTPROM, paramname) ==
56 	    1) {
57 		rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
58 		    DDI_PROP_DONTPASS, paramname, &option, &num_options);
59 
60 		if (rc == DDI_PROP_SUCCESS) {
61 			int inst = ddi_get_instance(dip);
62 
63 			if (num_options >= inst) {
64 				if (option[inst] == 1) {
65 					*paramval = B_TRUE;
66 				} else {
67 					*paramval = B_FALSE;
68 				}
69 			}
70 		}
71 
72 		ddi_prop_free(option);
73 	}
74 } /* bnx_cfg_readbool */
75 
76 static void
77 bnx_cfg_readint(dev_info_t *dip, char *paramname, int *paramval)
78 {
79 	int rc;
80 	int *option;
81 	uint_t num_options;
82 
83 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
84 	    paramname, &option, &num_options);
85 	if (rc == DDI_PROP_SUCCESS) {
86 		int inst = ddi_get_instance(dip);
87 
88 		if (num_options >= inst) {
89 			*paramval = option[inst];
90 		}
91 
92 		ddi_prop_free(option);
93 	}
94 } /* bnx_cfg_readint */
95 
96 void
97 bnx_cfg_msix(um_device_t * const umdevice)
98 {
99 	umdevice->dev_var.disableMsix = B_FALSE;
100 
101 	bnx_cfg_readbool(umdevice->os_param.dip, "disable_msix",
102 	    &(umdevice->dev_var.disableMsix));
103 }
104 
105 void
106 bnx_cfg_init(um_device_t *const umdevice)
107 {
108 	int option;
109 	lm_medium_t lmmedium;
110 	lm_device_t *lmdevice;
111 
112 	lmdevice = &(umdevice->lm_dev);
113 
114 	lmmedium = lm_get_medium(lmdevice);
115 	if (lmmedium == LM_MEDIUM_TYPE_FIBER) {
116 		umdevice->dev_var.isfiber = B_TRUE;
117 
118 		bcopy(&bnx_serdes_config,
119 		    &(umdevice->hwinit.lnkcfg),
120 		    sizeof (bnx_serdes_config));
121 	} else {
122 		umdevice->dev_var.isfiber = B_FALSE;
123 
124 		bcopy(&bnx_copper_config, &(umdevice->hwinit.lnkcfg),
125 		    sizeof (bnx_copper_config));
126 	}
127 
128 	umdevice->hwinit.flow_autoneg = B_TRUE;
129 	umdevice->hwinit.wirespeed    = B_TRUE;
130 
131 	bnx_cfg_readbool(umdevice->os_param.dip, "adv_autoneg_cap",
132 	    &(umdevice->hwinit.lnkcfg.link_autoneg));
133 
134 	bnx_cfg_readbool(umdevice->os_param.dip, "adv_1000fdx_cap",
135 	    &(umdevice->hwinit.lnkcfg.param_1000fdx));
136 
137 	bnx_cfg_readbool(umdevice->os_param.dip, "adv_1000hdx_cap",
138 	    &(umdevice->hwinit.lnkcfg.param_1000hdx));
139 
140 	bnx_cfg_readbool(umdevice->os_param.dip, "tx_pause_cap",
141 	    &(umdevice->hwinit.lnkcfg.param_tx_pause));
142 
143 	bnx_cfg_readbool(umdevice->os_param.dip, "rx_pause_cap",
144 	    &(umdevice->hwinit.lnkcfg.param_rx_pause));
145 
146 	if (umdevice->dev_var.isfiber) {
147 		bnx_cfg_readbool(umdevice->os_param.dip, "adv_2500fdx_cap",
148 		    &(umdevice->hwinit.lnkcfg.param_2500fdx));
149 	} else {
150 		bnx_cfg_readbool(umdevice->os_param.dip, "adv_100fdx_cap",
151 		    &(umdevice->hwinit.lnkcfg.param_100fdx));
152 
153 		bnx_cfg_readbool(umdevice->os_param.dip, "adv_100hdx_cap",
154 		    &(umdevice->hwinit.lnkcfg.param_100hdx));
155 
156 		bnx_cfg_readbool(umdevice->os_param.dip, "adv_10fdx_cap",
157 		    &(umdevice->hwinit.lnkcfg.param_10fdx));
158 
159 		bnx_cfg_readbool(umdevice->os_param.dip, "adv_10hdx_cap",
160 		    &(umdevice->hwinit.lnkcfg.param_10hdx));
161 	}
162 
163 	bnx_cfg_readbool(umdevice->os_param.dip, "autoneg_flow",
164 	    &(umdevice->hwinit.flow_autoneg));
165 
166 	bnx_cfg_readbool(umdevice->os_param.dip, "wirespeed",
167 	    &(umdevice->hwinit.wirespeed));
168 
169 #if 1
170 	/* FIXME -- Do we really need "transfer-speed"? */
171 	/*
172 	 * The link speed may be forced to 10, 100 or 1000 Mbps using
173 	 * the property "transfer-speed". This may be done in OBP by
174 	 * using the command "apply transfer-speed=<speed> <device>".
175 	 * The speed may be 10, 100 or 1000 - any other value will be
176 	 * ignored.  Note that this *enables* autonegotiation, but
177 	 * restricts it to the speed specified by the property.
178 	 */
179 	option = 0;
180 	bnx_cfg_readint(umdevice->os_param.dip,
181 	    "transfer-speed", &option);
182 	switch (option) {
183 		case 1000:
184 			umdevice->hwinit.lnkcfg.link_autoneg  = B_TRUE;
185 			umdevice->hwinit.lnkcfg.param_1000fdx = B_TRUE;
186 			umdevice->hwinit.lnkcfg.param_1000hdx = B_TRUE;
187 			umdevice->hwinit.lnkcfg.param_100fdx  = B_FALSE;
188 			umdevice->hwinit.lnkcfg.param_100hdx  = B_FALSE;
189 			umdevice->hwinit.lnkcfg.param_10fdx   = B_FALSE;
190 			umdevice->hwinit.lnkcfg.param_10hdx   = B_FALSE;
191 			break;
192 
193 		case 100:
194 			umdevice->hwinit.lnkcfg.link_autoneg  = B_TRUE;
195 			umdevice->hwinit.lnkcfg.param_1000fdx = B_FALSE;
196 			umdevice->hwinit.lnkcfg.param_1000hdx = B_FALSE;
197 			umdevice->hwinit.lnkcfg.param_100fdx  = B_TRUE;
198 			umdevice->hwinit.lnkcfg.param_100hdx  = B_TRUE;
199 			umdevice->hwinit.lnkcfg.param_10fdx   = B_FALSE;
200 			umdevice->hwinit.lnkcfg.param_10hdx   = B_FALSE;
201 			break;
202 
203 		case 10:
204 			umdevice->hwinit.lnkcfg.link_autoneg  = B_TRUE;
205 			umdevice->hwinit.lnkcfg.param_1000fdx = B_FALSE;
206 			umdevice->hwinit.lnkcfg.param_1000hdx = B_FALSE;
207 			umdevice->hwinit.lnkcfg.param_100fdx  = B_FALSE;
208 			umdevice->hwinit.lnkcfg.param_100hdx  = B_FALSE;
209 			umdevice->hwinit.lnkcfg.param_10fdx   = B_TRUE;
210 			umdevice->hwinit.lnkcfg.param_10hdx   = B_TRUE;
211 			break;
212 	}
213 #endif
214 
215 
216 	/* FIXME -- Make the MAC address hwconf configurable. */
217 
218 	/* Checksum configuration */
219 	option = USER_OPTION_CKSUM_DEFAULT;
220 	bnx_cfg_readint(umdevice->os_param.dip,
221 	    "checksum", &option);
222 	switch (option) {
223 		case USER_OPTION_CKSUM_TX_ONLY:
224 			umdevice->dev_var.enabled_oflds = LM_OFFLOAD_TX_IP_CKSUM
225 			    | LM_OFFLOAD_TX_TCP_CKSUM
226 			    | LM_OFFLOAD_TX_UDP_CKSUM;
227 			break;
228 
229 		case USER_OPTION_CKSUM_RX_ONLY:
230 			umdevice->dev_var.enabled_oflds = LM_OFFLOAD_RX_IP_CKSUM
231 			    | LM_OFFLOAD_RX_TCP_CKSUM
232 			    | LM_OFFLOAD_RX_UDP_CKSUM;
233 			break;
234 
235 		case USER_OPTION_CKSUM_TX_RX:
236 			umdevice->dev_var.enabled_oflds = LM_OFFLOAD_TX_IP_CKSUM
237 			    | LM_OFFLOAD_RX_IP_CKSUM
238 			    | LM_OFFLOAD_TX_TCP_CKSUM
239 			    | LM_OFFLOAD_RX_TCP_CKSUM
240 			    | LM_OFFLOAD_TX_UDP_CKSUM
241 			    | LM_OFFLOAD_RX_UDP_CKSUM;
242 			break;
243 
244 		case USER_OPTION_CKSUM_NONE:
245 		default:
246 			umdevice->dev_var.enabled_oflds = LM_OFFLOAD_NONE;
247 			break;
248 	}
249 
250 	/* Ticks interval between statistics block updates. */
251 	option = USER_OPTION_STATSTICKS_DEFAULT;
252 	bnx_cfg_readint(umdevice->os_param.dip,
253 	    USER_OPTION_KEYWORD_STATSTICKS, &option);
254 	if (option >= USER_OPTION_STATSTICKS_MIN &&
255 	    option <= USER_OPTION_STATSTICKS_MAX) {
256 		lmdevice->params.stats_ticks = option;
257 	} else {
258 		lmdevice->params.stats_ticks = USER_OPTION_STATSTICKS_DEFAULT;
259 	}
260 
261 	/* Tx ticks for interrupt coalescing */
262 	option = USER_OPTION_TXTICKS_DEFAULT;
263 	bnx_cfg_readint(umdevice->os_param.dip,
264 	    "tx_coalesce_ticks", &option);
265 	if (option >= USER_OPTION_TICKS_MIN &&
266 	    option <= USER_OPTION_TICKS_MAX) {
267 		lmdevice->params.tx_ticks = option;
268 	} else {
269 		lmdevice->params.tx_ticks = USER_OPTION_TXTICKS_DEFAULT;
270 	}
271 
272 	/* Interrupt mode Tx ticks for interrupt coalescing */
273 	option = USER_OPTION_TXTICKS_INT_DEFAULT;
274 	bnx_cfg_readint(umdevice->os_param.dip,
275 	    "tx_coalesce_ticks_int", &option);
276 	if (option >= USER_OPTION_TICKS_MIN &&
277 	    option <= USER_OPTION_TICKS_MAX) {
278 		lmdevice->params.tx_ticks_int = option;
279 	} else {
280 		lmdevice->params.tx_ticks_int = USER_OPTION_TXTICKS_INT_DEFAULT;
281 	}
282 
283 	/* Rx ticks for interrupt coalescing */
284 	option = USER_OPTION_RXTICKS_DEFAULT;
285 	bnx_cfg_readint(umdevice->os_param.dip,
286 	    "rx_coalesce_ticks", &option);
287 	if (option >= USER_OPTION_TICKS_MIN &&
288 	    option <= USER_OPTION_TICKS_MAX) {
289 		lmdevice->params.rx_ticks = option;
290 	} else {
291 		lmdevice->params.rx_ticks = USER_OPTION_RXTICKS_DEFAULT;
292 	}
293 
294 	/* Interrupt mode Rx ticks for interrupt coalescing */
295 	option = USER_OPTION_RXTICKS_INT_DEFAULT;
296 	bnx_cfg_readint(umdevice->os_param.dip,
297 	    "rx_coalesce_ticks_int", &option);
298 	if (option >= USER_OPTION_TICKS_INT_MIN &&
299 	    option <= USER_OPTION_TICKS_INT_MAX) {
300 		lmdevice->params.rx_ticks_int = option;
301 	} else {
302 		lmdevice->params.rx_ticks_int = USER_OPTION_RXTICKS_INT_DEFAULT;
303 	}
304 
305 
306 	/* Tx frames for interrupt coalescing */
307 	option = USER_OPTION_TXFRAMES_DEFAULT;
308 	bnx_cfg_readint(umdevice->os_param.dip,
309 	    "tx_coalesce_frames", &option);
310 	if (option >= USER_OPTION_FRAMES_MIN &&
311 	    option <= USER_OPTION_FRAMES_MAX) {
312 		lmdevice->params.tx_quick_cons_trip = option;
313 	} else {
314 		lmdevice->params.tx_quick_cons_trip =
315 		    USER_OPTION_TXFRAMES_DEFAULT;
316 	}
317 
318 	/* Interrupt mode Tx frames for interrupt coalescing */
319 	option = USER_OPTION_TXFRAMES_INT_DEFAULT;
320 	bnx_cfg_readint(umdevice->os_param.dip,
321 	    "tx_coalesce_frames_int", &option);
322 	if (option >= USER_OPTION_FRAMES_MIN &&
323 	    option <= USER_OPTION_FRAMES_MAX) {
324 		lmdevice->params.tx_quick_cons_trip_int = option;
325 	} else {
326 		lmdevice->params.tx_quick_cons_trip_int =
327 		    USER_OPTION_TXFRAMES_INT_DEFAULT;
328 	}
329 
330 	/* Rx frames for interrupt coalescing */
331 	option = USER_OPTION_RXFRAMES_DEFAULT;
332 	bnx_cfg_readint(umdevice->os_param.dip,
333 	    "rx_coalesce_frames", &option);
334 	if (option >= USER_OPTION_FRAMES_MIN &&
335 	    option <= USER_OPTION_FRAMES_MAX) {
336 		lmdevice->params.rx_quick_cons_trip = option;
337 	} else {
338 		lmdevice->params.rx_quick_cons_trip =
339 		    USER_OPTION_RXFRAMES_DEFAULT;
340 	}
341 
342 	/* Interrupt mode Rx frames for interrupt coalescing */
343 	option = USER_OPTION_RXFRAMES_INT_DEFAULT;
344 	bnx_cfg_readint(umdevice->os_param.dip,
345 	    "rx_coalesce_frames_int", &option);
346 	if (option >= USER_OPTION_FRAMES_MIN &&
347 	    option <= USER_OPTION_FRAMES_MAX) {
348 		lmdevice->params.rx_quick_cons_trip_int = option;
349 	} else {
350 		lmdevice->params.rx_quick_cons_trip_int =
351 		    USER_OPTION_RXFRAMES_INT_DEFAULT;
352 	}
353 
354 
355 	option = USER_OPTION_TX_DESC_CNT_DEFAULT;
356 	bnx_cfg_readint(umdevice->os_param.dip,
357 	    "tx_descriptor_count", &option);
358 	if (option < USER_OPTION_TX_DESC_CNT_MIN ||
359 	    option > USER_OPTION_TX_DESC_CNT_MAX) {
360 		option = USER_OPTION_TX_DESC_CNT_DEFAULT;
361 	}
362 
363 	/* FIXME -- tx bd pages assumes 1 pd === 1 bd */
364 	_TX_QINFO(umdevice, 0).desc_cnt = option;
365 	lmdevice->params.l2_tx_bd_page_cnt[0] = option / MAX_BD_PER_PAGE;
366 	if (option % MAX_BD_PER_PAGE) {
367 		lmdevice->params.l2_tx_bd_page_cnt[0]++;
368 	}
369 	if (lmdevice->params.l2_tx_bd_page_cnt[0] > 127) {
370 		lmdevice->params.l2_tx_bd_page_cnt[0] = 127;
371 	}
372 
373 
374 	option = USER_OPTION_RX_DESC_CNT_DEFAULT;
375 	bnx_cfg_readint(umdevice->os_param.dip,
376 	    "rx_descriptor_count", &option);
377 	if (option < USER_OPTION_RX_DESC_CNT_MIN ||
378 	    option > USER_OPTION_RX_DESC_CNT_MAX) {
379 		option = USER_OPTION_RX_DESC_CNT_DEFAULT;
380 	}
381 
382 	lmdevice->params.l2_rx_desc_cnt[0] = option;
383 	option = (option * BNX_RECV_MAX_FRAGS) / MAX_BD_PER_PAGE;
384 	lmdevice->params.l2_rx_bd_page_cnt[0] = option;
385 	if (option % MAX_BD_PER_PAGE) {
386 		lmdevice->params.l2_rx_bd_page_cnt[0]++;
387 	}
388 
389 	option = USER_OPTION_MTU_DEFAULT;
390 	bnx_cfg_readint(umdevice->os_param.dip,
391 	    "mtu", &option);
392 	if (option < USER_OPTION_MTU_MIN) {
393 		umdevice->dev_var.mtu = USER_OPTION_MTU_MIN;
394 	} else if (option > USER_OPTION_MTU_MAX) {
395 		umdevice->dev_var.mtu = USER_OPTION_MTU_MAX;
396 	} else {
397 		umdevice->dev_var.mtu = option;
398 	}
399 	lmdevice->params.mtu = umdevice->dev_var.mtu +
400 	    sizeof (struct ether_header) + VLAN_TAGSZ;
401 
402 	/* Flag to enable double copy of transmit payload. */
403 	option = USER_OPTION_TX_DCOPY_THRESH_DEFAULT;
404 	bnx_cfg_readint(umdevice->os_param.dip,
405 	    "tx_copy_thresh", &option);
406 	if (option < MIN_ETHERNET_PACKET_SIZE) {
407 		option = MIN_ETHERNET_PACKET_SIZE;
408 	}
409 	umdevice->tx_copy_threshold = option;
410 
411 	/* Flag to enable double copy of receive packet. */
412 	option = USER_OPTION_RX_DCOPY_DEFAULT;
413 	bnx_cfg_readint(umdevice->os_param.dip, USER_OPTION_KEYWORD_RX_DCOPY,
414 	    &option);
415 	if (option) {
416 		umdevice->rx_copy_threshold = 0xffffffff;
417 	} else {
418 		umdevice->rx_copy_threshold = 0;
419 	}
420 } /* bnx_cfg_init */
421 
422 
423 void
424 bnx_cfg_reset(um_device_t *const umdevice)
425 {
426 	/* Reset the link status. */
427 	umdevice->nddcfg.link_speed = 0;
428 	umdevice->nddcfg.link_duplex = B_FALSE;
429 	umdevice->nddcfg.link_tx_pause = B_FALSE;
430 	umdevice->nddcfg.link_rx_pause = B_FALSE;
431 
432 	/* Reset the link partner status. */
433 	umdevice->remote.link_autoneg   = B_FALSE;
434 	umdevice->remote.param_2500fdx  = B_FALSE;
435 	umdevice->remote.param_1000fdx  = B_FALSE;
436 	umdevice->remote.param_1000hdx  = B_FALSE;
437 	umdevice->remote.param_100fdx   = B_FALSE;
438 	umdevice->remote.param_100hdx   = B_FALSE;
439 	umdevice->remote.param_10fdx    = B_FALSE;
440 	umdevice->remote.param_10hdx    = B_FALSE;
441 	umdevice->remote.param_tx_pause = B_FALSE;
442 	umdevice->remote.param_rx_pause = B_FALSE;
443 
444 	/* Reset the configuration to the hardware default. */
445 	bcopy(&(umdevice->hwinit), &(umdevice->curcfg), sizeof (bnx_phy_cfg_t));
446 } /* bnx_cfg_reset */
447 
448 
449 
450 static lm_medium_t
451 bnx_cfg_map_serdes(um_device_t *const umdevice)
452 {
453 	lm_medium_t lmmedium;
454 	lm_device_t *lmdevice;
455 
456 	lmdevice = &(umdevice->lm_dev);
457 
458 	lmmedium = LM_MEDIUM_TYPE_FIBER;
459 
460 	if (umdevice->curcfg.lnkcfg.link_autoneg) {
461 		if (umdevice->curcfg.lnkcfg.param_2500fdx &&
462 		    umdevice->curcfg.lnkcfg.param_1000fdx &&
463 		    umdevice->curcfg.lnkcfg.param_1000hdx) {
464 			/*
465 			 * All autoneg speeds are advertised.
466 			 * Don't specify a speed so we get the full range.
467 			 */
468 			lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
469 		} else {
470 			lmdevice->params.selective_autoneg =
471 			    SELECTIVE_AUTONEG_SINGLE_SPEED;
472 
473 			if (umdevice->curcfg.lnkcfg.param_2500fdx) {
474 				lmmedium |= LM_MEDIUM_SPEED_2500MBPS
475 				    | LM_MEDIUM_FULL_DUPLEX;
476 			} else if (umdevice->curcfg.lnkcfg.param_1000fdx) {
477 				lmmedium |= LM_MEDIUM_SPEED_1000MBPS
478 				    | LM_MEDIUM_FULL_DUPLEX;
479 			} else if (umdevice->curcfg.lnkcfg.param_1000hdx) {
480 				lmmedium |= LM_MEDIUM_SPEED_1000MBPS
481 				    | LM_MEDIUM_HALF_DUPLEX;
482 			} else {
483 				/* Configuration error. */
484 				lmdevice->params.selective_autoneg =
485 				    SELECTIVE_AUTONEG_OFF;
486 				goto error;
487 			}
488 		}
489 
490 		/*
491 		 * Enable serdes fallback for all but one particular HP
492 		 * platform.
493 		 */
494 		if (CHIP_NUM(lmdevice) == CHIP_NUM_5706 &&
495 		    !(lmdevice->hw_info.svid == 0x103c &&
496 		    lmdevice->hw_info.ssid == 0x310c)) {
497 			if (umdevice->curcfg.lnkcfg.param_2500fdx) {
498 				lmmedium |=
499 				    LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK;
500 			} else {
501 				lmmedium |= LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK;
502 			}
503 		}
504 	} else {
505 		if (umdevice->curcfg.lnkcfg.param_2500fdx) {
506 			lmmedium |= LM_MEDIUM_SPEED_2500MBPS
507 			    | LM_MEDIUM_FULL_DUPLEX;
508 		} else if (umdevice->curcfg.lnkcfg.param_1000fdx) {
509 			lmmedium |= LM_MEDIUM_SPEED_1000MBPS
510 			    | LM_MEDIUM_FULL_DUPLEX;
511 		} else {
512 			/* Configuration error. */
513 			goto error;
514 		}
515 	}
516 
517 	return (lmmedium);
518 
519 error:
520 	/* Just give them full autoneg with no fallback capabilities. */
521 	lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
522 
523 	return (lmmedium);
524 } /* bnx_cfg_map_serdes */
525 
526 
527 
528 static lm_medium_t
529 bnx_cfg_map_copper(um_device_t *const umdevice)
530 {
531 	lm_medium_t lmmedium;
532 	lm_device_t *lmdevice;
533 
534 	lmdevice = &(umdevice->lm_dev);
535 
536 	lmmedium = LM_MEDIUM_TYPE_UTP;
537 
538 	if (umdevice->curcfg.lnkcfg.link_autoneg) {
539 		if (umdevice->curcfg.lnkcfg.param_1000fdx == B_TRUE &&
540 		    umdevice->curcfg.lnkcfg.param_1000hdx == B_TRUE &&
541 		    umdevice->curcfg.lnkcfg.param_100fdx == B_TRUE &&
542 		    umdevice->curcfg.lnkcfg.param_100hdx == B_TRUE &&
543 		    umdevice->curcfg.lnkcfg.param_10fdx == B_TRUE &&
544 		    umdevice->curcfg.lnkcfg.param_10hdx == B_TRUE) {
545 			/*
546 			 * All autoneg speeds are advertised.
547 			 * Don't specify a speed so we get the full range.
548 			 */
549 			lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
550 		} else {
551 			lmdevice->params.selective_autoneg =
552 			    SELECTIVE_AUTONEG_SINGLE_SPEED;
553 
554 			if (umdevice->curcfg.lnkcfg.param_1000fdx) {
555 				lmmedium |= LM_MEDIUM_SPEED_1000MBPS
556 				    | LM_MEDIUM_FULL_DUPLEX;
557 			} else if (umdevice->curcfg.lnkcfg.param_1000hdx) {
558 				lmmedium |= LM_MEDIUM_SPEED_1000MBPS
559 				    | LM_MEDIUM_HALF_DUPLEX;
560 
561 				if (umdevice->curcfg.lnkcfg.param_100fdx ==
562 				    B_TRUE &&
563 				    umdevice->curcfg.lnkcfg.param_100hdx ==
564 				    B_TRUE &&
565 				    umdevice->curcfg.lnkcfg.param_10fdx ==
566 				    B_TRUE &&
567 				    umdevice->curcfg.lnkcfg.param_10hdx ==
568 				    B_TRUE) {
569 					lmdevice->params.selective_autoneg =
570 					    SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
571 				}
572 			} else if (umdevice->curcfg.lnkcfg.param_100fdx) {
573 				lmmedium |= LM_MEDIUM_SPEED_100MBPS
574 				    | LM_MEDIUM_FULL_DUPLEX;
575 
576 				if (umdevice->curcfg.lnkcfg.param_100hdx ==
577 				    B_TRUE &&
578 				    umdevice->curcfg.lnkcfg.param_10fdx ==
579 				    B_TRUE &&
580 				    umdevice->curcfg.lnkcfg.param_10hdx ==
581 				    B_TRUE) {
582 					lmdevice->params.selective_autoneg =
583 					    SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
584 				}
585 			} else if (umdevice->curcfg.lnkcfg.param_100hdx) {
586 				lmmedium |= LM_MEDIUM_SPEED_100MBPS
587 				    | LM_MEDIUM_HALF_DUPLEX;
588 
589 				if (umdevice->curcfg.lnkcfg.param_10fdx ==
590 				    B_TRUE &&
591 				    umdevice->curcfg.lnkcfg.param_10hdx ==
592 				    B_TRUE) {
593 					lmdevice->params.selective_autoneg =
594 					    SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
595 				}
596 			} else if (umdevice->curcfg.lnkcfg.param_10fdx) {
597 				lmmedium |= LM_MEDIUM_SPEED_10MBPS
598 				    | LM_MEDIUM_FULL_DUPLEX;
599 
600 				if (umdevice->curcfg.lnkcfg.param_10hdx ==
601 				    B_TRUE) {
602 					lmdevice->params.selective_autoneg =
603 					    SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
604 				}
605 			} else if (umdevice->curcfg.lnkcfg.param_10hdx) {
606 				lmmedium |= LM_MEDIUM_SPEED_10MBPS
607 				    | LM_MEDIUM_HALF_DUPLEX;
608 			} else {
609 				/* Configuration error. */
610 				lmdevice->params.selective_autoneg =
611 				    SELECTIVE_AUTONEG_OFF;
612 				goto error;
613 			}
614 		}
615 	} else {
616 		/*
617 		 * Forced speeds greater than 100Mbps intentionally omitted.
618 		 * Forcing speeds greater than 100Mbps on copper media is
619 		 * illegal.
620 		 */
621 		if (umdevice->curcfg.lnkcfg.param_100fdx) {
622 			lmmedium |= LM_MEDIUM_SPEED_100MBPS
623 			    | LM_MEDIUM_FULL_DUPLEX;
624 		} else if (umdevice->curcfg.lnkcfg.param_100hdx) {
625 			lmmedium |= LM_MEDIUM_SPEED_100MBPS
626 			    | LM_MEDIUM_HALF_DUPLEX;
627 		} else if (umdevice->curcfg.lnkcfg.param_10fdx) {
628 			lmmedium |= LM_MEDIUM_SPEED_10MBPS
629 			    | LM_MEDIUM_FULL_DUPLEX;
630 		} else if (umdevice->curcfg.lnkcfg.param_10hdx) {
631 			lmmedium |= LM_MEDIUM_SPEED_10MBPS
632 			    | LM_MEDIUM_HALF_DUPLEX;
633 		} else {
634 			/* Configuration error. */
635 			goto error;
636 		}
637 	}
638 
639 	return (lmmedium);
640 
641 error:
642 	/* Just give them full autoneg. */
643 	lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
644 
645 	return (lmmedium);
646 } /* bnx_cfg_map_copper */
647 
648 
649 
650 /*
651  * Name:	bnx_cfg_map_phy
652  *
653  * Input:	ptr to device structure
654  *
655  * Return:	None
656  *
657  * Description:	This function is translates user configuration parameter,
658  *		ones accessible through 'ndd' commands to LM driver settings.
659  *		Driver chooses best possible parameters if conflicting ones
660  *		are set by the user.
661  */
662 void
663 bnx_cfg_map_phy(um_device_t *const umdevice)
664 {
665 	lm_medium_t lmmedium;
666 	lm_device_t *lmdevice;
667 	lm_flow_control_t flowctrl;
668 
669 	lmdevice = &(umdevice->lm_dev);
670 
671 	/* Disable the remote PHY. */
672 	lmdevice->params.enable_remote_phy = 0;
673 
674 	/* Assume selective autonegotiation is turned off. */
675 	lmdevice->params.selective_autoneg = SELECTIVE_AUTONEG_OFF;
676 
677 	/* FIXME -- Clean up configuration parameters. */
678 	if (umdevice->dev_var.isfiber) {
679 		lmmedium = bnx_cfg_map_serdes(umdevice);
680 	} else {
681 		lmmedium = bnx_cfg_map_copper(umdevice);
682 	}
683 
684 	lmdevice->params.req_medium = lmmedium;
685 
686 
687 	flowctrl = LM_FLOW_CONTROL_NONE;
688 
689 	if (umdevice->curcfg.lnkcfg.param_tx_pause) {
690 		flowctrl |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
691 	}
692 
693 	if (umdevice->curcfg.lnkcfg.param_rx_pause) {
694 		flowctrl |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
695 	}
696 
697 	if (umdevice->curcfg.flow_autoneg == B_TRUE &&
698 	    flowctrl != LM_FLOW_CONTROL_NONE) {
699 		/*
700 		 * FIXME -- LM Flow control constraint.
701 		 * LM_FLOW_CONTROL_AUTO_PAUSE ==
702 		 * (LM_FLOW_CONTROL_AUTO_PAUSE |
703 		 * LM_FLOW_CONTROL_TRANSMIT_PAUSE |
704 		 * LM_FLOW_CONTROL_RECEIVE_PAUSE)
705 		 * The LM does not allow us finer selection of what
706 		 * pause features to autoneg.
707 		 */
708 		flowctrl |= LM_FLOW_CONTROL_AUTO_PAUSE;
709 	}
710 
711 	lmdevice->params.flow_ctrl_cap = flowctrl;
712 
713 	lmdevice->params.wire_speed = umdevice->curcfg.wirespeed;
714 } /* bnx_cfg_map_phy */
715