/* * Set the promiscuity of the device. */ int igb_m_promisc(void *arg, boolean_t on) { igb_t *igb = (igb_t *)arg; uint32_t reg_val; mutex_enter(&igb->gen_lock); if (igb->igb_state & IGB_SUSPENDED) { mutex_exit(&igb->gen_lock); return (ECANCELED); } reg_val = E1000_READ_REG(&igb->hw, E1000_RCTL); if (on) reg_val |= (E1000_RCTL_UPE | E1000_RCTL_MPE); else reg_val &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE)); E1000_WRITE_REG(&igb->hw, E1000_RCTL, reg_val); mutex_exit(&igb->gen_lock); if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) { ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); return (EIO); } return (0); }
/* * Update driver private statistics. */ static int igb_update_stats(kstat_t *ks, int rw) { igb_t *igb; struct e1000_hw *hw; igb_stat_t *igb_ks; uint32_t val_low, val_high; #ifdef IGB_DEBUG int i; #endif if (rw == KSTAT_WRITE) return (EACCES); igb = (igb_t *)ks->ks_private; igb_ks = (igb_stat_t *)ks->ks_data; hw = &igb->hw; mutex_enter(&igb->gen_lock); /* * Basic information. */ igb_ks->reset_count.value.ui64 = igb->reset_count; igb_ks->dout_sync.value.ui64 = igb->dout_sync; #ifdef IGB_DEBUG igb_ks->rx_frame_error.value.ui64 = 0; igb_ks->rx_cksum_error.value.ui64 = 0; igb_ks->rx_exceed_pkt.value.ui64 = 0; for (i = 0; i < igb->num_rx_rings; i++) { igb_ks->rx_frame_error.value.ui64 += igb->rx_rings[i].stat_frame_error; igb_ks->rx_cksum_error.value.ui64 += igb->rx_rings[i].stat_cksum_error; igb_ks->rx_exceed_pkt.value.ui64 += igb->rx_rings[i].stat_exceed_pkt; } igb_ks->tx_overload.value.ui64 = 0; igb_ks->tx_fail_no_tbd.value.ui64 = 0; igb_ks->tx_fail_no_tcb.value.ui64 = 0; igb_ks->tx_fail_dma_bind.value.ui64 = 0; igb_ks->tx_reschedule.value.ui64 = 0; for (i = 0; i < igb->num_tx_rings; i++) { igb_ks->tx_overload.value.ui64 += igb->tx_rings[i].stat_overload; igb_ks->tx_fail_no_tbd.value.ui64 += igb->tx_rings[i].stat_fail_no_tbd; igb_ks->tx_fail_no_tcb.value.ui64 += igb->tx_rings[i].stat_fail_no_tcb; igb_ks->tx_fail_dma_bind.value.ui64 += igb->tx_rings[i].stat_fail_dma_bind; igb_ks->tx_reschedule.value.ui64 += igb->tx_rings[i].stat_reschedule; } /* * Hardware calculated statistics. */ igb_ks->gprc.value.ul += E1000_READ_REG(hw, E1000_GPRC); igb_ks->gptc.value.ul += E1000_READ_REG(hw, E1000_GPTC); igb_ks->prc64.value.ul += E1000_READ_REG(hw, E1000_PRC64); igb_ks->prc127.value.ul += E1000_READ_REG(hw, E1000_PRC127); igb_ks->prc255.value.ul += E1000_READ_REG(hw, E1000_PRC255); igb_ks->prc511.value.ul += E1000_READ_REG(hw, E1000_PRC511); igb_ks->prc1023.value.ul += E1000_READ_REG(hw, E1000_PRC1023); igb_ks->prc1522.value.ul += E1000_READ_REG(hw, E1000_PRC1522); igb_ks->ptc64.value.ul += E1000_READ_REG(hw, E1000_PTC64); igb_ks->ptc127.value.ul += E1000_READ_REG(hw, E1000_PTC127); igb_ks->ptc255.value.ul += E1000_READ_REG(hw, E1000_PTC255); igb_ks->ptc511.value.ul += E1000_READ_REG(hw, E1000_PTC511); igb_ks->ptc1023.value.ul += E1000_READ_REG(hw, E1000_PTC1023); igb_ks->ptc1522.value.ul += E1000_READ_REG(hw, E1000_PTC1522); /* * The 64-bit register will reset whenever the upper * 32 bits are read. So we need to read the lower * 32 bits first, then read the upper 32 bits. */ val_low = E1000_READ_REG(hw, E1000_GORCL); val_high = E1000_READ_REG(hw, E1000_GORCH); igb_ks->gor.value.ui64 += (uint64_t)val_high << 32 | (uint64_t)val_low; val_low = E1000_READ_REG(hw, E1000_GOTCL); val_high = E1000_READ_REG(hw, E1000_GOTCH); igb_ks->got.value.ui64 += (uint64_t)val_high << 32 | (uint64_t)val_low; #endif igb_ks->symerrs.value.ui64 += E1000_READ_REG(hw, E1000_SYMERRS); igb_ks->mpc.value.ui64 += E1000_READ_REG(hw, E1000_MPC); igb_ks->rlec.value.ui64 += E1000_READ_REG(hw, E1000_RLEC); igb_ks->fcruc.value.ui64 += E1000_READ_REG(hw, E1000_FCRUC); igb_ks->rfc.value.ul += E1000_READ_REG(hw, E1000_RFC); igb_ks->tncrs.value.ul += E1000_READ_REG(hw, E1000_TNCRS); igb_ks->tsctc.value.ul += E1000_READ_REG(hw, E1000_TSCTC); igb_ks->tsctfc.value.ul += E1000_READ_REG(hw, E1000_TSCTFC); igb_ks->xonrxc.value.ui64 += E1000_READ_REG(hw, E1000_XONRXC); igb_ks->xontxc.value.ui64 += E1000_READ_REG(hw, E1000_XONTXC); igb_ks->xoffrxc.value.ui64 += E1000_READ_REG(hw, E1000_XOFFRXC); igb_ks->xofftxc.value.ui64 += E1000_READ_REG(hw, E1000_XOFFTXC); mutex_exit(&igb->gen_lock); if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) { ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); return (EIO); } return (0); }
int igb_m_stat(void *arg, uint_t stat, uint64_t *val) { igb_t *igb = (igb_t *)arg; struct e1000_hw *hw = &igb->hw; igb_stat_t *igb_ks; uint32_t low_val, high_val; igb_ks = (igb_stat_t *)igb->igb_ks->ks_data; mutex_enter(&igb->gen_lock); if (igb->igb_state & IGB_SUSPENDED) { mutex_exit(&igb->gen_lock); return (ECANCELED); } switch (stat) { case MAC_STAT_IFSPEED: *val = igb->link_speed * 1000000ull; break; case MAC_STAT_MULTIRCV: igb_ks->mprc.value.ui64 += E1000_READ_REG(hw, E1000_MPRC); *val = igb_ks->mprc.value.ui64; break; case MAC_STAT_BRDCSTRCV: igb_ks->bprc.value.ui64 += E1000_READ_REG(hw, E1000_BPRC); *val = igb_ks->bprc.value.ui64; break; case MAC_STAT_MULTIXMT: igb_ks->mptc.value.ui64 += E1000_READ_REG(hw, E1000_MPTC); *val = igb_ks->mptc.value.ui64; break; case MAC_STAT_BRDCSTXMT: igb_ks->bptc.value.ui64 += E1000_READ_REG(hw, E1000_BPTC); *val = igb_ks->bptc.value.ui64; break; case MAC_STAT_NORCVBUF: igb_ks->rnbc.value.ui64 += E1000_READ_REG(hw, E1000_RNBC); *val = igb_ks->rnbc.value.ui64; break; case MAC_STAT_IERRORS: igb_ks->rxerrc.value.ui64 += E1000_READ_REG(hw, E1000_RXERRC); igb_ks->algnerrc.value.ui64 += E1000_READ_REG(hw, E1000_ALGNERRC); igb_ks->rlec.value.ui64 += E1000_READ_REG(hw, E1000_RLEC); igb_ks->crcerrs.value.ui64 += E1000_READ_REG(hw, E1000_CRCERRS); igb_ks->cexterr.value.ui64 += E1000_READ_REG(hw, E1000_CEXTERR); *val = igb_ks->rxerrc.value.ui64 + igb_ks->algnerrc.value.ui64 + igb_ks->rlec.value.ui64 + igb_ks->crcerrs.value.ui64 + igb_ks->cexterr.value.ui64; break; case MAC_STAT_NOXMTBUF: *val = 0; break; case MAC_STAT_OERRORS: igb_ks->ecol.value.ui64 += E1000_READ_REG(hw, E1000_ECOL); *val = igb_ks->ecol.value.ui64; break; case MAC_STAT_COLLISIONS: igb_ks->colc.value.ui64 += E1000_READ_REG(hw, E1000_COLC); *val = igb_ks->colc.value.ui64; break; case MAC_STAT_RBYTES: /* * The 64-bit register will reset whenever the upper * 32 bits are read. So we need to read the lower * 32 bits first, then read the upper 32 bits. */ low_val = E1000_READ_REG(hw, E1000_TORL); high_val = E1000_READ_REG(hw, E1000_TORH); igb_ks->tor.value.ui64 += (uint64_t)high_val << 32 | (uint64_t)low_val; *val = igb_ks->tor.value.ui64; break; case MAC_STAT_IPACKETS: igb_ks->tpr.value.ui64 += E1000_READ_REG(hw, E1000_TPR); *val = igb_ks->tpr.value.ui64; break; case MAC_STAT_OBYTES: /* * The 64-bit register will reset whenever the upper * 32 bits are read. So we need to read the lower * 32 bits first, then read the upper 32 bits. */ low_val = E1000_READ_REG(hw, E1000_TOTL); high_val = E1000_READ_REG(hw, E1000_TOTH); igb_ks->tot.value.ui64 += (uint64_t)high_val << 32 | (uint64_t)low_val; *val = igb_ks->tot.value.ui64; break; case MAC_STAT_OPACKETS: igb_ks->tpt.value.ui64 += E1000_READ_REG(hw, E1000_TPT); *val = igb_ks->tpt.value.ui64; break; /* RFC 1643 stats */ case ETHER_STAT_ALIGN_ERRORS: igb_ks->algnerrc.value.ui64 += E1000_READ_REG(hw, E1000_ALGNERRC); *val = igb_ks->algnerrc.value.ui64; break; case ETHER_STAT_FCS_ERRORS: igb_ks->crcerrs.value.ui64 += E1000_READ_REG(hw, E1000_CRCERRS); *val = igb_ks->crcerrs.value.ui64; break; case ETHER_STAT_FIRST_COLLISIONS: igb_ks->scc.value.ui64 += E1000_READ_REG(hw, E1000_SCC); *val = igb_ks->scc.value.ui64; break; case ETHER_STAT_MULTI_COLLISIONS: igb_ks->mcc.value.ui64 += E1000_READ_REG(hw, E1000_MCC); *val = igb_ks->mcc.value.ui64; break; case ETHER_STAT_SQE_ERRORS: igb_ks->sec.value.ui64 += E1000_READ_REG(hw, E1000_SEC); *val = igb_ks->sec.value.ui64; break; case ETHER_STAT_DEFER_XMTS: igb_ks->dc.value.ui64 += E1000_READ_REG(hw, E1000_DC); *val = igb_ks->dc.value.ui64; break; case ETHER_STAT_TX_LATE_COLLISIONS: igb_ks->latecol.value.ui64 += E1000_READ_REG(hw, E1000_LATECOL); *val = igb_ks->latecol.value.ui64; break; case ETHER_STAT_EX_COLLISIONS: igb_ks->ecol.value.ui64 += E1000_READ_REG(hw, E1000_ECOL); *val = igb_ks->ecol.value.ui64; break; case ETHER_STAT_MACXMT_ERRORS: igb_ks->ecol.value.ui64 += E1000_READ_REG(hw, E1000_ECOL); *val = igb_ks->ecol.value.ui64; break; case ETHER_STAT_CARRIER_ERRORS: igb_ks->cexterr.value.ui64 += E1000_READ_REG(hw, E1000_CEXTERR); *val = igb_ks->cexterr.value.ui64; break; case ETHER_STAT_TOOLONG_ERRORS: igb_ks->roc.value.ui64 += E1000_READ_REG(hw, E1000_ROC); *val = igb_ks->roc.value.ui64; break; case ETHER_STAT_MACRCV_ERRORS: igb_ks->rxerrc.value.ui64 += E1000_READ_REG(hw, E1000_RXERRC); *val = igb_ks->rxerrc.value.ui64; break; /* MII/GMII stats */ case ETHER_STAT_XCVR_ADDR: /* The Internal PHY's MDI address for each MAC is 1 */ *val = 1; break; case ETHER_STAT_XCVR_ID: *val = hw->phy.id | hw->phy.revision; break; case ETHER_STAT_XCVR_INUSE: switch (igb->link_speed) { case SPEED_1000: *val = (hw->phy.media_type == e1000_media_type_copper) ? XCVR_1000T : XCVR_1000X; break; case SPEED_100: *val = (hw->phy.media_type == e1000_media_type_copper) ? (igb->param_100t4_cap == 1) ? XCVR_100T4 : XCVR_100T2 : XCVR_100X; break; case SPEED_10: *val = XCVR_10; break; default: *val = XCVR_NONE; break; } break; case ETHER_STAT_CAP_1000FDX: *val = igb->param_1000fdx_cap; break; case ETHER_STAT_CAP_1000HDX: *val = igb->param_1000hdx_cap; break; case ETHER_STAT_CAP_100FDX: *val = igb->param_100fdx_cap; break; case ETHER_STAT_CAP_100HDX: *val = igb->param_100hdx_cap; break; case ETHER_STAT_CAP_10FDX: *val = igb->param_10fdx_cap; break; case ETHER_STAT_CAP_10HDX: *val = igb->param_10hdx_cap; break; case ETHER_STAT_CAP_ASMPAUSE: *val = igb->param_asym_pause_cap; break; case ETHER_STAT_CAP_PAUSE: *val = igb->param_pause_cap; break; case ETHER_STAT_CAP_AUTONEG: *val = igb->param_autoneg_cap; break; case ETHER_STAT_ADV_CAP_1000FDX: *val = igb->param_adv_1000fdx_cap; break; case ETHER_STAT_ADV_CAP_1000HDX: *val = igb->param_adv_1000hdx_cap; break; case ETHER_STAT_ADV_CAP_100FDX: *val = igb->param_adv_100fdx_cap; break; case ETHER_STAT_ADV_CAP_100HDX: *val = igb->param_adv_100hdx_cap; break; case ETHER_STAT_ADV_CAP_10FDX: *val = igb->param_adv_10fdx_cap; break; case ETHER_STAT_ADV_CAP_10HDX: *val = igb->param_adv_10hdx_cap; break; case ETHER_STAT_ADV_CAP_ASMPAUSE: *val = igb->param_adv_asym_pause_cap; break; case ETHER_STAT_ADV_CAP_PAUSE: *val = igb->param_adv_pause_cap; break; case ETHER_STAT_ADV_CAP_AUTONEG: *val = hw->mac.autoneg; break; case ETHER_STAT_LP_CAP_1000FDX: *val = igb->param_lp_1000fdx_cap; break; case ETHER_STAT_LP_CAP_1000HDX: *val = igb->param_lp_1000hdx_cap; break; case ETHER_STAT_LP_CAP_100FDX: *val = igb->param_lp_100fdx_cap; break; case ETHER_STAT_LP_CAP_100HDX: *val = igb->param_lp_100hdx_cap; break; case ETHER_STAT_LP_CAP_10FDX: *val = igb->param_lp_10fdx_cap; break; case ETHER_STAT_LP_CAP_10HDX: *val = igb->param_lp_10hdx_cap; break; case ETHER_STAT_LP_CAP_ASMPAUSE: *val = igb->param_lp_asym_pause_cap; break; case ETHER_STAT_LP_CAP_PAUSE: *val = igb->param_lp_pause_cap; break; case ETHER_STAT_LP_CAP_AUTONEG: *val = igb->param_lp_autoneg_cap; break; case ETHER_STAT_LINK_ASMPAUSE: *val = igb->param_asym_pause_cap; break; case ETHER_STAT_LINK_PAUSE: *val = igb->param_pause_cap; break; case ETHER_STAT_LINK_AUTONEG: *val = hw->mac.autoneg; break; case ETHER_STAT_LINK_DUPLEX: *val = (igb->link_duplex == FULL_DUPLEX) ? LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; break; case ETHER_STAT_TOOSHORT_ERRORS: igb_ks->ruc.value.ui64 += E1000_READ_REG(hw, E1000_RUC); *val = igb_ks->ruc.value.ui64; break; case ETHER_STAT_CAP_REMFAULT: *val = igb->param_rem_fault; break; case ETHER_STAT_ADV_REMFAULT: *val = igb->param_adv_rem_fault; break; case ETHER_STAT_LP_REMFAULT: *val = igb->param_lp_rem_fault; break; case ETHER_STAT_JABBER_ERRORS: igb_ks->rjc.value.ui64 += E1000_READ_REG(hw, E1000_RJC); *val = igb_ks->rjc.value.ui64; break; case ETHER_STAT_CAP_100T4: *val = igb->param_100t4_cap; break; case ETHER_STAT_ADV_CAP_100T4: *val = igb->param_adv_100t4_cap; break; case ETHER_STAT_LP_CAP_100T4: *val = igb->param_lp_100t4_cap; break; default: mutex_exit(&igb->gen_lock); return (ENOTSUP); } mutex_exit(&igb->gen_lock); if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) { ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); return (EIO); } return (0); }