/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2014 QLogic Corporation * The contents of this file are subject to the terms of the * QLogic End User License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the License at * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/ * QLogic_End_User_Software_License.txt * See the License for the specific language governing permissions * and limitations under the License. */ /* * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Joyent, Inc. * Copyright 2023 Oxide Computer Company */ #include "bnxe.h" #include #include #include #if !(defined(__S11) || defined(__S12)) #define mri_driver mr_driver #define mri_start mr_start #define mri_stop mr_stop #define mri_intr mr_intr #define mri_poll mr_poll #define mri_tx mr_send #define mgi_driver mrg_driver #define mgi_start mrg_start #define mgi_stop mrg_stop #define mgi_count mrg_count #define mgi_addmac mrg_addmac #define mgi_remmac mrg_addmac #define mr_gaddring mr_gadd_ring #define mr_gremring mr_grem_ring #endif /* not __S11 or __S12 */ /* * Reconfiguring the network devices parameters require net_config * privilege starting Solaris 10. Only root user is allowed to * update device parameter in Solaris 9 and earlier version. Following * declaration allows single binary image to run on all OS versions. */ extern int secpolicy_net_config(const cred_t *, boolean_t); extern int drv_priv(cred_t *); #pragma weak secpolicy_net_config #pragma weak drv_priv #ifdef MC_SETPROP char * bnxeLink_priv_props[] = { "_adv_2500fdx_cap", "_en_2500fdx_cap", "_adv_txpause_cap", "_en_txpause_cap", "_txpause", "_adv_rxpause_cap", "_en_rxpause_cap", "_rxpause", "_autoneg_flow", "_checksum", "_num_rings", "_rx_descs", "_rx_free_reclaim", "_rx_copy_threshold", "_tx_descs", "_tx_free_reclaim", "_tx_copy_threshold", "_tx_ring_policy", "_interrupt_coalesce", "_rx_interrupt_coalesce_usec", "_tx_interrupt_coalesce_usec", "_disable_msix", "_l2_fw_flow_ctrl", "_autogreeen_enable", "_lso_enable", "_log_enable", "_fcoe_enable", NULL }; #endif /* MC_SETPROP */ static int BnxeMacStats(void * pArg, uint_t stat, uint64_t * pVal) { um_device_t * pUM = (um_device_t *)pArg; lm_device_t * pLM; b10_l2_chip_statistics_t b10_l2_stats; int idx, rc = 0; if ((pUM == NULL) || (pVal == NULL)) { return EINVAL; } pLM = &pUM->lm_dev; BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { BNXE_LOCK_EXIT_GLD(pUM); return EAGAIN; } *pVal = 0; switch (stat) { case MAC_STAT_IFSPEED: *pVal = (pUM->props.link_speed * 1000000ULL); break; case MAC_STAT_MULTIRCV: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCInMulticastPkts; break; case MAC_STAT_BRDCSTRCV: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCInBroadcastPkts; break; case MAC_STAT_MULTIXMT: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCOutMulticastPkts; break; case MAC_STAT_BRDCSTXMT: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCOutBroadcastPkts; break; case MAC_STAT_NORCVBUF: lm_get_stats(pLM, LM_STATS_RCV_NO_BUFFER_DROP, (u64_t *)pVal); break; case MAC_STAT_NOXMTBUF: *pVal = 0; LM_FOREACH_TSS_IDX(pLM, idx) { *pVal += pUM->txq[idx].txRecycle; } break; case MAC_STAT_IERRORS: case ETHER_STAT_MACRCV_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfInErrors; break; case MAC_STAT_OERRORS: /* XXX not available */ break; case MAC_STAT_COLLISIONS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.EtherStatsCollisions; break; case MAC_STAT_RBYTES: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCInOctets; break; case MAC_STAT_IPACKETS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCInPkts; break; case MAC_STAT_OBYTES: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCOutOctets; break; case MAC_STAT_OPACKETS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.IfHCOutPkts; break; case ETHER_STAT_ALIGN_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsAlignmentErrors; break; case ETHER_STAT_FCS_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsFCSErrors; break; case ETHER_STAT_FIRST_COLLISIONS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsSingleCollisionFrames; break; case ETHER_STAT_MULTI_COLLISIONS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsMultipleCollisionFrames; break; case ETHER_STAT_DEFER_XMTS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsDeferredTransmissions; break; case ETHER_STAT_TX_LATE_COLLISIONS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsLateCollisions; break; case ETHER_STAT_EX_COLLISIONS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsExcessiveCollisions; break; case ETHER_STAT_MACXMT_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsInternalMacTransmitErrors; break; case ETHER_STAT_CARRIER_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.Dot3StatsCarrierSenseErrors; break; case ETHER_STAT_TOOLONG_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.EtherStatsOverrsizePkts; break; #if (MAC_VERSION > 1) case ETHER_STAT_TOOSHORT_ERRORS: lm_stats_get_l2_chip_stats(pLM, &b10_l2_stats, L2_CHIP_STATISTICS_VER_NUM_1); *pVal = b10_l2_stats.EtherStatsUndersizePkts; break; #endif case ETHER_STAT_XCVR_ADDR: *pVal = pLM->vars.phy_addr; break; case ETHER_STAT_XCVR_ID: *pVal = 0; break; case ETHER_STAT_XCVR_INUSE: *pVal = (uint64_t)bnxe_phy_to_media(pUM); break; #if (MAC_VERSION > 1) case ETHER_STAT_CAP_10GFDX: *pVal = 1; break; #endif case ETHER_STAT_CAP_1000FDX: *pVal = 1; break; #if 0 case ETHER_STAT_CAP_1000HDX: //*pVal = linkconf->param_1000hdx; *pVal = 0; break; #endif case ETHER_STAT_CAP_100FDX: //*pVal = linkconf->param_100fdx; *pVal = 1; break; case ETHER_STAT_CAP_100HDX: //*pVal = linkconf->param_100hdx; *pVal = 1; break; case ETHER_STAT_CAP_10FDX: //*pVal = linkconf->param_10fdx; *pVal = 1; break; case ETHER_STAT_CAP_10HDX: //*pVal = linkconf->param_10hdx; *pVal = 1; break; case ETHER_STAT_CAP_ASMPAUSE: *pVal = 1; break; case ETHER_STAT_CAP_PAUSE: *pVal = 1; break; case ETHER_STAT_CAP_AUTONEG: *pVal = 1; break; #if (MAC_VERSION > 1) case ETHER_STAT_CAP_REMFAULT: *pVal = 1; break; #endif #if (MAC_VERSION > 1) case ETHER_STAT_ADV_CAP_10GFDX: *pVal = pUM->curcfg.lnkcfg.param_10000fdx; break; #endif case ETHER_STAT_ADV_CAP_1000FDX: *pVal = pUM->curcfg.lnkcfg.param_1000fdx; break; #if 0 case ETHER_STAT_ADV_CAP_1000HDX: //*pVal = pUM->curcfg.lnkcfg.param_1000hdx; *pVal = 0; break; #endif case ETHER_STAT_ADV_CAP_100FDX: *pVal = pUM->curcfg.lnkcfg.param_100fdx; break; case ETHER_STAT_ADV_CAP_100HDX: *pVal = pUM->curcfg.lnkcfg.param_100hdx; break; case ETHER_STAT_ADV_CAP_10FDX: *pVal = pUM->curcfg.lnkcfg.param_10fdx; break; case ETHER_STAT_ADV_CAP_10HDX: *pVal = pUM->curcfg.lnkcfg.param_10hdx; break; case ETHER_STAT_ADV_CAP_ASMPAUSE: *pVal = 1; break; case ETHER_STAT_ADV_CAP_PAUSE: *pVal = 1; break; case ETHER_STAT_ADV_CAP_AUTONEG: *pVal = pUM->curcfg.lnkcfg.link_autoneg; break; #if (MAC_VERSION > 1) case ETHER_STAT_ADV_REMFAULT: *pVal = 1; break; #endif #if 0 /* LP caps not supported */ #if (MAC_VERSION > 1) case ETHER_STAT_LP_CAP_10GFDX: *pVal = pUM->remote.param_10000fdx; break; #endif case ETHER_STAT_LP_CAP_1000FDX: *pVal = pUM->remote.param_1000fdx; break; #if 0 case ETHER_STAT_LP_CAP_1000HDX: //*pVal = pUM->remote.param_1000hdx; *pVal = 0; break; #endif case ETHER_STAT_LP_CAP_100FDX: *pVal = pUM->remote.param_100fdx; break; case ETHER_STAT_LP_CAP_100HDX: *pVal = pUM->remote.param_100hdx; break; case ETHER_STAT_LP_CAP_10FDX: *pVal = pUM->remote.param_10fdx; break; case ETHER_STAT_LP_CAP_10HDX: *pVal = pUM->remote.param_10hdx; break; #if 0 case ETHER_STAT_LP_CAP_ASMPAUSE: /* XXX implement LP_ASYM_PAUSE stat */ break; case ETHER_STAT_LP_CAP_PAUSE: /* XXX implement LP_PAUSE stat */ break; #endif case ETHER_STAT_LP_CAP_AUTONEG: *pVal = pUM->remote.link_autoneg; break; case ETHER_STAT_LP_REMFAULT: /* XXX implement LP_REMFAULT stat */ break; #endif /* LP caps not supported */ #if 0 case ETHER_STAT_LINK_ASMPAUSE: /* XXX implement ASMPAUSE stat */ break; case ETHER_STAT_LINK_PAUSE: /* XXX implement PAUSE stat */ break; #endif case ETHER_STAT_LINK_AUTONEG: *pVal = pUM->curcfg.lnkcfg.link_autoneg; break; case ETHER_STAT_LINK_DUPLEX: *pVal = (pUM->props.link_duplex == B_TRUE) ? LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; break; default: rc = ENOTSUP; } BNXE_LOCK_EXIT_GLD(pUM); return rc; } /* * This routine is called by GLD to enable device for packet reception and * enable interrupts. */ static int BnxeMacStart(void * pArg) { um_device_t * pUM = (um_device_t *)pArg; BNXE_LOCK_ENTER_GLD(pUM); if (pUM->plumbed) { /* already started */ BNXE_LOCK_EXIT_GLD(pUM); return EAGAIN; } /* Always report the initial link state as unknown. */ mac_link_update(pUM->pMac, LINK_STATE_UNKNOWN); if (BnxeHwStartL2(pUM)) { BNXE_LOCK_EXIT_GLD(pUM); return EIO; } atomic_swap_32(&pUM->plumbed, B_TRUE); mutex_enter(&bnxeLoaderMutex); bnxeNumPlumbed++; mutex_exit(&bnxeLoaderMutex); BNXE_LOCK_EXIT_GLD(pUM); return 0; } /* * This routine stops packet reception by clearing RX MASK register. Also * interrupts are disabled for this device. */ static void BnxeMacStop(void * pArg) { um_device_t * pUM = (um_device_t *)pArg; BNXE_LOCK_ENTER_GLD(pUM); if (pUM->plumbed) { atomic_swap_32(&pUM->plumbed, B_FALSE); BnxeHwStopL2(pUM); /* Report the link state back to unknown. */ mac_link_update(pUM->pMac, LINK_STATE_UNKNOWN); mutex_enter(&bnxeLoaderMutex); bnxeNumPlumbed--; mutex_exit(&bnxeLoaderMutex); } BNXE_LOCK_EXIT_GLD(pUM); } /* (flag) TRUE = on, FALSE = off */ static int BnxeMacPromiscuous(void * pArg, boolean_t flag) { um_device_t * pUM = (um_device_t *)pArg; BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { BNXE_LOCK_EXIT_GLD(pUM); return EAGAIN; } if (flag) { pUM->devParams.rx_filter_mask[LM_CLI_IDX_NDIS] |= LM_RX_MASK_PROMISCUOUS_MODE; } else { pUM->devParams.rx_filter_mask[LM_CLI_IDX_NDIS] &= ~LM_RX_MASK_PROMISCUOUS_MODE; } BNXE_LOCK_ENTER_HWINIT(pUM); if (BnxeRxMask(pUM, LM_CLI_IDX_NDIS, pUM->devParams.rx_filter_mask[LM_CLI_IDX_NDIS]) < 0) { BNXE_LOCK_EXIT_HWINIT(pUM); BNXE_LOCK_EXIT_GLD(pUM); return ECANCELED; } BNXE_LOCK_EXIT_HWINIT(pUM); BNXE_LOCK_EXIT_GLD(pUM); return 0; } /* * This function is used to enable or disable multicast packet reception for * particular multicast addresses. * (flag) TRUE = add, FALSE = remove */ static int BnxeMacMulticast(void * pArg, boolean_t flag, const uint8_t * pMcastAddr) { um_device_t * pUM = (um_device_t *)pArg; int rc; BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { BNXE_LOCK_EXIT_GLD(pUM); return EAGAIN; } BNXE_LOCK_ENTER_HWINIT(pUM); rc = BnxeMulticast(pUM, LM_CLI_IDX_NDIS, flag, pMcastAddr, B_TRUE); BNXE_LOCK_EXIT_HWINIT(pUM); BNXE_LOCK_EXIT_GLD(pUM); return rc; } #ifdef BNXE_RINGS #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) static int BnxeRxRingGroupAddMac(void * groupHandle, const uint8_t * pMacAddr, uint64_t flags) #else static int BnxeRxRingGroupAddMac(void * groupHandle, const uint8_t * pMacAddr) #endif { RxQueueGroup * pRxQGroup = (RxQueueGroup *)groupHandle; um_device_t * pUM = (um_device_t *)pRxQGroup->pUM; //u32_t idx = pRxQGroup->idx; int rc; #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) _NOTE(ARGUNUSED(flags)) #endif BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { BNXE_LOCK_EXIT_GLD(pUM); return ECANCELED; } /* Validate MAC address */ if (IS_ETH_MULTICAST(pMacAddr)) { BnxeLogWarn(pUM, "Cannot program a mcast/bcast address as a MAC Address."); BNXE_LOCK_EXIT_GLD(pUM); return EINVAL; } if (pUM->ucastTableLen == LM_MAX_UC_TABLE_SIZE) { BNXE_LOCK_EXIT_GLD(pUM); return ENOMEM; } BNXE_LOCK_ENTER_HWINIT(pUM); COPY_ETH_ADDRESS(pMacAddr, pUM->lm_dev.params.mac_addr); rc = BnxeMacAddress(pUM, LM_CLI_IDX_NDIS, B_TRUE, pUM->lm_dev.params.mac_addr); BNXE_LOCK_EXIT_HWINIT(pUM); if (rc < 0) { BNXE_LOCK_EXIT_GLD(pUM); return ECANCELED; } pUM->ucastTableLen++; BNXE_LOCK_EXIT_GLD(pUM); return 0; } static int BnxeRxRingGroupRemMac(void * groupHandle, const uint8_t * pMacAddr) { RxQueueGroup * pRxQGroup = (RxQueueGroup *)groupHandle; um_device_t * pUM = (um_device_t *)pRxQGroup->pUM; //u32_t idx = pRxQGroup->idx; int rc; BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { BNXE_LOCK_EXIT_GLD(pUM); return ECANCELED; } if (pUM->ucastTableLen == 0) { BNXE_LOCK_EXIT_GLD(pUM); return EINVAL; } BNXE_LOCK_ENTER_HWINIT(pUM); if (!IS_ETH_ADDRESS_EQUAL(pMacAddr, pUM->lm_dev.params.mac_addr)) { BnxeLogWarn(pUM, "Deleting MAC address that doesn't match default"); /* XXX */ } rc = BnxeMacAddress(pUM, LM_CLI_IDX_NDIS, B_FALSE, pUM->lm_dev.params.mac_addr); memset(pUM->lm_dev.params.mac_addr, 0, sizeof(pUM->lm_dev.params.mac_addr)); BNXE_LOCK_EXIT_HWINIT(pUM); if (rc < 0) { BNXE_LOCK_EXIT_GLD(pUM); return ECANCELED; } pUM->ucastTableLen--; BNXE_LOCK_EXIT_GLD(pUM); return 0; } static mblk_t * BnxeTxRingSend(void * ringHandle, mblk_t * pMblk) { TxQueue * pTxQ = (TxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pTxQ->pUM; u32_t idx = pTxQ->idx; mblk_t * pNextMblk; int rc; while (pMblk) { pNextMblk = pMblk->b_next; pMblk->b_next = NULL; rc = BnxeTxSendMblk(pUM, idx, pMblk, 0, 0); if (rc == BNXE_TX_GOODXMIT) { pMblk = pNextMblk; continue; } else if (rc == BNXE_TX_DEFERPKT) { pMblk = pNextMblk; } else { pMblk->b_next = pNextMblk; } break; } return pMblk; } #endif /* BNXE_RINGS */ static int BnxeMacUnicast(void * pArg, const uint8_t * pMacAddr) { um_device_t * pUM = (um_device_t *)pArg; int rc; BNXE_LOCK_ENTER_GLD(pUM); if (!pUM->plumbed) { memcpy(pUM->gldMac, pMacAddr, ETHERNET_ADDRESS_SIZE); BNXE_LOCK_EXIT_GLD(pUM); return 0; } /* Validate MAC address */ if (IS_ETH_MULTICAST(pMacAddr)) { BnxeLogWarn(pUM, "Cannot program a mcast/bcast address as a MAC Address."); BNXE_LOCK_EXIT_GLD(pUM); return EINVAL; } BNXE_LOCK_ENTER_HWINIT(pUM); COPY_ETH_ADDRESS(pMacAddr, pUM->lm_dev.params.mac_addr); rc = BnxeMacAddress(pUM, LM_CLI_IDX_NDIS, B_TRUE, pUM->lm_dev.params.mac_addr); BNXE_LOCK_EXIT_HWINIT(pUM); if (rc < 0) { BNXE_LOCK_EXIT_GLD(pUM); return EAGAIN; } BNXE_LOCK_EXIT_GLD(pUM); return 0; } static mblk_t * BnxeMacTx(void * pArg, mblk_t * pMblk) { um_device_t * pUM = (um_device_t *)pArg; mblk_t * pNextMblk; int ring, rc; BNXE_LOCK_ENTER_GLDTX(pUM, RW_READER); if (!pUM->plumbed) { freemsgchain(pMblk); BNXE_LOCK_EXIT_GLDTX(pUM); return NULL; } while (pMblk) { ring = BnxeRouteTxRing(pUM, pMblk); pNextMblk = pMblk->b_next; pMblk->b_next = NULL; //rc = BnxeTxSendMblk(pUM, NDIS_CID(&pUM->lm_dev), pMblk, 0, 0); rc = BnxeTxSendMblk(pUM, ring, pMblk, 0, 0); if (rc == BNXE_TX_GOODXMIT) { pMblk = pNextMblk; continue; } else if (rc == BNXE_TX_DEFERPKT) { pMblk = pNextMblk; } else { pMblk->b_next = pNextMblk; } break; } BNXE_LOCK_EXIT_GLDTX(pUM); return pMblk; } #ifdef MC_RESOURCES static void BnxeBlank(void * pArg, time_t tick_cnt, uint_t pkt_cnt) { um_device_t * pUM = (um_device_t *)pArg; if (!pUM->plumbed) { return; } /* XXX * Need to dynamically reconfigure the hw with new interrupt * coalescing params... */ } static void BnxeMacResources(void * pArg) { um_device_t * pUM = (um_device_t *)pArg; mac_rx_fifo_t mrf; int idx; mrf.mrf_type = MAC_RX_FIFO; mrf.mrf_blank = BnxeBlank; mrf.mrf_arg = (void *)pUM; mrf.mrf_normal_blank_time = 25; mrf.mrf_normal_pkt_count = 8; LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) { pUM->macRxResourceHandles[idx] = mac_resource_add(pUM->pMac, (mac_resource_t *)&mrf); } } #endif /* MC_RESOURCES */ static boolean_t BnxeReadReg(um_device_t * pUM, struct bnxe_reg_data * pData) { if (pData->offset & 0x3) { BnxeLogWarn(pUM, "Invalid register offset for GIOCBNXEREG ioctl"); return B_FALSE; } LM_BAR_RD32_OFFSET(&pUM->lm_dev, 0, pData->offset, &pData->value); return B_TRUE; } static boolean_t BnxeWriteReg(um_device_t * pUM, struct bnxe_reg_data * pData) { if (pData->offset & 0x3) { BnxeLogWarn(pUM, "Invalid register offset for SIOCBNXEREG ioctl"); return B_FALSE; } LM_BAR_WR32_OFFSET(&pUM->lm_dev, 0, pData->offset, pData->value); return B_TRUE; } static boolean_t BnxeReadNvm(um_device_t * pUM, struct bnxe_nvram_data * pData) { if (pData->offset & 0x3) { BnxeLogWarn(pUM, "Invalid register offset for GIOCBNXENVRM ioctl"); return B_FALSE; } if (lm_nvram_read(&pUM->lm_dev, pData->offset, pData->value, (pData->num_of_u32 * sizeof(u32_t))) != LM_STATUS_SUCCESS) { return B_FALSE; } return B_TRUE; } static boolean_t BnxeWriteNvm(um_device_t * pUM, struct bnxe_nvram_data * pData) { if (pData->offset & 0x3) { BnxeLogWarn(pUM, "Invalid register offset for SIOCBNXENVRM ioctl"); return B_FALSE; } if (lm_nvram_write(&pUM->lm_dev, pData->offset, pData->value, (pData->num_of_u32 * sizeof(u32_t))) != LM_STATUS_SUCCESS) { return B_FALSE; } return B_TRUE; } static boolean_t BnxeReadPciCfg(um_device_t * pUM, struct bnxe_reg_data * pData) { pData->value = pci_config_get32(pUM->pPciCfg, (off_t)pData->offset); return B_TRUE; } typedef enum { STATS_SHOW_TYPE_NUM, STATS_SHOW_TYPE_STR, STATS_SHOW_TYPE_CNT, STATS_SHOW_TYPE_MAX } stats_show_type_t; typedef union _b10_stats_show_data_t { u32_t op; /* ioctl sub-commond */ struct { u32_t num; /* return number of stats */ u32_t len; /* length of each string item */ } desc; /* variable length... */ char str[1]; /* holds names of desc.num stats, each desc.len in length */ struct { b10_l2_chip_statistics_v2_t l2_chip_stats; b10_l4_chip_statistics_t l4_chip_stats; b10_l2_driver_statistics_t l2_drv_stats; b10_l4_driver_statistics_t l4_drv_stats; } cnt; } b10_stats_show_data_t; static boolean_t BnxeStatsShow(um_device_t * pUM, b10_stats_show_data_t * pStats, u32_t statsLen) { stats_show_type_t op; const size_t stats_size = sizeof(pStats->cnt); /* * All stats names MUST conform to STATS_STR_LEN length!!! */ #define STATS_STR_LEN 39 /* XXX * Note: these strings must be updated whenever any of * b10_l2_chip_statistics_t, b10_l4_chip_statistics_t, * b10_l2_driver_statistics_t or b10_l4_driver_statistics_t * are changed, or additional statistics are required. */ const char p_stat_str[] = // b10_l2_chip_statistics_t "l2_chip_stats_ver_num\0 " "IfHCInOctets\0 " "IfHCInBadOctets\0 " "IfHCOutOctets\0 " "IfHCOutBadOctets\0 " "IfHCOutPkts\0 " "IfHCInPkts\0 " "IfHCInUcastPkts\0 " "IfHCInMulticastPkts\0 " "IfHCInBroadcastPkts\0 " "IfHCOutUcastPkts\0 " "IfHCOutMulticastPkts\0 " "IfHCOutBroadcastPkts\0 " "IfHCInUcastOctets\0 " "IfHCInMulticastOctets\0 " "IfHCInBroadcastOctets\0 " "IfHCOutUcastOctets\0 " "IfHCOutMulticastOctets\0 " "IfHCOutBroadcastOctets\0 " "IfHCOutDiscards\0 " "IfHCInFalseCarrierErrors\0 " "Dot3StatsInternalMacTransmitErrors\0 " "Dot3StatsCarrierSenseErrors\0 " "Dot3StatsFCSErrors\0 " "Dot3StatsAlignmentErrors\0 " "Dot3StatsSingleCollisionFrames\0 " "Dot3StatsMultipleCollisionFrames\0 " "Dot3StatsDeferredTransmissions\0 " "Dot3StatsExcessiveCollisions\0 " "Dot3StatsLateCollisions\0 " "EtherStatsCollisions\0 " "EtherStatsFragments\0 " "EtherStatsJabbers\0 " "EtherStatsUndersizePkts\0 " "EtherStatsOverrsizePkts\0 " "EtherStatsPktsTx64Octets\0 " "EtherStatsPktsTx65Octetsto127Octets\0 " "EtherStatsPktsTx128Octetsto255Octets\0 " "EtherStatsPktsTx256Octetsto511Octets\0 " "EtherStatsPktsTx512Octetsto1023Octets\0 " "EtherStatsPktsTx1024Octetsto1522Octets\0" "EtherStatsPktsTxOver1522Octets\0 " "XonPauseFramesReceived\0 " "XoffPauseFramesReceived\0 " "OutXonSent\0 " "OutXoffSent\0 " "FlowControlDone\0 " "MacControlFramesReceived\0 " "XoffStateEntered\0 " "IfInFramesL2FilterDiscards\0 " "IfInTTL0Discards\0 " "IfInxxOverflowDiscards\0 " "IfInMBUFDiscards\0 " "IfInErrors\0 " "IfInErrorsOctets\0 " "IfInNoBrbBuffer\0 " "Nig_brb_packet\0 " "Nig_brb_truncate\0 " "Nig_flow_ctrl_discard\0 " "Nig_flow_ctrl_octets\0 " "Nig_flow_ctrl_packet\0 " "Nig_mng_discard\0 " "Nig_mng_octet_inp\0 " "Nig_mng_octet_out\0 " "Nig_mng_packet_inp\0 " "Nig_mng_packet_out\0 " "Nig_pbf_octets\0 " "Nig_pbf_packet\0 " "Nig_safc_inp\0 " "Tx_Lpi_Count\0 " // This counter counts the number of timers the debounced version of EEE link idle is asserted // b10_l4_chip_statistics_t "l4_chip_stats_ver_num\0 " "NoTxCqes\0 " "InTCP4Segments\0 " "OutTCP4Segments\0 " "RetransmittedTCP4Segments\0 " "InTCP4Errors\0 " "InIP4Receives\0 " "InIP4HeaderErrors\0 " "InIP4Discards\0 " "InIP4Delivers\0 " "InIP4Octets\0 " "OutIP4Octets\0 " "InIP4TruncatedPackets\0 " "InTCP6Segments\0 " "OutTCP6Segments\0 " "RetransmittedTCP6Segments\0 " "InTCP6Errors\0 " "InIP6Receives\0 " "InIP6HeaderErrors\0 " "InIP6Discards\0 " "InIP6Delivers\0 " "InIP6Octets\0 " "OutIP6Octets\0 " "InIP6TruncatedPackets\0 " // b10_l2_driver_statistics_t "l2_driver_stats_ver_num\0 " "RxIPv4FragCount\0 " "RxIpCsErrorCount\0 " "RxTcpCsErrorCount\0 " "RxLlcSnapCount\0 " "RxPhyErrorCount\0 " "RxIpv6ExtCount\0 " "TxNoL2Bd\0 " "TxNoSqWqe\0 " "TxL2AssemblyBufUse\0 " // b10_l4_driver_statistics_t "l4_driver_stats_ver_num\0 " "CurrentlyIpv4Established\0 " "OutIpv4Resets\0 " "OutIpv4Fin\0 " "InIpv4Reset\0 " "InIpv4Fin\0 " "CurrentlyIpv6Established\0 " "OutIpv6Resets\0 " "OutIpv6Fin\0 " "InIpv6Reset\0 " "InIpv6Fin\0 " "RxIndicateReturnPendingCnt\0 " "RxIndicateReturnDoneCnt\0 " "RxActiveGenBufCnt\0 " "TxNoL4Bd\0 " "TxL4AssemblyBufUse\0 " ; ASSERT_STATIC((sizeof(p_stat_str) / STATS_STR_LEN) == (stats_size / sizeof(u64_t))); op = *((stats_show_type_t *)pStats); switch (op) { case STATS_SHOW_TYPE_NUM: if (statsLen < sizeof(pStats->desc)) { return B_FALSE; } pStats->desc.num = (stats_size / sizeof(u64_t)); pStats->desc.len = STATS_STR_LEN; return B_TRUE; case STATS_SHOW_TYPE_STR: if (statsLen != sizeof(p_stat_str)) { return B_FALSE; } memcpy(pStats->str, p_stat_str, sizeof(p_stat_str)); return B_TRUE; case STATS_SHOW_TYPE_CNT: if (statsLen != stats_size) { return B_FALSE; } lm_stats_get_l2_chip_stats(&pUM->lm_dev, &pStats->cnt.l2_chip_stats, L2_CHIP_STATISTICS_VER_NUM_2); lm_stats_get_l4_chip_stats(&pUM->lm_dev, &pStats->cnt.l4_chip_stats); lm_stats_get_l2_driver_stats(&pUM->lm_dev ,&pStats->cnt.l2_drv_stats); lm_stats_get_l4_driver_stats(&pUM->lm_dev, &pStats->cnt.l4_drv_stats); return B_TRUE; default: return B_FALSE; } } static void BnxeMacIoctl(void * pArg, queue_t * pQ, mblk_t * pMblk) { um_device_t * pUM = (um_device_t *)pArg; struct iocblk * pIoctl; int rc; if ((pQ == NULL) || (pMblk == NULL)) { return; } if (pMblk->b_datap->db_type != M_IOCTL) { miocnak(pQ, pMblk, 0, EINVAL); return; } pIoctl = (struct iocblk *)pMblk->b_rptr; BNXE_LOCK_ENTER_GLD(pUM); switch (pIoctl->ioc_cmd) { case GIOCBNXELLDP: if ((pIoctl->ioc_count != sizeof(b10_lldp_params_get_t)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, sizeof(b10_lldp_params_get_t)) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (((b10_lldp_params_get_t *)pMblk->b_cont->b_rptr)->ver_num != LLDP_PARAMS_VER_NUM) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (lm_dcbx_lldp_read_params(&pUM->lm_dev, (b10_lldp_params_get_t *)pMblk->b_cont->b_rptr) != LM_STATUS_SUCCESS) { miocnak(pQ, pMblk, 0, (!IS_DCB_ENABLED(&pUM->lm_dev)) ? ENOTSUP : EINVAL); break; } miocack(pQ, pMblk, pIoctl->ioc_count, 0); break; case GIOCBNXEDCBX: if ((pIoctl->ioc_count != sizeof(b10_dcbx_params_get_t)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, sizeof(b10_dcbx_params_get_t)) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (((b10_dcbx_params_get_t *)pMblk->b_cont->b_rptr)->ver_num != DCBX_PARAMS_VER_NUM) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (lm_dcbx_read_params(&pUM->lm_dev, (b10_dcbx_params_get_t *)pMblk->b_cont->b_rptr) != LM_STATUS_SUCCESS) { miocnak(pQ, pMblk, 0, (!IS_DCB_ENABLED(&pUM->lm_dev)) ? ENOTSUP : EINVAL); break; } miocack(pQ, pMblk, pIoctl->ioc_count, 0); break; case SIOCBNXEDCBX: /* XXX */ miocnak(pQ, pMblk, 0, EINVAL); break; case GIOCBNXEREG: if ((pIoctl->ioc_count != sizeof(struct bnxe_reg_data)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, sizeof(struct bnxe_reg_data)) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeReadReg(pUM, (struct bnxe_reg_data *)pMblk->b_cont->b_rptr)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; case SIOCBNXEREG: if ((pIoctl->ioc_count != sizeof(struct bnxe_reg_data)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, sizeof(struct bnxe_reg_data)) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeWriteReg(pUM, (struct bnxe_reg_data *)pMblk->b_cont->b_rptr)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; case GIOCBNXENVRM: if ((pIoctl->ioc_count < sizeof(struct bnxe_nvram_data)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, pIoctl->ioc_count) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeReadNvm(pUM, (struct bnxe_nvram_data *)pMblk->b_cont->b_rptr)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; case SIOCBNXENVRM: if ((pIoctl->ioc_count < sizeof(struct bnxe_nvram_data)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, pIoctl->ioc_count) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeWriteNvm(pUM, (struct bnxe_nvram_data *)pMblk->b_cont->b_rptr)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; case GIOCBNXEPCI: if ((pIoctl->ioc_count != sizeof(struct bnxe_reg_data)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, sizeof(struct bnxe_reg_data)) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeReadPciCfg(pUM, (struct bnxe_reg_data *)pMblk->b_cont->b_rptr)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; case GIOCBNXESTATS: /* min size = sizeof(op) in b10_stats_show_data_t */ if ((pIoctl->ioc_count < sizeof(u32_t)) || (pMblk->b_cont == NULL) || (pMblk->b_cont->b_rptr == NULL) || (miocpullup(pMblk, pIoctl->ioc_count) < 0)) { miocnak(pQ, pMblk, 0, EINVAL); break; } if (!BnxeStatsShow(pUM, (b10_stats_show_data_t *)pMblk->b_cont->b_rptr, pIoctl->ioc_count)) { miocnak(pQ, pMblk, 0, EINVAL); } else { miocack(pQ, pMblk, pIoctl->ioc_count, 0); } break; default: miocnak(pQ, pMblk, 0, EINVAL); break; } BNXE_LOCK_EXIT_GLD(pUM); } #ifdef BNXE_RINGS #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) static mblk_t * BnxeRxRingPoll(void * ringHandle, int numBytes, int numPkts) #else static mblk_t * BnxeRxRingPoll(void * ringHandle, int numBytes) #endif { RxQueue * pRxQ = (RxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pRxQ->pUM; u32_t idx = pRxQ->idx; mblk_t * pMblk = NULL; boolean_t pktsRxed = 0; boolean_t pktsTxed = 0; #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) _NOTE(ARGUNUSED(numPkts)) #endif if (numBytes <= 0) { return NULL; } if (pRxQ->inPollMode == B_FALSE) { BnxeLogWarn(pUM, "Polling on ring %d when NOT in poll mode!", idx); return NULL; } BNXE_LOCK_ENTER_INTR(pUM, idx); pRxQ->pollCnt++; BnxePollRxRing(pUM, idx, &pktsRxed, &pktsTxed); if (pktsTxed) BnxeTxRingProcess(pUM, idx); if (pktsRxed) pMblk = BnxeRxRingProcess(pUM, idx, TRUE, numBytes); /* * This is here for the off chance that all rings are in polling * mode and the default interrupt hasn't fired recently to handle * the sq. */ lm_sq_post_pending(&pUM->lm_dev); BNXE_LOCK_EXIT_INTR(pUM, idx); return pMblk; } static int BnxeRxRingStart(mac_ring_driver_t ringHandle #if defined(__S11) || defined(__S12) , uint64_t genNumber #endif ) { RxQueue * pRxQ = (RxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pRxQ->pUM; u32_t idx = pRxQ->idx; BnxeLogDbg(pUM, "Starting Rx Ring %d", idx); BNXE_LOCK_ENTER_RX(pUM, idx); #if defined(__S11) || defined(__S12) pRxQ->genNumber = genNumber; #endif pRxQ->inPollMode = B_FALSE; pRxQ->intrDisableCnt = 0; pRxQ->intrEnableCnt = 0; pRxQ->pollCnt = 0; BNXE_LOCK_EXIT_RX(pUM, idx); return 0; } #if defined(__S11) || defined(__S12) static int BnxeRingStat(mac_ring_driver_t ringHandle, uint_t stat, uint64_t * val) { RxQueue * pRxQ = (RxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pRxQ->pUM; switch (stat) { case MAC_STAT_OERRORS: case MAC_STAT_OBYTES: case MAC_STAT_OPACKETS: case MAC_STAT_IERRORS: case MAC_STAT_RBYTES: /* MAC_STAT_IBYTES */ case MAC_STAT_IPACKETS: default: return ENOTSUP; } return 0; } #endif /* __S11 or __S12 */ #if defined(__S11) || defined(__S12) static int BnxeRxRingIntrEnable(mac_ring_driver_t ringHandle) #else static int BnxeRxRingIntrEnable(mac_intr_handle_t ringHandle) #endif { RxQueue * pRxQ = (RxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pRxQ->pUM; BnxeLogDbg(pUM, "Enabling Interrupt for Rx Ring %d", pRxQ->idx); /* polling not allowed on LM_NON_RSS_SB when overlapped with FCoE */ if ((pRxQ->idx == LM_NON_RSS_SB(&pUM->lm_dev)) && CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE) && (pUM->rssIntr.intrCount == LM_MAX_RSS_CHAINS(&pUM->lm_dev))) { return 0; /* ok, already enabled */ } BnxeIntrIguSbEnable(pUM, pRxQ->idx, B_FALSE); return 0; } #if defined(__S11) || defined(__S12) static int BnxeRxRingIntrDisable(mac_ring_driver_t ringHandle) #else static int BnxeRxRingIntrDisable(mac_intr_handle_t ringHandle) #endif { RxQueue * pRxQ = (RxQueue *)ringHandle; um_device_t * pUM = (um_device_t *)pRxQ->pUM; BnxeLogDbg(pUM, "Disabling Interrupt for Rx Ring %d", pRxQ->idx); /* polling not allowed on LM_NON_RSS_SB when overlapped with FCoE */ if ((pRxQ->idx == LM_NON_RSS_SB(&pUM->lm_dev)) && CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE) && (pUM->rssIntr.intrCount == LM_MAX_RSS_CHAINS(&pUM->lm_dev))) { return -1; /* NO, keep enabled! */ } BnxeIntrIguSbDisable(pUM, pRxQ->idx, B_FALSE); return 0; } /* callback function for MAC layer to register rings */ static void BnxeFillRing(void * arg, mac_ring_type_t ringType, const int ringGroupIndex, const int ringIndex, mac_ring_info_t * pRingInfo, mac_ring_handle_t ringHandle) { um_device_t * pUM = (um_device_t *)arg; RxQueue * pRxQ; TxQueue * pTxQ; switch (ringType) { case MAC_RING_TYPE_RX: BnxeLogInfo(pUM, "Initializing Rx Ring %d (Ring Group %d)", ringIndex, ringGroupIndex); ASSERT(ringGroupIndex == 0); ASSERT(ringIndex < pUM->devParams.numRings); pRxQ = &pUM->rxq[ringIndex]; pRxQ->ringHandle = ringHandle; pRingInfo->mri_driver = (mac_ring_driver_t)pRxQ; pRingInfo->mri_start = BnxeRxRingStart; pRingInfo->mri_stop = NULL; #if defined(__S11) || defined(__S12) pRingInfo->mri_stat = BnxeRingStat; #endif pRingInfo->mri_poll = BnxeRxRingPoll; #if !(defined(__S11) || defined(__S12)) pRingInfo->mri_intr.mi_handle = (mac_intr_handle_t)pRxQ; #endif pRingInfo->mri_intr.mi_enable = (mac_intr_enable_t)BnxeRxRingIntrEnable; pRingInfo->mri_intr.mi_disable = (mac_intr_disable_t)BnxeRxRingIntrDisable; break; case MAC_RING_TYPE_TX: BnxeLogInfo(pUM, "Initializing Tx Ring %d (Ring Group %d)", ringIndex, ringGroupIndex); ASSERT(ringGroupIndex == 0); ASSERT(ringIndex < pUM->devParams.numRings); pTxQ = &pUM->txq[ringIndex]; pTxQ->ringHandle = ringHandle; pRingInfo->mri_driver = (mac_ring_driver_t)pTxQ; pRingInfo->mri_start = NULL; pRingInfo->mri_stop = NULL; #if defined(__S11) || defined(__S12) pRingInfo->mri_stat = BnxeRingStat; #endif pRingInfo->mri_tx = (mac_ring_send_t)BnxeTxRingSend; break; default: break; } } /* callback function for MAC layer to register groups */ static void BnxeFillGroup(void * arg, mac_ring_type_t ringType, const int ringGroupIndex, mac_group_info_t * pGroupInfo, mac_group_handle_t groupHandle) { um_device_t * pUM = (um_device_t *)arg; RxQueueGroup * pRxQGroup; switch (ringType) { case MAC_RING_TYPE_RX: BnxeLogInfo(pUM, "Initializing Rx Group %d", ringGroupIndex); pRxQGroup = &pUM->rxqGroup[ringGroupIndex]; pRxQGroup->groupHandle = groupHandle; pGroupInfo->mgi_driver = (mac_group_driver_t)pRxQGroup; pGroupInfo->mgi_start = NULL; pGroupInfo->mgi_stop = NULL; pGroupInfo->mgi_addmac = BnxeRxRingGroupAddMac; pGroupInfo->mgi_remmac = BnxeRxRingGroupRemMac; pGroupInfo->mgi_count = (pUM->devParams.numRings / USER_OPTION_RX_RING_GROUPS_DEFAULT); #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) pGroupInfo->mgi_flags = MAC_GROUP_DEFAULT; #endif break; case MAC_RING_TYPE_TX: default: break; } } #endif /* BNXE_RINGS */ static boolean_t BnxeMacGetCapability(void * pArg, mac_capab_t capability, void * pCapabilityData) { um_device_t * pUM = (um_device_t *)pArg; mac_capab_lso_t * pCapLSO; mac_capab_rings_t * pCapRings; switch (capability) { case MAC_CAPAB_HCKSUM: *((u32_t *)pCapabilityData) = 0; if (pUM->devParams.enabled_oflds & (LM_OFFLOAD_TX_IP_CKSUM | LM_OFFLOAD_RX_IP_CKSUM)) { *((u32_t *)pCapabilityData) |= HCKSUM_IPHDRCKSUM; } if (pUM->devParams.enabled_oflds & (LM_OFFLOAD_TX_TCP_CKSUM | LM_OFFLOAD_TX_UDP_CKSUM | LM_OFFLOAD_RX_TCP_CKSUM | LM_OFFLOAD_RX_UDP_CKSUM)) { *((u32_t *)pCapabilityData) |= HCKSUM_INET_PARTIAL; } break; case MAC_CAPAB_LSO: pCapLSO = (mac_capab_lso_t *)pCapabilityData; if (pUM->devParams.lsoEnable) { pCapLSO->lso_flags = LSO_TX_BASIC_TCP_IPV4; pCapLSO->lso_basic_tcp_ipv4.lso_max = BNXE_LSO_MAXLEN; break; } return B_FALSE; #ifdef BNXE_RINGS case MAC_CAPAB_RINGS: if (!pUM->devParams.numRings) { return B_FALSE; } pCapRings = (mac_capab_rings_t *)pCapabilityData; #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) pCapRings->mr_version = MAC_RINGS_VERSION_1; pCapRings->mr_flags = MAC_RINGS_FLAGS_NONE; #endif pCapRings->mr_group_type = MAC_GROUP_TYPE_STATIC; pCapRings->mr_rnum = pUM->devParams.numRings; pCapRings->mr_rget = BnxeFillRing; pCapRings->mr_gaddring = NULL; pCapRings->mr_gremring = NULL; #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) pCapRings->mr_ggetringtc = NULL; #endif switch (pCapRings->mr_type) { case MAC_RING_TYPE_RX: pCapRings->mr_gnum = USER_OPTION_RX_RING_GROUPS_DEFAULT; pCapRings->mr_gget = BnxeFillGroup; break; case MAC_RING_TYPE_TX: #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) pCapRings->mr_gnum = 1; #else pCapRings->mr_gnum = 0; #endif pCapRings->mr_gget = NULL; break; default: return B_FALSE; } break; #endif /* BNXE_RINGS */ #if !(defined(__S11) || defined(__S12)) case MAC_CAPAB_POLL: /* * There's nothing for us to fill in, simply returning B_TRUE stating * that we support polling is sufficient. */ break; #endif /* not __S11 or __S12 */ #if defined(ILLUMOS) case MAC_CAPAB_TRANSCEIVER: return bnxe_fill_transceiver(pUM, pCapabilityData); #endif default: return B_FALSE; } return B_TRUE; } #ifdef MC_SETPROP static int BnxeSetPrivateProperty(um_device_t * pUM, const char * pr_name, uint_t pr_valsize, const void * pr_val) { int err = 0; long result; if (strcmp(pr_name, "_en_2500fdx_cap") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->hwinit.lnkcfg.param_2500fdx = (uint32_t)result; pUM->curcfg.lnkcfg.param_2500fdx = (uint32_t)result; if (pUM->plumbed) BnxeUpdatePhy(pUM); } else if (strcmp(pr_name, "_en_txpause_cap") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->hwinit.lnkcfg.param_txpause = (uint32_t)result; pUM->curcfg.lnkcfg.param_txpause = (uint32_t)result; if (pUM->plumbed) BnxeUpdatePhy(pUM); } else if (strcmp(pr_name, "_en_rxpause_cap") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->hwinit.lnkcfg.param_rxpause = (uint32_t)result; pUM->curcfg.lnkcfg.param_rxpause = (uint32_t)result; if (pUM->plumbed) BnxeUpdatePhy(pUM); } else if (strcmp(pr_name, "_autoneg_flow") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->hwinit.flow_autoneg = (uint32_t)result; pUM->curcfg.flow_autoneg = (uint32_t)result; if (pUM->plumbed) BnxeUpdatePhy(pUM); } else if (strcmp(pr_name, "_checksum") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } switch (result) { case USER_OPTION_CKSUM_NONE: pUM->devParams.enabled_oflds = LM_OFFLOAD_NONE; break; case USER_OPTION_CKSUM_L3: pUM->devParams.enabled_oflds = (LM_OFFLOAD_TX_IP_CKSUM | LM_OFFLOAD_RX_IP_CKSUM); break; case USER_OPTION_CKSUM_L3_L4: pUM->devParams.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; default: return EINVAL; } pUM->devParams.checksum = (uint32_t)result; } else if (strcmp(pr_name, "_tx_ring_policy") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } switch (result) { case BNXE_ROUTE_RING_NONE: case BNXE_ROUTE_RING_TCPUDP: case BNXE_ROUTE_RING_DEST_MAC: case BNXE_ROUTE_RING_MSG_PRIO: break; default: return EINVAL; } pUM->devParams.routeTxRingPolicy = (uint32_t)result; } else if (strcmp(pr_name, "_num_rings") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_NUM_RINGS_MIN) || (result > USER_OPTION_NUM_RINGS_MAX)) { return EINVAL; } pUM->devParams.numRings = (uint32_t)result; } else if (strcmp(pr_name, "_rx_descs") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_BDS_MIN) || (result > USER_OPTION_BDS_MAX)) { return EINVAL; } pUM->devParams.numRxDesc[LM_CLI_IDX_NDIS] = (uint32_t)result; } else if (strcmp(pr_name, "_rx_free_reclaim") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_BDS_MIN) || (result > USER_OPTION_BDS_MAX)) { return EINVAL; } pUM->devParams.maxRxFree = (uint32_t)result; } else if (strcmp(pr_name, "_tx_descs") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_BDS_MIN) || (result > USER_OPTION_BDS_MAX)) { return EINVAL; } pUM->devParams.numTxDesc[LM_CLI_IDX_NDIS] = (uint32_t)result; } else if (strcmp(pr_name, "_tx_free_reclaim") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_BDS_MIN) || (result > USER_OPTION_BDS_MAX)) { return EINVAL; } pUM->devParams.maxTxFree = (uint32_t)result; } else if (strcmp(pr_name, "_rx_copy_threshold") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } pUM->devParams.rxCopyThreshold = (uint32_t)result; } else if (strcmp(pr_name, "_tx_copy_threshold") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } pUM->devParams.txCopyThreshold = (uint32_t)result; } else if (strcmp(pr_name, "_interrupt_coalesce") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.intrCoalesce = (uint32_t)result; } else if (strcmp(pr_name, "_rx_interrupt_coalesce_usec") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_INTR_COALESCE_MIN) || (result < USER_OPTION_INTR_COALESCE_MAX)) { return EINVAL; } pUM->devParams.intrRxPerSec = (uint32_t)(1000000 / result); } else if (strcmp(pr_name, "_tx_interrupt_coalesce_usec") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result < USER_OPTION_INTR_COALESCE_MIN) || (result < USER_OPTION_INTR_COALESCE_MAX)) { return EINVAL; } pUM->devParams.intrTxPerSec = (uint32_t)(1000000 / result); } else if (strcmp(pr_name, "_disable_msix") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.disableMsix = (uint32_t)result; } else if (strcmp(pr_name, "_l2_fw_flow_ctrl") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.l2_fw_flow_ctrl = (uint32_t)result; } else if (strcmp(pr_name, "_autogreeen_enable") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.autogreeenEnable = (uint32_t)result; if (pUM->plumbed) BnxeUpdatePhy(pUM); } else if (strcmp(pr_name, "_lso_enable") == 0) { if (pUM->plumbed) { return EBUSY; } if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.lsoEnable = (uint32_t)result; } else if (strcmp(pr_name, "_log_enable") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.logEnable = (uint32_t)result; } else if (strcmp(pr_name, "_fcoe_enable") == 0) { if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) { return EINVAL; } if ((result > 1) || (result < 0)) { return EINVAL; } pUM->devParams.fcoeEnable = (uint32_t)result; if (BNXE_FCOE(pUM)) { BnxeFcoeStartStop(pUM); } } else { err = ENOTSUP; } return err; } static int BnxeMacSetProperty(void * barg, const char * pr_name, mac_prop_id_t pr_num, uint_t pr_valsize, const void * pr_val) { um_device_t * pUM = barg; boolean_t reprogram = B_FALSE; boolean_t rxpause; boolean_t txpause; uint32_t mtu; link_flowctrl_t fl; int err = 0; BNXE_LOCK_ENTER_GLD(pUM); switch (pr_num) { /* read-only props */ case MAC_PROP_STATUS: case MAC_PROP_SPEED: case MAC_PROP_DUPLEX: case MAC_PROP_MEDIA: case MAC_PROP_ADV_10GFDX_CAP: case MAC_PROP_ADV_1000FDX_CAP: case MAC_PROP_ADV_1000HDX_CAP: case MAC_PROP_ADV_100FDX_CAP: case MAC_PROP_ADV_100HDX_CAP: case MAC_PROP_ADV_10FDX_CAP: case MAC_PROP_ADV_10HDX_CAP: case MAC_PROP_ADV_100T4_CAP: case MAC_PROP_EN_1000HDX_CAP: case MAC_PROP_EN_100T4_CAP: default: err = ENOTSUP; break; case MAC_PROP_EN_10GFDX_CAP: pUM->hwinit.lnkcfg.param_10000fdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_10000fdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_EN_1000FDX_CAP: pUM->hwinit.lnkcfg.param_1000fdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_1000fdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_EN_100FDX_CAP: pUM->hwinit.lnkcfg.param_100fdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_100fdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_EN_100HDX_CAP: pUM->hwinit.lnkcfg.param_100hdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_100hdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_EN_10FDX_CAP: pUM->hwinit.lnkcfg.param_10fdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_10fdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_EN_10HDX_CAP: pUM->hwinit.lnkcfg.param_10hdx = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.param_10hdx = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_AUTONEG: pUM->hwinit.lnkcfg.link_autoneg = *(uint8_t *)pr_val; pUM->curcfg.lnkcfg.link_autoneg = *(uint8_t *)pr_val; reprogram = B_TRUE; break; case MAC_PROP_FLOWCTRL: bcopy(pr_val, &fl, sizeof(fl)); switch (fl) { case LINK_FLOWCTRL_NONE: rxpause = B_FALSE; txpause = B_FALSE; break; case LINK_FLOWCTRL_RX: rxpause = B_TRUE; txpause = B_FALSE; break; case LINK_FLOWCTRL_TX: rxpause = B_FALSE; txpause = B_TRUE; break; case LINK_FLOWCTRL_BI: rxpause = B_TRUE; txpause = B_TRUE; break; default: err = ENOTSUP; break; } if (err == 0) { pUM->hwinit.lnkcfg.param_rxpause = rxpause; pUM->hwinit.lnkcfg.param_txpause = txpause; pUM->curcfg.lnkcfg.param_rxpause = rxpause; pUM->curcfg.lnkcfg.param_txpause = txpause; reprogram = B_TRUE; } break; case MAC_PROP_MTU: if (pUM->plumbed) { err = EBUSY; break; } bcopy(pr_val, &mtu, sizeof (mtu)); if ((mtu < USER_OPTION_MTU_MIN) || (mtu > USER_OPTION_MTU_MAX)) { err = EINVAL; break; } if (pUM->devParams.mtu[LM_CLI_IDX_NDIS] == mtu) { break; } pUM->devParams.mtu[LM_CLI_IDX_NDIS] = mtu; err = mac_maxsdu_update(pUM->pMac, pUM->devParams.mtu[LM_CLI_IDX_NDIS]); pUM->lm_dev.params.mtu[LM_CLI_IDX_NDIS] = pUM->devParams.mtu[LM_CLI_IDX_NDIS]; break; case MAC_PROP_PRIVATE: err = BnxeSetPrivateProperty(pUM, pr_name, pr_valsize, pr_val); break; } if (!err && reprogram) { if (pUM->plumbed) BnxeUpdatePhy(pUM); } BNXE_LOCK_EXIT_GLD(pUM); return err; } #endif /* MC_SETPROP */ #ifdef MC_GETPROP static int BnxeGetPrivateProperty(um_device_t * pUM, const char * pr_name, uint_t pr_valsize, void * pr_val) { BnxeLinkCfg * lnk_cfg = &pUM->curcfg.lnkcfg; BnxeLinkCfg * hw_cfg = &pUM->hwinit.lnkcfg; int value; int err = 0; if (strcmp(pr_name, "_adv_2500fdx_cap") == 0) { value = lnk_cfg->param_2500fdx; } else if (strcmp(pr_name, "_en_2500fdx_cap") == 0) { value = hw_cfg->param_2500fdx; } else if (strcmp(pr_name, "_adv_txpause_cap") == 0) { value = lnk_cfg->param_txpause; } else if (strcmp(pr_name, "_en_txpause_cap") == 0) { value = hw_cfg->param_txpause; } else if (strcmp(pr_name, "_txpause") == 0) { value = pUM->props.link_txpause; } else if (strcmp(pr_name, "_adv_rxpause_cap") == 0) { value = lnk_cfg->param_rxpause; } else if (strcmp(pr_name, "_en_rxpause_cap") == 0) { value = hw_cfg->param_rxpause; } else if (strcmp(pr_name, "_rxpause") == 0) { value = pUM->props.link_rxpause; } else if (strcmp(pr_name, "_autoneg_flow") == 0) { value = pUM->hwinit.flow_autoneg; } else if (strcmp(pr_name, "_checksum") == 0) { value = pUM->devParams.checksum; } else if (strcmp(pr_name, "_tx_ring_policy") == 0) { value = pUM->devParams.routeTxRingPolicy; } else if (strcmp(pr_name, "_num_rings") == 0) { value = pUM->devParams.numRings; } else if (strcmp(pr_name, "_rx_descs") == 0) { value = pUM->devParams.numRxDesc[LM_CLI_IDX_NDIS]; } else if (strcmp(pr_name, "_rx_free_reclaim") == 0) { value = pUM->devParams.maxRxFree; } else if (strcmp(pr_name, "_tx_descs") == 0) { value = pUM->devParams.numTxDesc[LM_CLI_IDX_NDIS]; } else if (strcmp(pr_name, "_tx_free_reclaim") == 0) { value = pUM->devParams.maxTxFree; } else if (strcmp(pr_name, "_rx_copy_threshold") == 0) { value = pUM->devParams.rxCopyThreshold; } else if (strcmp(pr_name, "_tx_copy_threshold") == 0) { value = pUM->devParams.txCopyThreshold; } else if (strcmp(pr_name, "_interrupt_coalesce") == 0) { value = pUM->devParams.intrCoalesce; } else if (strcmp(pr_name, "_rx_interrupt_coalesce_usec") == 0) { value = pUM->devParams.intrRxPerSec; } else if (strcmp(pr_name, "_tx_interrupt_coalesce_usec") == 0) { value = pUM->devParams.intrTxPerSec; } else if (strcmp(pr_name, "_disable_msix") == 0) { value = pUM->devParams.disableMsix; } else if (strcmp(pr_name, "_l2_fw_flow_ctrl") == 0) { value = pUM->devParams.l2_fw_flow_ctrl; } else if (strcmp(pr_name, "_autogreeen_enable") == 0) { value = pUM->devParams.autogreeenEnable; } else if (strcmp(pr_name, "_lso_enable") == 0) { value = pUM->devParams.lsoEnable; } else if (strcmp(pr_name, "_log_enable") == 0) { value = pUM->devParams.logEnable; } else if (strcmp(pr_name, "_fcoe_enable") == 0) { value = pUM->devParams.fcoeEnable; } else { err = ENOTSUP; } if (!err) { (void)snprintf(pr_val, pr_valsize, "%d", value); } return err; } static int BnxeMacGetProperty(void * barg, const char * pr_name, mac_prop_id_t pr_num, uint_t pr_valsize, void * pr_val) { um_device_t * pUM = barg; link_flowctrl_t link_flowctrl; link_state_t link_state; link_duplex_t link_duplex; uint64_t link_speed; mac_ether_media_t link_media; BnxeLinkCfg * lnk_cfg = &pUM->curcfg.lnkcfg; BnxeLinkCfg * hw_cfg = &pUM->hwinit.lnkcfg; switch (pr_num) { case MAC_PROP_MTU: ASSERT(pr_valsize >= sizeof(u32_t)); bcopy(&pUM->devParams.mtu[LM_CLI_IDX_NDIS], pr_val, sizeof(u32_t)); break; case MAC_PROP_DUPLEX: ASSERT(pr_valsize >= sizeof(link_duplex_t)); link_duplex = pUM->props.link_duplex ? LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; bcopy(&link_duplex, pr_val, sizeof(link_duplex_t)); break; case MAC_PROP_SPEED: ASSERT(pr_valsize >= sizeof(link_speed)); link_speed = (pUM->props.link_speed * 1000000ULL); bcopy(&link_speed, pr_val, sizeof(link_speed)); break; case MAC_PROP_STATUS: ASSERT(pr_valsize >= sizeof(link_state_t)); link_state = pUM->props.link_speed ? LINK_STATE_UP : LINK_STATE_DOWN; bcopy(&link_state, pr_val, sizeof(link_state_t)); break; case MAC_PROP_MEDIA: ASSERT(pr_valsize >= sizeof(mac_ether_media_t)); link_media = bnxe_phy_to_media(pUM); bcopy(&link_media, pr_val, sizeof(mac_ether_media_t)); break; case MAC_PROP_AUTONEG: *(uint8_t *)pr_val = lnk_cfg->link_autoneg; break; case MAC_PROP_FLOWCTRL: ASSERT(pr_valsize >= sizeof(link_flowctrl_t)); if (!lnk_cfg->param_rxpause && !lnk_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_NONE; } if (lnk_cfg->param_rxpause && !lnk_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_RX; } if (!lnk_cfg->param_rxpause && lnk_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_TX; } if (lnk_cfg->param_rxpause && lnk_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_BI; } bcopy(&link_flowctrl, pr_val, sizeof(link_flowctrl_t)); break; case MAC_PROP_ADV_10GFDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_10000fdx; break; case MAC_PROP_EN_10GFDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_10000fdx; break; case MAC_PROP_ADV_1000FDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_1000fdx; break; case MAC_PROP_EN_1000FDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_1000fdx; break; case MAC_PROP_ADV_1000HDX_CAP: case MAC_PROP_EN_1000HDX_CAP: *(uint8_t *)pr_val = 0; break; case MAC_PROP_ADV_100FDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_100fdx; break; case MAC_PROP_EN_100FDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_100fdx; break; case MAC_PROP_ADV_100HDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_100hdx; break; case MAC_PROP_EN_100HDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_100hdx; break; case MAC_PROP_ADV_100T4_CAP: case MAC_PROP_EN_100T4_CAP: *(uint8_t *)pr_val = 0; break; case MAC_PROP_ADV_10FDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_10fdx; break; case MAC_PROP_EN_10FDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_10fdx; break; case MAC_PROP_ADV_10HDX_CAP: *(uint8_t *)pr_val = lnk_cfg->param_10hdx; break; case MAC_PROP_EN_10HDX_CAP: *(uint8_t *)pr_val = hw_cfg->param_10hdx; break; case MAC_PROP_PRIVATE: return BnxeGetPrivateProperty(pUM, pr_name, pr_valsize, pr_val); default: return ENOTSUP; } return 0; } #endif /* MC_GETPROP */ #ifdef MC_PROPINFO static void BnxeMacPrivatePropertyInfo(um_device_t * pUM, const char * pr_name, mac_prop_info_handle_t prh) { char valstr[64]; BnxeLinkCfg * default_cfg = &bnxeLinkCfg; int default_val; bzero(valstr, sizeof (valstr)); if ((strcmp(pr_name, "_adv_2500fdx_cap") == 0) || (strcmp(pr_name, "_adv_txpause_cap") == 0) || (strcmp(pr_name, "_txpause") == 0) || (strcmp(pr_name, "_adv_rxpause_cap") == 0) || (strcmp(pr_name, "_rxpause") == 0) || (strcmp(pr_name, "_checksum") == 0) || (strcmp(pr_name, "_num_rings") == 0) || (strcmp(pr_name, "_rx_descs") == 0) || (strcmp(pr_name, "_tx_descs") == 0) || (strcmp(pr_name, "_interrupt_coalesce") == 0) || (strcmp(pr_name, "_rx_interrupt_coalesce_usec") == 0) || (strcmp(pr_name, "_tx_interrupt_coalesce_usec") == 0) || (strcmp(pr_name, "_disable_msix") == 0) || (strcmp(pr_name, "_l2_fw_flow_ctrl") == 0) || (strcmp(pr_name, "_lso_enable") == 0)) { mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); return; } if (strcmp(pr_name, "_autoneg_flow") == 0) { default_val = B_TRUE; } else if (strcmp(pr_name, "_tx_ring_policy") == 0) { default_val = BNXE_ROUTE_RING_TCPUDP; } else if (strcmp(pr_name, "_rx_free_reclaim") == 0) { default_val = USER_OPTION_RX_MAX_FREE_DEFAULT; } else if (strcmp(pr_name, "_tx_free_reclaim") == 0) { default_val = USER_OPTION_TX_MAX_FREE_DEFAULT; } else if (strcmp(pr_name, "_rx_copy_threshold") == 0) { default_val = USER_OPTION_RX_DCOPY_THRESH_DEFAULT; } else if (strcmp(pr_name, "_tx_copy_threshold") == 0) { default_val = USER_OPTION_TX_DCOPY_THRESH_DEFAULT; } else if (strcmp(pr_name, "_autogreeen_enable") == 0) { default_val = B_TRUE; } else if (strcmp(pr_name, "_log_enable") == 0) { default_val = B_TRUE; } else if (strcmp(pr_name, "_fcoe_enable") == 0) { default_val = B_TRUE; } else { return; } snprintf(valstr, sizeof (valstr), "%d", default_val); mac_prop_info_set_default_str(prh, valstr); } static void BnxeMacPropertyInfo(void * barg, const char * pr_name, mac_prop_id_t pr_num, mac_prop_info_handle_t prh) { um_device_t * pUM = barg; link_flowctrl_t link_flowctrl; BnxeLinkCfg * default_cfg = &bnxeLinkCfg; switch (pr_num) { case MAC_PROP_STATUS: case MAC_PROP_SPEED: case MAC_PROP_DUPLEX: case MAC_PROP_ADV_10GFDX_CAP: case MAC_PROP_ADV_1000FDX_CAP: case MAC_PROP_ADV_1000HDX_CAP: case MAC_PROP_ADV_100FDX_CAP: case MAC_PROP_ADV_100HDX_CAP: case MAC_PROP_ADV_100T4_CAP: case MAC_PROP_ADV_10FDX_CAP: case MAC_PROP_ADV_10HDX_CAP: case MAC_PROP_EN_1000HDX_CAP: case MAC_PROP_EN_100T4_CAP: mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); break; case MAC_PROP_EN_10GFDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_10000fdx); break; case MAC_PROP_EN_1000FDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_1000fdx); break; case MAC_PROP_EN_100FDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_100fdx); break; case MAC_PROP_EN_100HDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_100hdx); break; case MAC_PROP_EN_10FDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_10fdx); break; case MAC_PROP_EN_10HDX_CAP: mac_prop_info_set_default_uint8(prh, default_cfg->param_10hdx); break; case MAC_PROP_MTU: mac_prop_info_set_range_uint32(prh, USER_OPTION_MTU_MIN, USER_OPTION_MTU_MAX); break; case MAC_PROP_AUTONEG: mac_prop_info_set_default_uint8(prh, default_cfg->link_autoneg); break; case MAC_PROP_FLOWCTRL: if (!default_cfg->param_rxpause && !default_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_NONE; } if (default_cfg->param_rxpause && !default_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_RX; } if (!default_cfg->param_rxpause && default_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_TX; } if (default_cfg->param_rxpause && default_cfg->param_txpause) { link_flowctrl = LINK_FLOWCTRL_BI; } mac_prop_info_set_default_link_flowctrl(prh, link_flowctrl); break; case MAC_PROP_PRIVATE: BnxeMacPrivatePropertyInfo(pUM, pr_name, prh); break; } } #endif /* MC_PROPINFO */ static mac_callbacks_t bnxe_callbacks = { ( MC_IOCTL #ifdef MC_RESOURCES | MC_RESOURCES #endif #ifdef MC_SETPROP | MC_SETPROP #endif #ifdef MC_GETPROP | MC_GETPROP #endif #ifdef MC_PROPINFO | MC_PROPINFO #endif | MC_GETCAPAB ), BnxeMacStats, BnxeMacStart, BnxeMacStop, BnxeMacPromiscuous, BnxeMacMulticast, NULL, BnxeMacTx, #ifdef MC_RESOURCES BnxeMacResources, #else NULL, #endif BnxeMacIoctl, BnxeMacGetCapability, #ifdef MC_OPEN NULL, NULL, #endif #ifdef MC_SETPROP BnxeMacSetProperty, #endif #ifdef MC_GETPROP BnxeMacGetProperty, #endif #ifdef MC_PROPINFO BnxeMacPropertyInfo #endif }; boolean_t BnxeGldInit(um_device_t * pUM) { mac_register_t * pMac; int rc; atomic_swap_32(&pUM->plumbed, B_FALSE); if ((pMac = mac_alloc(MAC_VERSION)) == NULL) { BnxeLogWarn(pUM, "Failed to allocate GLD MAC memory"); return B_FALSE; } pMac->m_driver = pUM; pMac->m_dip = pUM->pDev; pMac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; pMac->m_callbacks = &bnxe_callbacks; pMac->m_min_sdu = 0; pMac->m_max_sdu = pUM->devParams.mtu[LM_CLI_IDX_NDIS]; pMac->m_src_addr = &(pUM->lm_dev.params.mac_addr[0]); #ifdef MC_OPEN pMac->m_margin = VLAN_TAGSZ; #endif #ifdef MC_SETPROP pMac->m_priv_props = bnxeLink_priv_props; #endif #if (defined(__S11) || defined(__S12)) && !defined(ILLUMOS) bnxe_callbacks.mc_unicst = (!pUM->devParams.numRings) ? BnxeMacUnicast : NULL; #else bnxe_callbacks.mc_unicst = BnxeMacUnicast; #endif rc = mac_register(pMac, &pUM->pMac); mac_free(pMac); if (rc != 0) { BnxeLogWarn(pUM, "Failed to register with GLD (%d)", rc); return B_FALSE; } /* Always report the initial link state as unknown. */ mac_link_update(pUM->pMac, LINK_STATE_UNKNOWN); return B_TRUE; } boolean_t BnxeGldFini(um_device_t * pUM) { int cnt; if (pUM->plumbed) { BnxeLogWarn(pUM, "Detaching device from GLD that is started!"); return B_FALSE; } /* We must not detach until all packets held by stack are retrieved. */ if (!BnxeWaitForPacketsFromClient(pUM, LM_CLI_IDX_NDIS)) { return B_FALSE; } if (pUM->pMac) { if (mac_unregister(pUM->pMac)) { BnxeLogWarn(pUM, "Failed to unregister with the GLD"); return B_FALSE; } } return B_TRUE; } void BnxeGldLink(um_device_t * pUM, link_state_t state) { mac_link_update(pUM->pMac, state); }