/* * Basic low-level function to probe for a PHY * * Returns TRUE if the PHY responds with valid data, FALSE otherwise */ static boolean_t bge_phy_probe(bge_t *bgep) { uint16_t miicfg; uint32_t nicsig, niccfg; BGE_TRACE(("bge_phy_probe($%p)", (void *)bgep)); ASSERT(mutex_owned(bgep->genlock)); nicsig = bge_nic_read32(bgep, BGE_NIC_DATA_SIG_ADDR); if (nicsig == BGE_NIC_DATA_SIG) { niccfg = bge_nic_read32(bgep, BGE_NIC_DATA_NIC_CFG_ADDR); switch (niccfg & BGE_NIC_CFG_PHY_TYPE_MASK) { default: case BGE_NIC_CFG_PHY_TYPE_COPPER: return (B_TRUE); case BGE_NIC_CFG_PHY_TYPE_FIBER: return (B_FALSE); } } else { /* * Read the MII_STATUS register twice, in * order to clear any sticky bits (but they should * have been cleared by the RESET, I think). */ miicfg = bge_mii_get16(bgep, MII_STATUS); miicfg = bge_mii_get16(bgep, MII_STATUS); BGE_DEBUG(("bge_phy_probe: status 0x%x", miicfg)); /* * Now check the value read; it should have at least one bit set * (for the device capabilities) and at least one clear (one of * the error bits). So if we see all 0s or all 1s, there's a * problem. In particular, bge_mii_get16() returns all 1s if * communications fails ... */ switch (miicfg) { case 0x0000: case 0xffff: return (B_FALSE); default : return (B_TRUE); } } }
static void bge_phy_macro_wait(bge_t *bgep) { uint_t count; for (count = 100; --count; ) if ((bge_mii_get16(bgep, 0x16) & 0x1000) == 0) break; }
static void bge_phydump(bge_t *bgep, uint16_t mii_status, uint16_t aux) { uint16_t regs[32]; int i; ASSERT(mutex_owned(bgep->genlock)); for (i = 0; i < 32; ++i) switch (i) { default: regs[i] = bge_mii_get16(bgep, i); break; case MII_STATUS: regs[i] = mii_status; break; case MII_AUX_STATUS: regs[i] = aux; break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x15: case 0x16: case 0x17: case 0x1c: case 0x1f: /* reserved registers -- don't read these */ regs[i] = 0; break; } for (i = 0; i < 32; i += 8) BGE_DEBUG(("bge_phydump: " "0x%04x %04x %04x %04x %04x %04x %04x %04x", regs[i+0], regs[i+1], regs[i+2], regs[i+3], regs[i+4], regs[i+5], regs[i+6], regs[i+7])); }
/* * 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 int bge_restart_copper(bge_t *bgep, boolean_t powerdown) { uint16_t phy_status; boolean_t reset_ok; uint16_t extctrl, auxctrl; BGE_TRACE(("bge_restart_copper($%p, %d)", (void *)bgep, powerdown)); ASSERT(mutex_owned(bgep->genlock)); switch (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev)) { default: /* * Shouldn't happen; it means we don't recognise this chip. * It's probably a new one, so we'll try our best anyway ... */ case MHCR_CHIP_ASIC_REV_5703: case MHCR_CHIP_ASIC_REV_5704: case MHCR_CHIP_ASIC_REV_5705: case MHCR_CHIP_ASIC_REV_5752: case MHCR_CHIP_ASIC_REV_5714: case MHCR_CHIP_ASIC_REV_5715: reset_ok = bge_phy_reset_and_check(bgep); break; case MHCR_CHIP_ASIC_REV_5906: case MHCR_CHIP_ASIC_REV_5700: case MHCR_CHIP_ASIC_REV_5701: case MHCR_CHIP_ASIC_REV_5723: case MHCR_CHIP_ASIC_REV_5721_5751: /* * Just a plain reset; the "check" code breaks these chips */ reset_ok = bge_phy_reset(bgep); if (!reset_ok) bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); break; } if (!reset_ok) { BGE_REPORT((bgep, "PHY failed to reset correctly")); return (DDI_FAILURE); } /* * Step 5: disable WOL (not required after RESET) * * Step 6: refer to errata */ switch (bgep->chipid.asic_rev) { default: break; case MHCR_CHIP_REV_5704_A0: bge_phy_tweak_gmii(bgep); break; } switch (MHCR_CHIP_ASIC_REV(bgep->chipid.asic_rev)) { case MHCR_CHIP_ASIC_REV_5705: case MHCR_CHIP_ASIC_REV_5721_5751: bge_phy_bit_err_fix(bgep); break; } if (!(bgep->chipid.flags & CHIP_FLAG_NO_JUMBO) && (bgep->chipid.default_mtu > BGE_DEFAULT_MTU)) { /* Set the GMII Fifo Elasticity to high latency */ extctrl = bge_mii_get16(bgep, 0x10); bge_mii_put16(bgep, 0x10, extctrl | 0x1); /* Allow reception of extended length packets */ bge_mii_put16(bgep, MII_AUX_CONTROL, 0x0007); auxctrl = bge_mii_get16(bgep, MII_AUX_CONTROL); auxctrl |= 0x4000; bge_mii_put16(bgep, MII_AUX_CONTROL, auxctrl); } /* * Step 7: read the MII_INTR_STATUS register twice, * in order to clear any sticky bits (but they should * have been cleared by the RESET, I think), and we're * not using PHY interrupts anyway. * * Step 8: enable the PHY to interrupt on link status * change (not required) * * Step 9: configure PHY LED Mode - not applicable? * * Step 10: read the MII_STATUS register twice, in * order to clear any sticky bits (but they should * have been cleared by the RESET, I think). */ phy_status = bge_mii_get16(bgep, MII_STATUS); phy_status = bge_mii_get16(bgep, MII_STATUS); BGE_DEBUG(("bge_restart_copper: status 0x%x", phy_status)); /* * Finally, shut down the PHY, if required */ if (powerdown) bge_phy_powerdown(bgep); return (DDI_SUCCESS); }
/* * Special-case code to reset the PHY on the 5702/5703/5704C/5705/5782. * Tries up to 5 times to recover from failure to reset or PHY lockup. * * Returns TRUE on success, FALSE if there's an unrecoverable problem */ static boolean_t bge_phy_reset_and_check(bge_t *bgep) { boolean_t reset_success; boolean_t phy_locked; uint16_t extctrl; uint16_t gigctrl; uint_t retries; for (retries = 0; retries < 5; ++retries) { /* Issue a phy reset, and wait for reset to complete */ /* Assuming reset is successful first */ reset_success = bge_phy_reset(bgep); /* * Now go check the DFE TAPs to see if locked up, but * first, we need to set up PHY so we can read DFE * TAPs. */ /* * Disable Transmitter and Interrupt, while we play * with the PHY registers, so the link partner won't * see any strange data and the Driver won't see any * interrupts. */ extctrl = bge_mii_get16(bgep, 0x10); bge_mii_put16(bgep, 0x10, extctrl | 0x3000); /* Setup Full-Duplex, 1000 mbps */ bge_mii_put16(bgep, 0x0, 0x0140); /* Set to Master mode */ gigctrl = bge_mii_get16(bgep, 0x9); bge_mii_put16(bgep, 0x9, 0x1800); /* Enable SM_DSP_CLOCK & 6dB */ bge_mii_put16(bgep, 0x18, 0x0c00); /* "the ADC fix" */ /* Work-arounds */ bge_mii_put16(bgep, 0x17, 0x201f); bge_mii_put16(bgep, 0x15, 0x2aaa); /* More workarounds */ bge_mii_put16(bgep, 0x17, 0x000a); bge_mii_put16(bgep, 0x15, 0x0323); /* "the Gamma fix" */ /* Blocks the PHY control access */ bge_mii_put16(bgep, 0x17, 0x8005); bge_mii_put16(bgep, 0x15, 0x0800); /* Test whether PHY locked up ;-( */ phy_locked = bge_phy_locked_up(bgep); if (reset_success && !phy_locked) break; /* * Some problem here ... log it & retry */ if (!reset_success) BGE_REPORT((bgep, "PHY didn't reset!")); if (phy_locked) BGE_REPORT((bgep, "PHY locked up!")); } /* Remove block phy control */ bge_mii_put16(bgep, 0x17, 0x8005); bge_mii_put16(bgep, 0x15, 0x0000); /* Unfreeze DFE TAP filter for all channels */ bge_mii_put16(bgep, 0x17, 0x8200); bge_mii_put16(bgep, 0x16, 0x0000); /* Restore PHY back to operating state */ bge_mii_put16(bgep, 0x18, 0x0400); /* Restore 1000BASE-T Control Register */ bge_mii_put16(bgep, 0x9, gigctrl); /* Enable transmitter and interrupt */ extctrl = bge_mii_get16(bgep, 0x10); bge_mii_put16(bgep, 0x10, extctrl & ~0x3000); if (DEVICE_5906_SERIES_CHIPSETS(bgep)) (void) bge_adj_volt_5906(bgep); if (!reset_success) bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE); else if (phy_locked) bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); return (reset_success && !phy_locked); }
/* * Check whether the PHY has locked up after a RESET. * * Returns TRUE if it did, FALSE is it's OK ;-) */ static boolean_t bge_phy_locked_up(bge_t *bgep) { uint16_t dataLo; uint16_t dataHi; uint_t chan; uint_t tap; /* * Check TAPs for all 4 channels, as soon as we see a lockup * we'll stop checking. */ for (chan = 0; chan < N_CHANNELS; ++chan) { /* Select channel and set TAP index to 0 */ bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200); /* Freeze filter again just to be safe */ bge_mii_put16(bgep, 0x16, 0x0002); /* * Write fixed pattern to the RAM, 3 TAPs for * each channel, each TAP have 2 WORDs (LO/HI) */ for (tap = 0; tap < N_TAPS; ++tap) { bge_mii_put16(bgep, 0x15, tap_data[chan][tap].lo); bge_mii_put16(bgep, 0x15, tap_data[chan][tap].hi); } /* * Active PHY's Macro operation to write DFE * TAP from RAM, and wait for Macro to complete. */ bge_mii_put16(bgep, 0x16, 0x0202); bge_phy_macro_wait(bgep); /* * Done with write phase, now begin read phase. */ /* Select channel and set TAP index to 0 */ bge_mii_put16(bgep, 0x17, (chan << 13) | 0x0200); /* * Active PHY's Macro operation to load DFE * TAP to RAM, and wait for Macro to complete */ bge_mii_put16(bgep, 0x16, 0x0082); bge_phy_macro_wait(bgep); /* Enable "pre-fetch" */ bge_mii_put16(bgep, 0x16, 0x0802); bge_phy_macro_wait(bgep); /* * Read back the TAP values. 3 TAPs for each * channel, each TAP have 2 WORDs (LO/HI) */ for (tap = 0; tap < N_TAPS; ++tap) { /* * Read Lo/Hi then wait for 'done' is faster. * For DFE TAP, the HI word contains 6 bits, * LO word contains 15 bits */ dataLo = bge_mii_get16(bgep, 0x15) & 0x7fff; dataHi = bge_mii_get16(bgep, 0x15) & 0x003f; bge_phy_macro_wait(bgep); /* * Check if what we wrote is what we read back. * If failed, then the PHY is locked up, we need * to do PHY reset again */ if (dataLo != tap_data[chan][tap].lo) return (B_TRUE); /* wedged! */ if (dataHi != tap_data[chan][tap].hi) return (B_TRUE); /* wedged! */ } } /* * The PHY isn't locked up ;-) */ return (B_FALSE); }
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); }