summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/bnx/bnxcfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/bnx/bnxcfg.c')
-rw-r--r--usr/src/uts/common/io/bnx/bnxcfg.c714
1 files changed, 714 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/bnx/bnxcfg.c b/usr/src/uts/common/io/bnx/bnxcfg.c
new file mode 100644
index 0000000000..fd94c28c59
--- /dev/null
+++ b/usr/src/uts/common/io/bnx/bnxcfg.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright 2014-2017 Cavium, Inc.
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License, v.1, (the "License").
+ *
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the License at available
+ * at http://opensource.org/licenses/CDDL-1.0
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+#include "bnxcfg.h"
+
+const bnx_lnk_cfg_t bnx_copper_config = {
+ B_TRUE, /* link_autoneg */
+ B_FALSE, /* param_2500fdx */
+ B_TRUE, /* param_1000fdx */
+ B_TRUE, /* param_1000hdx */
+ B_TRUE, /* param_100fdx */
+ B_TRUE, /* param_100hdx */
+ B_TRUE, /* param_10fdx */
+ B_TRUE, /* param_10hdx */
+ B_TRUE, /* param_tx_pause */
+ B_TRUE /* param_rx_pause */
+};
+
+const bnx_lnk_cfg_t bnx_serdes_config = {
+ B_TRUE, /* link_autoneg */
+ B_TRUE, /* param_2500fdx */
+ B_TRUE, /* param_1000fdx */
+ B_TRUE, /* param_1000hdx */
+ B_FALSE, /* param_100fdx */
+ B_FALSE, /* param_100hdx */
+ B_FALSE, /* param_10fdx */
+ B_FALSE, /* param_10hdx */
+ B_TRUE, /* param_tx_pause */
+ B_TRUE /* param_rx_pause */
+};
+
+static void
+bnx_cfg_readbool(dev_info_t *dip, char *paramname, boolean_t *paramval)
+{
+ int rc;
+ int *option;
+ uint_t num_options;
+
+ if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_NOTPROM, paramname) ==
+ 1) {
+ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, paramname, &option, &num_options);
+
+ if (rc == DDI_PROP_SUCCESS) {
+ int inst = ddi_get_instance(dip);
+
+ if (num_options >= inst) {
+ if (option[inst] == 1) {
+ *paramval = B_TRUE;
+ } else {
+ *paramval = B_FALSE;
+ }
+ }
+ }
+
+ ddi_prop_free(option);
+ }
+} /* bnx_cfg_readbool */
+
+static void
+bnx_cfg_readint(dev_info_t *dip, char *paramname, int *paramval)
+{
+ int rc;
+ int *option;
+ uint_t num_options;
+
+ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ paramname, &option, &num_options);
+ if (rc == DDI_PROP_SUCCESS) {
+ int inst = ddi_get_instance(dip);
+
+ if (num_options >= inst) {
+ *paramval = option[inst];
+ }
+
+ ddi_prop_free(option);
+ }
+} /* bnx_cfg_readint */
+
+void
+bnx_cfg_msix(um_device_t * const umdevice)
+{
+ umdevice->dev_var.disableMsix = B_FALSE;
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "disable_msix",
+ &(umdevice->dev_var.disableMsix));
+}
+
+void
+bnx_cfg_init(um_device_t *const umdevice)
+{
+ int option;
+ lm_medium_t lmmedium;
+ lm_device_t *lmdevice;
+
+ lmdevice = &(umdevice->lm_dev);
+
+ lmmedium = lm_get_medium(lmdevice);
+ if (lmmedium == LM_MEDIUM_TYPE_FIBER) {
+ umdevice->dev_var.isfiber = B_TRUE;
+
+ bcopy(&bnx_serdes_config,
+ &(umdevice->hwinit.lnkcfg),
+ sizeof (bnx_serdes_config));
+ } else {
+ umdevice->dev_var.isfiber = B_FALSE;
+
+ bcopy(&bnx_copper_config, &(umdevice->hwinit.lnkcfg),
+ sizeof (bnx_copper_config));
+ }
+
+ umdevice->hwinit.flow_autoneg = B_TRUE;
+ umdevice->hwinit.wirespeed = B_TRUE;
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_autoneg_cap",
+ &(umdevice->hwinit.lnkcfg.link_autoneg));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_1000fdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_1000fdx));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_1000hdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_1000hdx));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "tx_pause_cap",
+ &(umdevice->hwinit.lnkcfg.param_tx_pause));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "rx_pause_cap",
+ &(umdevice->hwinit.lnkcfg.param_rx_pause));
+
+ if (umdevice->dev_var.isfiber) {
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_2500fdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_2500fdx));
+ } else {
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_100fdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_100fdx));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_100hdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_100hdx));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_10fdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_10fdx));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "adv_10hdx_cap",
+ &(umdevice->hwinit.lnkcfg.param_10hdx));
+ }
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "autoneg_flow",
+ &(umdevice->hwinit.flow_autoneg));
+
+ bnx_cfg_readbool(umdevice->os_param.dip, "wirespeed",
+ &(umdevice->hwinit.wirespeed));
+
+#if 1
+ /* FIXME -- Do we really need "transfer-speed"? */
+ /*
+ * The link speed may be forced to 10, 100 or 1000 Mbps using
+ * the property "transfer-speed". This may be done in OBP by
+ * using the command "apply transfer-speed=<speed> <device>".
+ * The speed may be 10, 100 or 1000 - any other value will be
+ * ignored. Note that this *enables* autonegotiation, but
+ * restricts it to the speed specified by the property.
+ */
+ option = 0;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "transfer-speed", &option);
+ switch (option) {
+ case 1000:
+ umdevice->hwinit.lnkcfg.link_autoneg = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_1000fdx = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_1000hdx = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_100fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_100hdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_10fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_10hdx = B_FALSE;
+ break;
+
+ case 100:
+ umdevice->hwinit.lnkcfg.link_autoneg = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_1000fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_1000hdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_100fdx = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_100hdx = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_10fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_10hdx = B_FALSE;
+ break;
+
+ case 10:
+ umdevice->hwinit.lnkcfg.link_autoneg = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_1000fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_1000hdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_100fdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_100hdx = B_FALSE;
+ umdevice->hwinit.lnkcfg.param_10fdx = B_TRUE;
+ umdevice->hwinit.lnkcfg.param_10hdx = B_TRUE;
+ break;
+ }
+#endif
+
+
+ /* FIXME -- Make the MAC address hwconf configurable. */
+
+ /* Checksum configuration */
+ option = USER_OPTION_CKSUM_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "checksum", &option);
+ switch (option) {
+ case USER_OPTION_CKSUM_TX_ONLY:
+ umdevice->dev_var.enabled_oflds = LM_OFFLOAD_TX_IP_CKSUM
+ | LM_OFFLOAD_TX_TCP_CKSUM
+ | LM_OFFLOAD_TX_UDP_CKSUM;
+ break;
+
+ case USER_OPTION_CKSUM_RX_ONLY:
+ umdevice->dev_var.enabled_oflds = LM_OFFLOAD_RX_IP_CKSUM
+ | LM_OFFLOAD_RX_TCP_CKSUM
+ | LM_OFFLOAD_RX_UDP_CKSUM;
+ break;
+
+ case USER_OPTION_CKSUM_TX_RX:
+ umdevice->dev_var.enabled_oflds = LM_OFFLOAD_TX_IP_CKSUM
+ | LM_OFFLOAD_RX_IP_CKSUM
+ | LM_OFFLOAD_TX_TCP_CKSUM
+ | LM_OFFLOAD_RX_TCP_CKSUM
+ | LM_OFFLOAD_TX_UDP_CKSUM
+ | LM_OFFLOAD_RX_UDP_CKSUM;
+ break;
+
+ case USER_OPTION_CKSUM_NONE:
+ default:
+ umdevice->dev_var.enabled_oflds = LM_OFFLOAD_NONE;
+ break;
+ }
+
+ /* Ticks interval between statistics block updates. */
+ option = USER_OPTION_STATSTICKS_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ USER_OPTION_KEYWORD_STATSTICKS, &option);
+ if (option >= USER_OPTION_STATSTICKS_MIN &&
+ option <= USER_OPTION_STATSTICKS_MAX) {
+ lmdevice->params.stats_ticks = option;
+ } else {
+ lmdevice->params.stats_ticks = USER_OPTION_STATSTICKS_DEFAULT;
+ }
+
+ /* Tx ticks for interrupt coalescing */
+ option = USER_OPTION_TXTICKS_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_coalesce_ticks", &option);
+ if (option >= USER_OPTION_TICKS_MIN &&
+ option <= USER_OPTION_TICKS_MAX) {
+ lmdevice->params.tx_ticks = option;
+ } else {
+ lmdevice->params.tx_ticks = USER_OPTION_TXTICKS_DEFAULT;
+ }
+
+ /* Interrupt mode Tx ticks for interrupt coalescing */
+ option = USER_OPTION_TXTICKS_INT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_coalesce_ticks_int", &option);
+ if (option >= USER_OPTION_TICKS_MIN &&
+ option <= USER_OPTION_TICKS_MAX) {
+ lmdevice->params.tx_ticks_int = option;
+ } else {
+ lmdevice->params.tx_ticks_int = USER_OPTION_TXTICKS_INT_DEFAULT;
+ }
+
+ /* Rx ticks for interrupt coalescing */
+ option = USER_OPTION_RXTICKS_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "rx_coalesce_ticks", &option);
+ if (option >= USER_OPTION_TICKS_MIN &&
+ option <= USER_OPTION_TICKS_MAX) {
+ lmdevice->params.rx_ticks = option;
+ } else {
+ lmdevice->params.rx_ticks = USER_OPTION_RXTICKS_DEFAULT;
+ }
+
+ /* Interrupt mode Rx ticks for interrupt coalescing */
+ option = USER_OPTION_RXTICKS_INT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "rx_coalesce_ticks_int", &option);
+ if (option >= USER_OPTION_TICKS_INT_MIN &&
+ option <= USER_OPTION_TICKS_INT_MAX) {
+ lmdevice->params.rx_ticks_int = option;
+ } else {
+ lmdevice->params.rx_ticks_int = USER_OPTION_RXTICKS_INT_DEFAULT;
+ }
+
+
+ /* Tx frames for interrupt coalescing */
+ option = USER_OPTION_TXFRAMES_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_coalesce_frames", &option);
+ if (option >= USER_OPTION_FRAMES_MIN &&
+ option <= USER_OPTION_FRAMES_MAX) {
+ lmdevice->params.tx_quick_cons_trip = option;
+ } else {
+ lmdevice->params.tx_quick_cons_trip =
+ USER_OPTION_TXFRAMES_DEFAULT;
+ }
+
+ /* Interrupt mode Tx frames for interrupt coalescing */
+ option = USER_OPTION_TXFRAMES_INT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_coalesce_frames_int", &option);
+ if (option >= USER_OPTION_FRAMES_MIN &&
+ option <= USER_OPTION_FRAMES_MAX) {
+ lmdevice->params.tx_quick_cons_trip_int = option;
+ } else {
+ lmdevice->params.tx_quick_cons_trip_int =
+ USER_OPTION_TXFRAMES_INT_DEFAULT;
+ }
+
+ /* Rx frames for interrupt coalescing */
+ option = USER_OPTION_RXFRAMES_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "rx_coalesce_frames", &option);
+ if (option >= USER_OPTION_FRAMES_MIN &&
+ option <= USER_OPTION_FRAMES_MAX) {
+ lmdevice->params.rx_quick_cons_trip = option;
+ } else {
+ lmdevice->params.rx_quick_cons_trip =
+ USER_OPTION_RXFRAMES_DEFAULT;
+ }
+
+ /* Interrupt mode Rx frames for interrupt coalescing */
+ option = USER_OPTION_RXFRAMES_INT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "rx_coalesce_frames_int", &option);
+ if (option >= USER_OPTION_FRAMES_MIN &&
+ option <= USER_OPTION_FRAMES_MAX) {
+ lmdevice->params.rx_quick_cons_trip_int = option;
+ } else {
+ lmdevice->params.rx_quick_cons_trip_int =
+ USER_OPTION_RXFRAMES_INT_DEFAULT;
+ }
+
+
+ option = USER_OPTION_TX_DESC_CNT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_descriptor_count", &option);
+ if (option < USER_OPTION_TX_DESC_CNT_MIN ||
+ option > USER_OPTION_TX_DESC_CNT_MAX) {
+ option = USER_OPTION_TX_DESC_CNT_DEFAULT;
+ }
+
+ /* FIXME -- tx bd pages assumes 1 pd === 1 bd */
+ _TX_QINFO(umdevice, 0).desc_cnt = option;
+ lmdevice->params.l2_tx_bd_page_cnt[0] = option / MAX_BD_PER_PAGE;
+ if (option % MAX_BD_PER_PAGE) {
+ lmdevice->params.l2_tx_bd_page_cnt[0]++;
+ }
+ if (lmdevice->params.l2_tx_bd_page_cnt[0] > 127) {
+ lmdevice->params.l2_tx_bd_page_cnt[0] = 127;
+ }
+
+
+ option = USER_OPTION_RX_DESC_CNT_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "rx_descriptor_count", &option);
+ if (option < USER_OPTION_RX_DESC_CNT_MIN ||
+ option > USER_OPTION_RX_DESC_CNT_MAX) {
+ option = USER_OPTION_RX_DESC_CNT_DEFAULT;
+ }
+
+ lmdevice->params.l2_rx_desc_cnt[0] = option;
+ option = (option * BNX_RECV_MAX_FRAGS) / MAX_BD_PER_PAGE;
+ lmdevice->params.l2_rx_bd_page_cnt[0] = option;
+ if (option % MAX_BD_PER_PAGE) {
+ lmdevice->params.l2_rx_bd_page_cnt[0]++;
+ }
+
+ option = USER_OPTION_MTU_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "mtu", &option);
+ if (option < USER_OPTION_MTU_MIN) {
+ umdevice->dev_var.mtu = USER_OPTION_MTU_MIN;
+ } else if (option > USER_OPTION_MTU_MAX) {
+ umdevice->dev_var.mtu = USER_OPTION_MTU_MAX;
+ } else {
+ umdevice->dev_var.mtu = option;
+ }
+ lmdevice->params.mtu = umdevice->dev_var.mtu +
+ sizeof (struct ether_header) + VLAN_TAGSZ;
+
+ /* Flag to enable double copy of transmit payload. */
+ option = USER_OPTION_TX_DCOPY_THRESH_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip,
+ "tx_copy_thresh", &option);
+ if (option < MIN_ETHERNET_PACKET_SIZE) {
+ option = MIN_ETHERNET_PACKET_SIZE;
+ }
+ umdevice->tx_copy_threshold = option;
+
+ /* Flag to enable double copy of receive packet. */
+ option = USER_OPTION_RX_DCOPY_DEFAULT;
+ bnx_cfg_readint(umdevice->os_param.dip, USER_OPTION_KEYWORD_RX_DCOPY,
+ &option);
+ if (option) {
+ umdevice->rx_copy_threshold = 0xffffffff;
+ } else {
+ umdevice->rx_copy_threshold = 0;
+ }
+} /* bnx_cfg_init */
+
+
+void
+bnx_cfg_reset(um_device_t *const umdevice)
+{
+ /* Reset the link status. */
+ umdevice->nddcfg.link_speed = 0;
+ umdevice->nddcfg.link_duplex = B_FALSE;
+ umdevice->nddcfg.link_tx_pause = B_FALSE;
+ umdevice->nddcfg.link_rx_pause = B_FALSE;
+
+ /* Reset the link partner status. */
+ umdevice->remote.link_autoneg = B_FALSE;
+ umdevice->remote.param_2500fdx = B_FALSE;
+ umdevice->remote.param_1000fdx = B_FALSE;
+ umdevice->remote.param_1000hdx = B_FALSE;
+ umdevice->remote.param_100fdx = B_FALSE;
+ umdevice->remote.param_100hdx = B_FALSE;
+ umdevice->remote.param_10fdx = B_FALSE;
+ umdevice->remote.param_10hdx = B_FALSE;
+ umdevice->remote.param_tx_pause = B_FALSE;
+ umdevice->remote.param_rx_pause = B_FALSE;
+
+ /* Reset the configuration to the hardware default. */
+ bcopy(&(umdevice->hwinit), &(umdevice->curcfg), sizeof (bnx_phy_cfg_t));
+} /* bnx_cfg_reset */
+
+
+
+static lm_medium_t
+bnx_cfg_map_serdes(um_device_t *const umdevice)
+{
+ lm_medium_t lmmedium;
+ lm_device_t *lmdevice;
+
+ lmdevice = &(umdevice->lm_dev);
+
+ lmmedium = LM_MEDIUM_TYPE_FIBER;
+
+ if (umdevice->curcfg.lnkcfg.link_autoneg) {
+ if (umdevice->curcfg.lnkcfg.param_2500fdx &&
+ umdevice->curcfg.lnkcfg.param_1000fdx &&
+ umdevice->curcfg.lnkcfg.param_1000hdx) {
+ /*
+ * All autoneg speeds are advertised.
+ * Don't specify a speed so we get the full range.
+ */
+ lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
+ } else {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_SINGLE_SPEED;
+
+ if (umdevice->curcfg.lnkcfg.param_2500fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_2500MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_1000fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_1000MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_1000hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_1000MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+ } else {
+ /* Configuration error. */
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_OFF;
+ goto error;
+ }
+ }
+
+ /*
+ * Enable serdes fallback for all but one particular HP
+ * platform.
+ */
+ if (CHIP_NUM(lmdevice) == CHIP_NUM_5706 &&
+ !(lmdevice->hw_info.svid == 0x103c &&
+ lmdevice->hw_info.ssid == 0x310c)) {
+ if (umdevice->curcfg.lnkcfg.param_2500fdx) {
+ lmmedium |=
+ LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK;
+ } else {
+ lmmedium |= LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK;
+ }
+ }
+ } else {
+ if (umdevice->curcfg.lnkcfg.param_2500fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_2500MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_1000fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_1000MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else {
+ /* Configuration error. */
+ goto error;
+ }
+ }
+
+ return (lmmedium);
+
+error:
+ /* Just give them full autoneg with no fallback capabilities. */
+ lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
+
+ return (lmmedium);
+} /* bnx_cfg_map_serdes */
+
+
+
+static lm_medium_t
+bnx_cfg_map_copper(um_device_t *const umdevice)
+{
+ lm_medium_t lmmedium;
+ lm_device_t *lmdevice;
+
+ lmdevice = &(umdevice->lm_dev);
+
+ lmmedium = LM_MEDIUM_TYPE_UTP;
+
+ if (umdevice->curcfg.lnkcfg.link_autoneg) {
+ if (umdevice->curcfg.lnkcfg.param_1000fdx == B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_1000hdx == B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_100fdx == B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_100hdx == B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10fdx == B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10hdx == B_TRUE) {
+ /*
+ * All autoneg speeds are advertised.
+ * Don't specify a speed so we get the full range.
+ */
+ lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
+ } else {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_SINGLE_SPEED;
+
+ if (umdevice->curcfg.lnkcfg.param_1000fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_1000MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_1000hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_1000MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+
+ if (umdevice->curcfg.lnkcfg.param_100fdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_100hdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10fdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10hdx ==
+ B_TRUE) {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
+ }
+ } else if (umdevice->curcfg.lnkcfg.param_100fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_100MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+
+ if (umdevice->curcfg.lnkcfg.param_100hdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10fdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10hdx ==
+ B_TRUE) {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
+ }
+ } else if (umdevice->curcfg.lnkcfg.param_100hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_100MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+
+ if (umdevice->curcfg.lnkcfg.param_10fdx ==
+ B_TRUE &&
+ umdevice->curcfg.lnkcfg.param_10hdx ==
+ B_TRUE) {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
+ }
+ } else if (umdevice->curcfg.lnkcfg.param_10fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_10MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+
+ if (umdevice->curcfg.lnkcfg.param_10hdx ==
+ B_TRUE) {
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS;
+ }
+ } else if (umdevice->curcfg.lnkcfg.param_10hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_10MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+ } else {
+ /* Configuration error. */
+ lmdevice->params.selective_autoneg =
+ SELECTIVE_AUTONEG_OFF;
+ goto error;
+ }
+ }
+ } else {
+ /*
+ * Forced speeds greater than 100Mbps intentionally omitted.
+ * Forcing speeds greater than 100Mbps on copper media is
+ * illegal.
+ */
+ if (umdevice->curcfg.lnkcfg.param_100fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_100MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_100hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_100MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_10fdx) {
+ lmmedium |= LM_MEDIUM_SPEED_10MBPS
+ | LM_MEDIUM_FULL_DUPLEX;
+ } else if (umdevice->curcfg.lnkcfg.param_10hdx) {
+ lmmedium |= LM_MEDIUM_SPEED_10MBPS
+ | LM_MEDIUM_HALF_DUPLEX;
+ } else {
+ /* Configuration error. */
+ goto error;
+ }
+ }
+
+ return (lmmedium);
+
+error:
+ /* Just give them full autoneg. */
+ lmmedium |= LM_MEDIUM_SPEED_AUTONEG;
+
+ return (lmmedium);
+} /* bnx_cfg_map_copper */
+
+
+
+/*
+ * Name: bnx_cfg_map_phy
+ *
+ * Input: ptr to device structure
+ *
+ * Return: None
+ *
+ * Description: This function is translates user configuration parameter,
+ * ones accessible through 'ndd' commands to LM driver settings.
+ * Driver chooses best possible parameters if conflicting ones
+ * are set by the user.
+ */
+void
+bnx_cfg_map_phy(um_device_t *const umdevice)
+{
+ lm_medium_t lmmedium;
+ lm_device_t *lmdevice;
+ lm_flow_control_t flowctrl;
+
+ lmdevice = &(umdevice->lm_dev);
+
+ /* Disable the remote PHY. */
+ lmdevice->params.enable_remote_phy = 0;
+
+ /* Assume selective autonegotiation is turned off. */
+ lmdevice->params.selective_autoneg = SELECTIVE_AUTONEG_OFF;
+
+ /* FIXME -- Clean up configuration parameters. */
+ if (umdevice->dev_var.isfiber) {
+ lmmedium = bnx_cfg_map_serdes(umdevice);
+ } else {
+ lmmedium = bnx_cfg_map_copper(umdevice);
+ }
+
+ lmdevice->params.req_medium = lmmedium;
+
+
+ flowctrl = LM_FLOW_CONTROL_NONE;
+
+ if (umdevice->curcfg.lnkcfg.param_tx_pause) {
+ flowctrl |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
+ }
+
+ if (umdevice->curcfg.lnkcfg.param_rx_pause) {
+ flowctrl |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
+ }
+
+ if (umdevice->curcfg.flow_autoneg == B_TRUE &&
+ flowctrl != LM_FLOW_CONTROL_NONE) {
+ /*
+ * FIXME -- LM Flow control constraint.
+ * LM_FLOW_CONTROL_AUTO_PAUSE ==
+ * (LM_FLOW_CONTROL_AUTO_PAUSE |
+ * LM_FLOW_CONTROL_TRANSMIT_PAUSE |
+ * LM_FLOW_CONTROL_RECEIVE_PAUSE)
+ * The LM does not allow us finer selection of what
+ * pause features to autoneg.
+ */
+ flowctrl |= LM_FLOW_CONTROL_AUTO_PAUSE;
+ }
+
+ lmdevice->params.flow_ctrl_cap = flowctrl;
+
+ lmdevice->params.wire_speed = umdevice->curcfg.wirespeed;
+} /* bnx_cfg_map_phy */