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
22const 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
35const 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
48static void
49bnx_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
76static void
77bnx_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
96void
97bnx_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
105void
106bnx_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
423void
424bnx_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
450static lm_medium_t
451bnx_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
519error:
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
528static lm_medium_t
529bnx_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
641error:
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 */
662void
663bnx_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