/* * Bare-minimum autoneg protocol * * This code is only called when the link is up and we're receiving config * words, which implies that the link partner wants to autonegotiate * (otherwise, we wouldn't see configs and wouldn't reach this code). */ static void bge_autoneg_serdes(bge_t *bgep) { boolean_t ack; bgep->serdes_lpadv = bge_reg_get32(bgep, RX_1000BASEX_AUTONEG_REG); ack = BIS(bgep->serdes_lpadv, AUTONEG_CODE_ACKNOWLEDGE); if (!ack) { /* * Phase 1: after SerDes reset, we send a few zero configs * but then stop. Here the partner is sending configs, but * not ACKing ours; we assume that's 'cos we're not sending * any. So here we send ours, with ACK already set. */ bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, bgep->serdes_advert | AUTONEG_CODE_ACKNOWLEDGE); bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); } else { /* * Phase 2: partner has ACKed our configs, so now we can * stop sending; once our partner also stops sending, we * can resolve the Tx/Rx configs. */ bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); } BGE_DEBUG(("bge_autoneg_serdes: Rx 0x%x %s Tx 0x%x", bgep->serdes_lpadv, ack ? "stop" : "send", bgep->serdes_advert)); }
/* * Here we have to determine which media we're using (copper or serdes). * Once that's done, we can initialise the physical layer appropriately. */ int bge_phys_init(bge_t *bgep) { BGE_TRACE(("bge_phys_init($%p)", (void *)bgep)); mutex_enter(bgep->genlock); /* * Probe for the (internal) PHY. If it's not there, we'll assume * that this is a 5703/4S, with a SerDes interface rather than * a PHY. BCM5714S/BCM5715S are not supported.It are based on * BCM800x PHY. */ bgep->phy_mii_addr = 1; if (DEVICE_5717_SERIES_CHIPSETS(bgep)) { int regval = bge_reg_get32(bgep, CPMU_STATUS_REG); if (regval & CPMU_STATUS_FUN_NUM) bgep->phy_mii_addr += 1; regval = bge_reg_get32(bgep, SGMII_STATUS_REG); if (regval & MEDIA_SELECTION_MODE) bgep->phy_mii_addr += 7; } if (bge_phy_probe(bgep)) { bgep->chipid.flags &= ~CHIP_FLAG_SERDES; bgep->physops = &copper_ops; } else { bgep->chipid.flags |= CHIP_FLAG_SERDES; bgep->physops = &serdes_ops; } if ((*bgep->physops->phys_restart)(bgep, B_FALSE) != DDI_SUCCESS) { mutex_exit(bgep->genlock); return (EIO); } if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { mutex_exit(bgep->genlock); return (EIO); } mutex_exit(bgep->genlock); return (0); }
/* * Reinitialise the SerDes interface. Note that it normally powers * up in the disabled state, so we need to explicitly activate it. */ static int bge_restart_serdes(bge_t *bgep, boolean_t powerdown) { uint32_t macmode; BGE_TRACE(("bge_restart_serdes($%p, %d)", (void *)bgep, powerdown)); ASSERT(mutex_owned(bgep->genlock)); /* * Ensure that the main Ethernet MAC mode register is programmed * appropriately for the SerDes interface ... */ macmode = bge_reg_get32(bgep, ETHERNET_MAC_MODE_REG); if (DEVICE_5714_SERIES_CHIPSETS(bgep)) { macmode |= ETHERNET_MODE_LINK_POLARITY; macmode &= ~ETHERNET_MODE_PORTMODE_MASK; macmode |= ETHERNET_MODE_PORTMODE_GMII; } else { macmode &= ~ETHERNET_MODE_LINK_POLARITY; macmode &= ~ETHERNET_MODE_PORTMODE_MASK; macmode |= ETHERNET_MODE_PORTMODE_TBI; } bge_reg_put32(bgep, ETHERNET_MAC_MODE_REG, macmode); /* * Ensure that loopback is OFF and comma detection is enabled. Then * disable the SerDes output (the first time through, it may/will * already be disabled). If we're shutting down, leave it disabled. */ bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TBI_LOOPBACK); bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_COMMA_DETECT); bge_reg_set32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE); if (powerdown) return (DDI_SUCCESS); /* * Otherwise, pause, (re-)enable the SerDes output, and send * all-zero config words in order to force autoneg restart. * Invalidate the saved "link partners received configs", as * we're starting over ... */ drv_usecwait(10000); bge_reg_clr32(bgep, SERDES_CONTROL_REG, SERDES_CONTROL_TX_DISABLE); bge_reg_put32(bgep, TX_1000BASEX_AUTONEG_REG, 0); bge_reg_set32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); drv_usecwait(10); bge_reg_clr32(bgep, ETHERNET_MAC_MODE_REG, ETHERNET_MODE_SEND_CFGS); bgep->serdes_lpadv = AUTONEG_CODE_FAULT_ANEG_ERR; bgep->serdes_status = ~0U; return (DDI_SUCCESS); }
/* * Basic low-level function to reset the PHY. * Doesn't incorporate any special-case workarounds. * * Returns TRUE on success, FALSE if the RESET bit doesn't clear */ static boolean_t bge_phy_reset(bge_t *bgep) { uint16_t control; uint_t count; BGE_TRACE(("bge_phy_reset($%p)", (void *)bgep)); ASSERT(mutex_owned(bgep->genlock)); if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { drv_usecwait(40); /* put PHY into ready state */ bge_reg_clr32(bgep, MISC_CONFIG_REG, MISC_CONFIG_EPHY_IDDQ); (void) bge_reg_get32(bgep, MISC_CONFIG_REG); /* flush */ drv_usecwait(40); } /* * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear */ bge_mii_put16(bgep, MII_CONTROL, MII_CONTROL_RESET); for (count = 0; ++count < 1000; ) { drv_usecwait(5); control = bge_mii_get16(bgep, MII_CONTROL); if (BIC(control, MII_CONTROL_RESET)) return (B_TRUE); } if (DEVICE_5906_SERIES_CHIPSETS(bgep)) (void) bge_adj_volt_5906(bgep); BGE_DEBUG(("bge_phy_reset: FAILED, control now 0x%x", control)); return (B_FALSE); }
static boolean_t bge_check_copper(bge_t *bgep, boolean_t recheck) { uint32_t emac_status; uint16_t mii_status; uint16_t aux; uint_t mode; boolean_t linkup; /* * Step 10: read the status from the PHY (which is self-clearing * on read!); also read & clear the main (Ethernet) MAC status * (the relevant bits of this are write-one-to-clear). */ mii_status = bge_mii_get16(bgep, MII_STATUS); emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG); bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status); BGE_DEBUG(("bge_check_copper: link %d/%s, MII status 0x%x " "(was 0x%x), Ethernet MAC status 0x%x", bgep->link_state, UPORDOWN(bgep->param_link_up), mii_status, bgep->phy_gen_status, emac_status)); /* * If the PHY status hasn't changed since last we looked, and * we not forcing a recheck (i.e. the link state was already * known), there's nothing to do. */ if (mii_status == bgep->phy_gen_status && !recheck) return (B_FALSE); do { /* * Step 11: read AUX STATUS register to find speed/duplex */ aux = bge_mii_get16(bgep, MII_AUX_STATUS); BGE_CDB(bge_phydump, (bgep, mii_status, aux)); /* * We will only consider the link UP if all the readings * are consistent and give meaningful results ... */ mode = aux & MII_AUX_STATUS_MODE_MASK; mode >>= MII_AUX_STATUS_MODE_SHIFT; if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { linkup = BIS(aux, MII_AUX_STATUS_LINKUP); linkup &= BIS(mii_status, MII_STATUS_LINKUP); } else { linkup = bge_copper_link_speed[mode] > 0; linkup &= bge_copper_link_duplex[mode] != LINK_DUPLEX_UNKNOWN; linkup &= BIS(aux, MII_AUX_STATUS_LINKUP); linkup &= BIS(mii_status, MII_STATUS_LINKUP); } BGE_DEBUG(("bge_check_copper: MII status 0x%x aux 0x%x " "=> mode %d (%s)", mii_status, aux, mode, UPORDOWN(linkup))); /* * Record current register values, then reread status * register & loop until it stabilises ... */ bgep->phy_aux_status = aux; bgep->phy_gen_status = mii_status; mii_status = bge_mii_get16(bgep, MII_STATUS); } while (mii_status != bgep->phy_gen_status); /* * Assume very little ... */ bgep->param_lp_autoneg = B_FALSE; bgep->param_lp_1000fdx = B_FALSE; bgep->param_lp_1000hdx = B_FALSE; bgep->param_lp_100fdx = B_FALSE; bgep->param_lp_100hdx = B_FALSE; bgep->param_lp_10fdx = B_FALSE; bgep->param_lp_10hdx = B_FALSE; bgep->param_lp_pause = B_FALSE; bgep->param_lp_asym_pause = B_FALSE; bgep->param_link_autoneg = B_FALSE; bgep->param_link_tx_pause = B_FALSE; if (bgep->param_adv_autoneg) bgep->param_link_rx_pause = B_FALSE; else bgep->param_link_rx_pause = bgep->param_adv_pause; /* * Discover all the link partner's abilities. * These are scattered through various registers ... */ if (BIS(aux, MII_AUX_STATUS_LP_ANEG_ABLE)) { bgep->param_lp_autoneg = B_TRUE; bgep->param_link_autoneg = B_TRUE; bgep->param_link_tx_pause = BIS(aux, MII_AUX_STATUS_TX_PAUSE); bgep->param_link_rx_pause = BIS(aux, MII_AUX_STATUS_RX_PAUSE); aux = bge_mii_get16(bgep, MII_MSSTATUS); bgep->param_lp_1000fdx = BIS(aux, MII_MSSTATUS_LP1000T_FD); bgep->param_lp_1000hdx = BIS(aux, MII_MSSTATUS_LP1000T); aux = bge_mii_get16(bgep, MII_AN_LPABLE); bgep->param_lp_100fdx = BIS(aux, MII_ABILITY_100BASE_TX_FD); bgep->param_lp_100hdx = BIS(aux, MII_ABILITY_100BASE_TX); bgep->param_lp_10fdx = BIS(aux, MII_ABILITY_10BASE_T_FD); bgep->param_lp_10hdx = BIS(aux, MII_ABILITY_10BASE_T); bgep->param_lp_pause = BIS(aux, MII_ABILITY_PAUSE); bgep->param_lp_asym_pause = BIS(aux, MII_ABILITY_ASMPAUSE); } /* * Step 12: update ndd-visible state parameters, BUT! * we don't transfer the new state to <link_state> just yet; * instead we mark the <link_state> as UNKNOWN, and our caller * will resolve it once the status has stopped changing and * been stable for several seconds. */ BGE_DEBUG(("bge_check_copper: link was %s speed %d duplex %d", UPORDOWN(bgep->param_link_up), bgep->param_link_speed, bgep->param_link_duplex)); if (!linkup) mode = MII_AUX_STATUS_MODE_NONE; bgep->param_link_up = linkup; bgep->link_state = LINK_STATE_UNKNOWN; if (DEVICE_5906_SERIES_CHIPSETS(bgep)) { if (bgep->phy_aux_status & MII_AUX_STATUS_NEG_ENABLED_5906) { bgep->param_link_speed = bge_copper_link_speed_5906[mode]; bgep->param_link_duplex = bge_copper_link_duplex_5906[mode]; } else { bgep->param_link_speed = (bgep->phy_aux_status & MII_AUX_STATUS_SPEED_IND_5906) ? 100 : 10; bgep->param_link_duplex = (bgep->phy_aux_status & MII_AUX_STATUS_DUPLEX_IND_5906) ? LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; } } else { bgep->param_link_speed = bge_copper_link_speed[mode]; bgep->param_link_duplex = bge_copper_link_duplex[mode]; } BGE_DEBUG(("bge_check_copper: link now %s speed %d duplex %d", UPORDOWN(bgep->param_link_up), bgep->param_link_speed, bgep->param_link_duplex)); return (B_TRUE); }
static boolean_t bge_check_serdes(bge_t *bgep, boolean_t recheck) { uint32_t emac_status; uint32_t tx_status; uint32_t lpadv; boolean_t linkup; boolean_t linkup_old = bgep->param_link_up; for (;;) { /* * Step 10: BCM5714S, BCM5715S only * Don't call function bge_autoneg_serdes() as * RX_1000BASEX_AUTONEG_REG (0x0448) is not applicable * to BCM5705, BCM5788, BCM5721, BCM5751, BCM5752, * BCM5714, and BCM5715 devices. */ if (DEVICE_5714_SERIES_CHIPSETS(bgep)) { tx_status = bge_reg_get32(bgep, TRANSMIT_MAC_STATUS_REG); linkup = BIS(tx_status, TRANSMIT_STATUS_LINK_UP); emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG); bgep->serdes_status = emac_status; if ((linkup && linkup_old) || (!linkup && !linkup_old)) { emac_status &= ~ETHERNET_STATUS_LINK_CHANGED; emac_status &= ~ETHERNET_STATUS_RECEIVING_CFG; break; } emac_status |= ETHERNET_STATUS_LINK_CHANGED; emac_status |= ETHERNET_STATUS_RECEIVING_CFG; if (linkup) linkup_old = B_TRUE; else linkup_old = B_FALSE; recheck = B_TRUE; } else { /* * Step 10: others * read & clear the main (Ethernet) MAC status * (the relevant bits of this are write-one-to-clear). */ emac_status = bge_reg_get32(bgep, ETHERNET_MAC_STATUS_REG); bge_reg_put32(bgep, ETHERNET_MAC_STATUS_REG, emac_status); BGE_DEBUG(("bge_check_serdes: link %d/%s, " "MAC status 0x%x (was 0x%x)", bgep->link_state, UPORDOWN(bgep->param_link_up), emac_status, bgep->serdes_status)); /* * We will only consider the link UP if all the readings * are consistent and give meaningful results ... */ bgep->serdes_status = emac_status; linkup = BIS(emac_status, ETHERNET_STATUS_SIGNAL_DETECT); linkup &= BIS(emac_status, ETHERNET_STATUS_PCS_SYNCHED); /* * Now some fiddling with the interpretation: * if there's been an error at the PCS level, treat * it as a link change (the h/w doesn't do this) * * if there's been a change, but it's only a PCS * sync change (not a config change), AND the link * already was & is still UP, then ignore the * change */ if (BIS(emac_status, ETHERNET_STATUS_PCS_ERROR)) emac_status |= ETHERNET_STATUS_LINK_CHANGED; else if (BIC(emac_status, ETHERNET_STATUS_CFG_CHANGED)) if (bgep->param_link_up && linkup) emac_status &= ~ETHERNET_STATUS_LINK_CHANGED; BGE_DEBUG(("bge_check_serdes: status 0x%x => 0x%x %s", bgep->serdes_status, emac_status, UPORDOWN(linkup))); /* * If we're receiving configs, run the autoneg protocol */ if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG)) bge_autoneg_serdes(bgep); /* * If the SerDes status hasn't changed, we're done ... */ if (BIC(emac_status, ETHERNET_STATUS_LINK_CHANGED)) break; /* * Go round again until we no longer see a change ... */ recheck = B_TRUE; } } /* * If we're not forcing a recheck (i.e. the link state was already * known), and we didn't see the hardware flag a change, there's * no more to do (and we tell the caller nothing happened). */ if (!recheck) return (B_FALSE); /* * Don't resolve autoneg until we're no longer receiving configs */ if (linkup && BIS(emac_status, ETHERNET_STATUS_RECEIVING_CFG)) return (B_FALSE); /* * Assume very little ... */ bgep->param_lp_autoneg = B_FALSE; bgep->param_lp_1000fdx = B_FALSE; bgep->param_lp_1000hdx = B_FALSE; bgep->param_lp_100fdx = B_FALSE; bgep->param_lp_100hdx = B_FALSE; bgep->param_lp_10fdx = B_FALSE; bgep->param_lp_10hdx = B_FALSE; bgep->param_lp_pause = B_FALSE; bgep->param_lp_asym_pause = B_FALSE; bgep->param_link_autoneg = B_FALSE; bgep->param_link_tx_pause = B_FALSE; if (bgep->param_adv_autoneg) bgep->param_link_rx_pause = B_FALSE; else bgep->param_link_rx_pause = bgep->param_adv_pause; /* * Discover all the link partner's abilities. */ lpadv = bgep->serdes_lpadv; if (lpadv != 0 && BIC(lpadv, AUTONEG_CODE_FAULT_MASK)) { /* * No fault, so derive partner's capabilities */ bgep->param_lp_autoneg = B_TRUE; bgep->param_lp_1000fdx = BIS(lpadv, AUTONEG_CODE_FULL_DUPLEX); bgep->param_lp_1000hdx = BIS(lpadv, AUTONEG_CODE_HALF_DUPLEX); bgep->param_lp_pause = BIS(lpadv, AUTONEG_CODE_PAUSE); bgep->param_lp_asym_pause = BIS(lpadv, AUTONEG_CODE_ASYM_PAUSE); /* * Pause direction resolution */ bgep->param_link_autoneg = B_TRUE; if (bgep->param_adv_pause && bgep->param_lp_pause) { bgep->param_link_tx_pause = B_TRUE; bgep->param_link_rx_pause = B_TRUE; } if (bgep->param_adv_asym_pause && bgep->param_lp_asym_pause) { if (bgep->param_adv_pause) bgep->param_link_rx_pause = B_TRUE; if (bgep->param_lp_pause) bgep->param_link_tx_pause = B_TRUE; } } /* * Step 12: update ndd-visible state parameters, BUT! * we don't transfer the new state to <link_state> just yet; * instead we mark the <link_state> as UNKNOWN, and our caller * will resolve it once the status has stopped changing and * been stable for several seconds. */ BGE_DEBUG(("bge_check_serdes: link was %s speed %d duplex %d", UPORDOWN(bgep->param_link_up), bgep->param_link_speed, bgep->param_link_duplex)); if (linkup) { bgep->param_link_up = B_TRUE; bgep->param_link_speed = 1000; if (bgep->param_adv_1000fdx) bgep->param_link_duplex = LINK_DUPLEX_FULL; else bgep->param_link_duplex = LINK_DUPLEX_HALF; if (bgep->param_lp_autoneg && !bgep->param_lp_1000fdx) bgep->param_link_duplex = LINK_DUPLEX_HALF; } else { bgep->param_link_up = B_FALSE; bgep->param_link_speed = 0; bgep->param_link_duplex = LINK_DUPLEX_UNKNOWN; } bgep->link_state = LINK_STATE_UNKNOWN; BGE_DEBUG(("bge_check_serdes: link now %s speed %d duplex %d", UPORDOWN(bgep->param_link_up), bgep->param_link_speed, bgep->param_link_duplex)); return (B_TRUE); }
int bge_m_stat(void *arg, uint_t stat, uint64_t *val) { bge_t *bgep = arg; bge_statistics_t *bstp; bge_statistics_reg_t *pstats; if (bgep->bge_chip_state != BGE_CHIP_RUNNING) { return (EINVAL); } if (bgep->chipid.statistic_type == BGE_STAT_BLK) bstp = DMA_VPTR(bgep->statistics); else { pstats = bgep->pstats; pstats->ifHCOutOctets += bge_reg_get32(bgep, STAT_IFHCOUT_OCTETS_REG); pstats->etherStatsCollisions += bge_reg_get32(bgep, STAT_ETHER_COLLIS_REG); pstats->outXonSent += bge_reg_get32(bgep, STAT_OUTXON_SENT_REG); pstats->outXoffSent += bge_reg_get32(bgep, STAT_OUTXOFF_SENT_REG); pstats->dot3StatsInternalMacTransmitErrors += bge_reg_get32(bgep, STAT_DOT3_INTMACTX_ERR_REG); pstats->dot3StatsSingleCollisionFrames += bge_reg_get32(bgep, STAT_DOT3_SCOLLI_FRAME_REG); pstats->dot3StatsMultipleCollisionFrames += bge_reg_get32(bgep, STAT_DOT3_MCOLLI_FRAME_REG); pstats->dot3StatsDeferredTransmissions += bge_reg_get32(bgep, STAT_DOT3_DEFERED_TX_REG); pstats->dot3StatsExcessiveCollisions += bge_reg_get32(bgep, STAT_DOT3_EXCE_COLLI_REG); pstats->dot3StatsLateCollisions += bge_reg_get32(bgep, STAT_DOT3_LATE_COLLI_REG); pstats->ifHCOutUcastPkts += bge_reg_get32(bgep, STAT_IFHCOUT_UPKGS_REG); pstats->ifHCOutMulticastPkts += bge_reg_get32(bgep, STAT_IFHCOUT_MPKGS_REG); pstats->ifHCOutBroadcastPkts += bge_reg_get32(bgep, STAT_IFHCOUT_BPKGS_REG); pstats->ifHCInOctets += bge_reg_get32(bgep, STAT_IFHCIN_OCTETS_REG); pstats->etherStatsFragments += bge_reg_get32(bgep, STAT_ETHER_FRAGMENT_REG); pstats->ifHCInUcastPkts += bge_reg_get32(bgep, STAT_IFHCIN_UPKGS_REG); pstats->ifHCInMulticastPkts += bge_reg_get32(bgep, STAT_IFHCIN_MPKGS_REG); pstats->ifHCInBroadcastPkts += bge_reg_get32(bgep, STAT_IFHCIN_BPKGS_REG); pstats->dot3StatsFCSErrors += bge_reg_get32(bgep, STAT_DOT3_FCS_ERR_REG); pstats->dot3StatsAlignmentErrors += bge_reg_get32(bgep, STAT_DOT3_ALIGN_ERR_REG); pstats->xonPauseFramesReceived += bge_reg_get32(bgep, STAT_XON_PAUSE_RX_REG); pstats->xoffPauseFramesReceived += bge_reg_get32(bgep, STAT_XOFF_PAUSE_RX_REG); pstats->macControlFramesReceived += bge_reg_get32(bgep, STAT_MAC_CTRL_RX_REG); pstats->xoffStateEntered += bge_reg_get32(bgep, STAT_XOFF_STATE_ENTER_REG); pstats->dot3StatsFrameTooLongs += bge_reg_get32(bgep, STAT_DOT3_FRAME_TOOLONG_REG); pstats->etherStatsJabbers += bge_reg_get32(bgep, STAT_ETHER_JABBERS_REG); pstats->etherStatsUndersizePkts += bge_reg_get32(bgep, STAT_ETHER_UNDERSIZE_REG); mutex_enter(bgep->genlock); if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); } mutex_exit(bgep->genlock); } switch (stat) { case MAC_STAT_IFSPEED: *val = (bgep->link_state != LINK_STATE_UNKNOWN) ? (bgep->param_link_speed * 1000000ull) : 0; break; case MAC_STAT_MULTIRCV: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCInMulticastPkts; else *val = pstats->ifHCInMulticastPkts; break; case MAC_STAT_BRDCSTRCV: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCInBroadcastPkts; else *val = pstats->ifHCInBroadcastPkts; break; case MAC_STAT_MULTIXMT: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCOutMulticastPkts; else *val = pstats->ifHCOutMulticastPkts; break; case MAC_STAT_BRDCSTXMT: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCOutBroadcastPkts; else *val = pstats->ifHCOutBroadcastPkts; break; case MAC_STAT_NORCVBUF: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifInDiscards; else *val = 0; break; case MAC_STAT_IERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) { *val = bstp->s.dot3StatsFCSErrors + bstp->s.dot3StatsAlignmentErrors + bstp->s.dot3StatsFrameTooLongs + bstp->s.etherStatsUndersizePkts + bstp->s.etherStatsJabbers; } else { *val = pstats->dot3StatsFCSErrors + pstats->dot3StatsAlignmentErrors + pstats->dot3StatsFrameTooLongs + pstats->etherStatsUndersizePkts + pstats->etherStatsJabbers; } break; case MAC_STAT_NOXMTBUF: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifOutDiscards; else *val = 0; break; case MAC_STAT_OERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifOutDiscards; else *val = 0; break; case MAC_STAT_COLLISIONS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.etherStatsCollisions; else *val = pstats->etherStatsCollisions; break; case MAC_STAT_RBYTES: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCInOctets; else *val = pstats->ifHCInOctets; break; case MAC_STAT_IPACKETS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCInUcastPkts + bstp->s.ifHCInMulticastPkts + bstp->s.ifHCInBroadcastPkts; else *val = pstats->ifHCInUcastPkts + pstats->ifHCInMulticastPkts + pstats->ifHCInBroadcastPkts; break; case MAC_STAT_OBYTES: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCOutOctets; else *val = pstats->ifHCOutOctets; break; case MAC_STAT_OPACKETS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.ifHCOutUcastPkts + bstp->s.ifHCOutMulticastPkts + bstp->s.ifHCOutBroadcastPkts; else *val = pstats->ifHCOutUcastPkts + pstats->ifHCOutMulticastPkts + pstats->ifHCOutBroadcastPkts; break; case ETHER_STAT_ALIGN_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsAlignmentErrors; else *val = pstats->dot3StatsAlignmentErrors; break; case ETHER_STAT_FCS_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsFCSErrors; else *val = pstats->dot3StatsFCSErrors; break; case ETHER_STAT_FIRST_COLLISIONS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsSingleCollisionFrames; else *val = pstats->dot3StatsSingleCollisionFrames; break; case ETHER_STAT_MULTI_COLLISIONS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsMultipleCollisionFrames; else *val = pstats->dot3StatsMultipleCollisionFrames; break; case ETHER_STAT_DEFER_XMTS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsDeferredTransmissions; else *val = pstats->dot3StatsDeferredTransmissions; break; case ETHER_STAT_TX_LATE_COLLISIONS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsLateCollisions; else *val = pstats->dot3StatsLateCollisions; break; case ETHER_STAT_EX_COLLISIONS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsExcessiveCollisions; else *val = pstats->dot3StatsExcessiveCollisions; break; case ETHER_STAT_MACXMT_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsInternalMacTransmitErrors; else *val = bgep->pstats->dot3StatsInternalMacTransmitErrors; break; case ETHER_STAT_CARRIER_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsCarrierSenseErrors; else *val = 0; break; case ETHER_STAT_TOOLONG_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.dot3StatsFrameTooLongs; else *val = pstats->dot3StatsFrameTooLongs; break; #if (MAC_VERSION > 1) case ETHER_STAT_TOOSHORT_ERRORS: if (bgep->chipid.statistic_type == BGE_STAT_BLK) *val = bstp->s.etherStatsUndersizePkts; else *val = pstats->etherStatsUndersizePkts; break; #endif case ETHER_STAT_XCVR_ADDR: *val = bgep->phy_mii_addr; break; case ETHER_STAT_XCVR_ID: mutex_enter(bgep->genlock); *val = bge_mii_get16(bgep, MII_PHYIDH); *val <<= 16; *val |= bge_mii_get16(bgep, MII_PHYIDL); if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); } mutex_exit(bgep->genlock); break; case ETHER_STAT_XCVR_INUSE: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = XCVR_1000X; else *val = XCVR_1000T; break; case ETHER_STAT_CAP_1000FDX: *val = 1; break; case ETHER_STAT_CAP_1000HDX: *val = 1; break; case ETHER_STAT_CAP_100FDX: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else *val = 1; break; case ETHER_STAT_CAP_100HDX: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else *val = 1; break; case ETHER_STAT_CAP_10FDX: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else *val = 1; break; case ETHER_STAT_CAP_10HDX: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else *val = 1; break; case ETHER_STAT_CAP_ASMPAUSE: *val = 1; break; case ETHER_STAT_CAP_PAUSE: *val = 1; break; case ETHER_STAT_CAP_AUTONEG: *val = 1; break; #if (MAC_VERSION > 1) case ETHER_STAT_CAP_REMFAULT: *val = 1; break; #endif case ETHER_STAT_ADV_CAP_1000FDX: *val = bgep->param_adv_1000fdx; break; case ETHER_STAT_ADV_CAP_1000HDX: *val = bgep->param_adv_1000hdx; break; case ETHER_STAT_ADV_CAP_100FDX: *val = bgep->param_adv_100fdx; break; case ETHER_STAT_ADV_CAP_100HDX: *val = bgep->param_adv_100hdx; break; case ETHER_STAT_ADV_CAP_10FDX: *val = bgep->param_adv_10fdx; break; case ETHER_STAT_ADV_CAP_10HDX: *val = bgep->param_adv_10hdx; break; case ETHER_STAT_ADV_CAP_ASMPAUSE: *val = bgep->param_adv_asym_pause; break; case ETHER_STAT_ADV_CAP_PAUSE: *val = bgep->param_adv_pause; break; case ETHER_STAT_ADV_CAP_AUTONEG: *val = bgep->param_adv_autoneg; break; #if (MAC_VERSION > 1) case ETHER_STAT_ADV_REMFAULT: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else { mutex_enter(bgep->genlock); *val = bge_mii_get16(bgep, MII_AN_ADVERT) & MII_AN_ADVERT_REMFAULT ? 1 : 0; if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); } mutex_exit(bgep->genlock); } break; #endif case ETHER_STAT_LP_CAP_1000FDX: *val = bgep->param_lp_1000fdx; break; case ETHER_STAT_LP_CAP_1000HDX: *val = bgep->param_lp_1000hdx; break; case ETHER_STAT_LP_CAP_100FDX: *val = bgep->param_lp_100fdx; break; case ETHER_STAT_LP_CAP_100HDX: *val = bgep->param_lp_100hdx; break; case ETHER_STAT_LP_CAP_10FDX: *val = bgep->param_lp_10fdx; break; case ETHER_STAT_LP_CAP_10HDX: *val = bgep->param_lp_10hdx; break; case ETHER_STAT_LP_CAP_ASMPAUSE: *val = bgep->param_lp_asym_pause; break; case ETHER_STAT_LP_CAP_PAUSE: *val = bgep->param_lp_pause; break; case ETHER_STAT_LP_CAP_AUTONEG: *val = bgep->param_lp_autoneg; break; #if (MAC_VERSION > 1) case ETHER_STAT_LP_REMFAULT: if (bgep->chipid.flags & CHIP_FLAG_SERDES) *val = 0; else { mutex_enter(bgep->genlock); *val = bge_mii_get16(bgep, MII_AN_LPABLE) & MII_AN_ADVERT_REMFAULT ? 1 : 0; if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); } mutex_exit(bgep->genlock); } break; #endif case ETHER_STAT_LINK_ASMPAUSE: *val = bgep->param_adv_asym_pause && bgep->param_lp_asym_pause && bgep->param_adv_pause != bgep->param_lp_pause; break; case ETHER_STAT_LINK_PAUSE: *val = bgep->param_link_rx_pause; break; case ETHER_STAT_LINK_AUTONEG: *val = bgep->param_link_autoneg; break; case ETHER_STAT_LINK_DUPLEX: *val = (bgep->link_state != LINK_STATE_UNKNOWN) ? bgep->param_link_duplex : LINK_DUPLEX_UNKNOWN; break; default: return (ENOTSUP); } return (0); }
static int bge_phydata_update(kstat_t *ksp, int flag) { bge_t *bgep; kstat_named_t *knp; const bge_ksindex_t *ksip; if (flag != KSTAT_READ) return (EACCES); bgep = ksp->ks_private; if (bgep->bge_chip_state == BGE_CHIP_FAULT) return (EIO); knp = ksp->ks_data; /* * Read the PHY registers & update the kstats ... * * We need to hold the mutex while performing MII reads, but * we don't want to hold it across the entire sequence of reads. * So we grab and release it on each iteration, 'cos it doesn't * really matter if the kstats are less than 100% consistent ... */ for (ksip = bge_phydata; ksip->name != NULL; ++knp, ++ksip) { mutex_enter(bgep->genlock); switch (ksip->index) { case MII_STATUS: knp->value.ui64 = bgep->phy_gen_status; break; case MII_PHYIDH: knp->value.ui64 = bge_mii_get16(bgep, MII_PHYIDH); knp->value.ui64 <<= 16; knp->value.ui64 |= bge_mii_get16(bgep, MII_PHYIDL); break; case EEE_MODE_REG: knp->value.ui64 = 0; if (bgep->link_state == LINK_STATE_UP) { knp->value.ui64 = (bge_reg_get32(bgep, EEE_MODE_REG) & 0x80) ? 1 : 0; } break; default: knp->value.ui64 = bge_mii_get16(bgep, ksip->index); break; } if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); mutex_exit(bgep->genlock); return (EIO); } mutex_exit(bgep->genlock); } return (0); }
static int bge_driverinfo_update(kstat_t *ksp, int flag) { bge_t *bgep; kstat_named_t *knp; ddi_acc_handle_t handle; if (flag != KSTAT_READ) return (EACCES); bgep = ksp->ks_private; if (bgep->bge_chip_state == BGE_CHIP_FAULT) return (EIO); knp = ksp->ks_data; (knp++)->value.ui64 = bgep->rx_buff[0].cookie.dmac_laddress; (knp++)->value.ui64 = bgep->tx_buff[0].cookie.dmac_laddress; (knp++)->value.ui64 = bgep->rx_desc[0].cookie.dmac_laddress; (knp++)->value.ui64 = bgep->tx_desc.cookie.dmac_laddress; (knp++)->value.ui64 = bgep->send[0].tx_free; (knp++)->value.ui64 = bgep->send[0].tx_array; (knp++)->value.ui64 = bgep->send[0].tc_next; (knp++)->value.ui64 = bgep->send[0].tx_next; (knp++)->value.ui64 = bgep->send[0].txfill_next; (knp++)->value.ui64 = bgep->send[0].txpkt_next; (knp++)->value.ui64 = bgep->send[0].txbuf_pop_queue->count + bgep->send[0].txbuf_push_queue->count; (knp++)->value.ui64 = bgep->send[0].tx_flow; (knp++)->value.ui64 = bgep->tx_resched_needed; (knp++)->value.ui64 = bgep->tx_resched; (knp++)->value.ui64 = bgep->send[0].tx_nobuf; (knp++)->value.ui64 = bgep->send[0].tx_nobd; (knp++)->value.ui64 = bgep->send[0].tx_block; (knp++)->value.ui64 = bgep->send[0].tx_alloc_fail; (knp++)->value.ui64 = bgep->watchdog; (knp++)->value.ui64 = bgep->chip_resets; (knp++)->value.ui64 = bgep->missed_dmas; (knp++)->value.ui64 = bgep->missed_updates; /* * Hold the mutex while accessing the chip registers * just in case the factotum is trying to reset it! */ handle = bgep->cfg_handle; mutex_enter(bgep->genlock); (knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_MHCR); (knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_PDRWCR); (knp++)->value.ui64 = pci_config_get32(handle, PCI_CONF_BGE_PCISTATE); if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); mutex_exit(bgep->genlock); return (EIO); } (knp++)->value.ui64 = bge_reg_get32(bgep, BUFFER_MANAGER_STATUS_REG); (knp++)->value.ui64 = bge_reg_get32(bgep, RCV_INITIATOR_STATUS_REG); if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); mutex_exit(bgep->genlock); return (EIO); } mutex_exit(bgep->genlock); return (0); }