From 947eaaf6b0b58b0301d724a4745bd31d35616eb5 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Fri, 16 Jun 2017 22:58:47 +0000 Subject: [PATCH] 8866 bnxe MAC_CAPAB_TRANSCEIVER support Reviewed by: Patrick Mooney Reviewed by: Peter Tribble Approved by: Dan McDonald --- usr/src/uts/common/Makefile.files | 1 + usr/src/uts/common/io/bnxe/bnxe.h | 3 + usr/src/uts/common/io/bnxe/bnxe_gld.c | 6 + usr/src/uts/common/io/bnxe/bnxe_illumos.c | 180 ++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 usr/src/uts/common/io/bnxe/bnxe_illumos.c diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 4269e7514b..96f012d0ab 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -2219,6 +2219,7 @@ BNXE_OBJS += bnxe_cfg.o \ bnxe_tx.o \ bnxe_workq.o \ bnxe_clc.o \ + bnxe_illumos.o \ ecore_sp_verbs.o \ bnxe_context.o \ 57710_init_values.o \ diff --git a/usr/src/uts/common/io/bnxe/bnxe.h b/usr/src/uts/common/io/bnxe/bnxe.h index 9634d2f4ad..3a707708b5 100644 --- a/usr/src/uts/common/io/bnxe/bnxe.h +++ b/usr/src/uts/common/io/bnxe/bnxe.h @@ -916,6 +916,9 @@ int BnxeCheckAccHandle(ddi_acc_handle_t handle); int BnxeCheckDmaHandle(ddi_dma_handle_t handle); void BnxeFmErrorReport(um_device_t * pUM, char * detail); +/* bnxe_illumos.c */ +extern boolean_t bnxe_fill_transceiver(um_device_t *, void *); + extern kmutex_t bnxeLoaderMutex; extern u32_t bnxeNumPlumbed; diff --git a/usr/src/uts/common/io/bnxe/bnxe_gld.c b/usr/src/uts/common/io/bnxe/bnxe_gld.c index a49d89dd20..679ec3d5a9 100644 --- a/usr/src/uts/common/io/bnxe/bnxe_gld.c +++ b/usr/src/uts/common/io/bnxe/bnxe_gld.c @@ -34,6 +34,7 @@ /* * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ #include "bnxe.h" @@ -1859,6 +1860,11 @@ static boolean_t BnxeMacGetCapability(void * pArg, #endif /* not __S11 or __S12 */ +#if defined(ILLUMOS) + case MAC_CAPAB_TRANSCEIVER: + return bnxe_fill_transceiver(pUM, pCapabilityData); +#endif + default: return B_FALSE; diff --git a/usr/src/uts/common/io/bnxe/bnxe_illumos.c b/usr/src/uts/common/io/bnxe/bnxe_illumos.c new file mode 100644 index 0000000000..089fd773a8 --- /dev/null +++ b/usr/src/uts/common/io/bnxe/bnxe_illumos.c @@ -0,0 +1,180 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * illumos specific bnxe related functions. + */ + +#include "bnxe.h" + +/* + * Try to figure out which phy we should be using at this time based on the + * requested transceiver. + */ +static uint_t +bnxe_get_phy_id(um_device_t *um) +{ + if (um->lm_dev.params.link.num_phys <= 1) + return (ELINK_INT_PHY); + + if (um->lm_dev.vars.link.link_up) { + if ((um->lm_dev.vars.link.link_status & + LINK_STATUS_SERDES_LINK) && + (um->lm_dev.params.link.phy[ELINK_EXT_PHY2].supported & + ELINK_SUPPORTED_FIBRE)) + return (ELINK_EXT_PHY2); + return (ELINK_EXT_PHY1); + } else { + switch (elink_phy_selection(&um->lm_dev.params.link)) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + return (ELINK_EXT_PHY1); + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + return (ELINK_EXT_PHY2); + /* + * The above hardware types are the only ones currently defined + * by the specification and common code. If we end up with an + * unknown value, then we default to what the hardware considers + * the default, which is PHY1. + */ + default: + return (ELINK_EXT_PHY1); + } + } +} + +static int +bnxe_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) +{ + uint_t phyid; + um_device_t *um = arg; + struct elink_params *params; + struct elink_phy *phy; + boolean_t present = B_FALSE, usable = B_FALSE; + elink_status_t ret; + uint8_t buf; + + if (id != 0 || arg == NULL || infop == NULL) + return (EINVAL); + + BNXE_LOCK_ENTER_PHY(um); + phyid = bnxe_get_phy_id(um); + params = &um->lm_dev.params.link; + phy = ¶ms->phy[phyid]; + if (phy->media_type == ELINK_ETH_PHY_BASE_T) { + BNXE_LOCK_EXIT_PHY(um); + return (ENOTSUP); + } + + /* + * Right now, the core OS-independent code from QLogic doesn't quite + * track whether or not the phy is plugged in, though it easily could. + * As such, the best way to determine whether or not the phy is present + * is to see if we can read the first byte from page 0xa0. We expect to + * get an explicit timeout if the device isn't present. We'll propagate + * EIO on any other error as we're not in a good state to understand + * what happened. + */ + PHY_HW_LOCK(&um->lm_dev); + ret = elink_read_sfp_module_eeprom(phy, params, 0xa0, 0, sizeof (buf), + &buf); + PHY_HW_UNLOCK(&um->lm_dev); + if (ret != ELINK_STATUS_OK && ret != ELINK_STATUS_TIMEOUT) { + BNXE_LOCK_EXIT_PHY(um); + return (EIO); + } + if (ret == ELINK_STATUS_OK) { + present = B_TRUE; + if ((phy->flags & ELINK_FLAGS_SFP_NOT_APPROVED) == 0) + usable = B_TRUE; + } + BNXE_LOCK_EXIT_PHY(um); + + mac_transceiver_info_set_present(infop, present); + mac_transceiver_info_set_usable(infop, usable); + + return (0); +} + +static int +bnxe_transceiver_read(void *arg, uint_t id, uint_t page, void *bp, + size_t nbytes, off_t offset, size_t *nread) +{ + uint_t phyid; + um_device_t *um = arg; + struct elink_phy *phy; + struct elink_params *params; + elink_status_t ret; + + if (id != 0 || bp == NULL || nbytes == 0 || nread == NULL || + (page != 0xa0 && page != 0xa2) || offset < 0) + return (EINVAL); + + /* + * Sanity check length params. + */ + if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) { + return (EINVAL); + } + + BNXE_LOCK_ENTER_PHY(um); + phyid = bnxe_get_phy_id(um); + params = &um->lm_dev.params.link; + phy = &um->lm_dev.params.link.phy[phyid]; + + if (phy->media_type == ELINK_ETH_PHY_BASE_T) { + BNXE_LOCK_EXIT_PHY(um); + return (ENOTSUP); + } + + + PHY_HW_LOCK(&um->lm_dev); + ret = elink_read_sfp_module_eeprom(phy, params, (uint8_t)page, + (uint16_t)offset, (uint16_t)nbytes, bp); + PHY_HW_UNLOCK(&um->lm_dev); + + BNXE_LOCK_EXIT_PHY(um); + + switch (ret) { + case ELINK_STATUS_OK: + *nread = nbytes; + return (0); + case ELINK_OP_NOT_SUPPORTED: + return (ENOTSUP); + default: + return (EIO); + } +} + +boolean_t +bnxe_fill_transceiver(um_device_t *um, void *arg) +{ + uint_t ntran = 1; + mac_capab_transceiver_t *mct = arg; + + mct->mct_flags = 0; + /* + * While there is nominally a dual-phy version of bnxe out there (see + * ELINK_DUAL_MEDIA and related macros), these haven't been seen in the + * wild. For now, only assume that we have a single phy. + */ + mct->mct_ntransceivers = 1; + mct->mct_info = bnxe_transceiver_info; + mct->mct_read = bnxe_transceiver_read; + + return (B_TRUE); +} -- 2.11.4.GIT