bge_kstats.c revision 8eb6c4f9472d7b6f007c889f8e14385510452918
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "sys/bge_impl.h"
#define BGE_DBG BGE_DBG_STATS /* debug flag for this code */
/*
* Type of transceiver currently in use. The IEEE 802.3 std aPhyType
* enumerates the following set
*/
enum xcvr_type {
XCVR_TYPE_UNDEFINED = 0, /* 0 = undefined, or not yet known */
XCVR_TYPE_NONE, /* 1= MII present & nothing connected */
XCVR_TYPE_10BASE_T, /* 2 = 10 Mbps copper */
XCVR_TYPE_100BASE_T4, /* 3 = 10 Mbps copper */
XCVR_TYPE_100BASE_X, /* 4 = 100 Mbps copper */
XCVR_TYPE_100BASE_T2, /* 5 = 100 Mbps copper */
XCVR_TYPE_1000BASE_X, /* 6 = 1000 Mbps SerDes */
XCVR_TYPE_1000BASE_T /* 7 = 1000 Mbps copper */
};
/*
* Local datatype for defining tables of (Offset, Name) pairs
*/
typedef struct {
offset_t index;
char *name;
} bge_ksindex_t;
/*
* Table of Hardware-defined Statistics Block Offsets and Names
*/
#define KS_NAME(s) { KS_ ## s, #s }
static const bge_ksindex_t bge_statistics[] = {
KS_NAME(ifHCInOctets),
KS_NAME(etherStatsFragments),
KS_NAME(ifHCInUcastPkts),
KS_NAME(ifHCInMulticastPkts),
KS_NAME(ifHCInBroadcastPkts),
KS_NAME(dot3StatsFCSErrors),
KS_NAME(dot3StatsAlignmentErrors),
KS_NAME(xonPauseFramesReceived),
KS_NAME(xoffPauseFramesReceived),
KS_NAME(macControlFramesReceived),
KS_NAME(xoffStateEntered),
KS_NAME(dot3StatsFrameTooLongs),
KS_NAME(etherStatsJabbers),
KS_NAME(etherStatsUndersizePkts),
KS_NAME(inRangeLengthError),
KS_NAME(outRangeLengthError),
KS_NAME(etherStatsPkts64Octets),
KS_NAME(etherStatsPkts65to127Octets),
KS_NAME(etherStatsPkts128to255Octets),
KS_NAME(etherStatsPkts256to511Octets),
KS_NAME(etherStatsPkts512to1023Octets),
KS_NAME(etherStatsPkts1024to1518Octets),
KS_NAME(etherStatsPkts1519to2047Octets),
KS_NAME(etherStatsPkts2048to4095Octets),
KS_NAME(etherStatsPkts4096to8191Octets),
KS_NAME(etherStatsPkts8192to9022Octets),
KS_NAME(ifHCOutOctets),
KS_NAME(etherStatsCollisions),
KS_NAME(outXonSent),
KS_NAME(outXoffSent),
KS_NAME(flowControlDone),
KS_NAME(dot3StatsInternalMacTransmitErrors),
KS_NAME(dot3StatsSingleCollisionFrames),
KS_NAME(dot3StatsMultipleCollisionFrames),
KS_NAME(dot3StatsDeferredTransmissions),
KS_NAME(dot3StatsExcessiveCollisions),
KS_NAME(dot3StatsLateCollisions),
KS_NAME(dot3Collided2Times),
KS_NAME(dot3Collided3Times),
KS_NAME(dot3Collided4Times),
KS_NAME(dot3Collided5Times),
KS_NAME(dot3Collided6Times),
KS_NAME(dot3Collided7Times),
KS_NAME(dot3Collided8Times),
KS_NAME(dot3Collided9Times),
KS_NAME(dot3Collided10Times),
KS_NAME(dot3Collided11Times),
KS_NAME(dot3Collided12Times),
KS_NAME(dot3Collided13Times),
KS_NAME(dot3Collided14Times),
KS_NAME(dot3Collided15Times),
KS_NAME(ifHCOutUcastPkts),
KS_NAME(ifHCOutMulticastPkts),
KS_NAME(ifHCOutBroadcastPkts),
KS_NAME(dot3StatsCarrierSenseErrors),
KS_NAME(ifOutDiscards),
KS_NAME(ifOutErrors),
KS_NAME(COSIfHCInPkts_1),
KS_NAME(COSIfHCInPkts_2),
KS_NAME(COSIfHCInPkts_3),
KS_NAME(COSIfHCInPkts_4),
KS_NAME(COSIfHCInPkts_5),
KS_NAME(COSIfHCInPkts_6),
KS_NAME(COSIfHCInPkts_7),
KS_NAME(COSIfHCInPkts_8),
KS_NAME(COSIfHCInPkts_9),
KS_NAME(COSIfHCInPkts_10),
KS_NAME(COSIfHCInPkts_11),
KS_NAME(COSIfHCInPkts_12),
KS_NAME(COSIfHCInPkts_13),
KS_NAME(COSIfHCInPkts_14),
KS_NAME(COSIfHCInPkts_15),
KS_NAME(COSIfHCInPkts_16),
KS_NAME(COSFramesDroppedDueToFilters),
KS_NAME(nicDmaWriteQueueFull),
KS_NAME(nicDmaWriteHighPriQueueFull),
KS_NAME(nicNoMoreRxBDs),
KS_NAME(ifInDiscards),
KS_NAME(ifInErrors),
KS_NAME(nicRecvThresholdHit),
KS_NAME(COSIfHCOutPkts_1),
KS_NAME(COSIfHCOutPkts_2),
KS_NAME(COSIfHCOutPkts_3),
KS_NAME(COSIfHCOutPkts_4),
KS_NAME(COSIfHCOutPkts_5),
KS_NAME(COSIfHCOutPkts_6),
KS_NAME(COSIfHCOutPkts_7),
KS_NAME(COSIfHCOutPkts_8),
KS_NAME(COSIfHCOutPkts_9),
KS_NAME(COSIfHCOutPkts_10),
KS_NAME(COSIfHCOutPkts_11),
KS_NAME(COSIfHCOutPkts_12),
KS_NAME(COSIfHCOutPkts_13),
KS_NAME(COSIfHCOutPkts_14),
KS_NAME(COSIfHCOutPkts_15),
KS_NAME(COSIfHCOutPkts_16),
KS_NAME(nicDmaReadQueueFull),
KS_NAME(nicDmaReadHighPriQueueFull),
KS_NAME(nicSendDataCompQueueFull),
KS_NAME(nicRingSetSendProdIndex),
KS_NAME(nicRingStatusUpdate),
KS_NAME(nicInterrupts),
KS_NAME(nicAvoidedInterrupts),
KS_NAME(nicSendThresholdHit),
{ KS_STATS_SIZE, NULL }
};
static const bge_ksindex_t bge_stat_val[] = {
KS_NAME(ifHCOutOctets),
KS_NAME(etherStatsCollisions),
KS_NAME(outXonSent),
KS_NAME(outXoffSent),
KS_NAME(dot3StatsInternalMacTransmitErrors),
KS_NAME(dot3StatsSingleCollisionFrames),
KS_NAME(dot3StatsMultipleCollisionFrames),
KS_NAME(dot3StatsDeferredTransmissions),
KS_NAME(dot3StatsExcessiveCollisions),
KS_NAME(dot3StatsLateCollisions),
KS_NAME(ifHCOutUcastPkts),
KS_NAME(ifHCOutMulticastPkts),
KS_NAME(ifHCOutBroadcastPkts),
KS_NAME(ifHCInOctets),
KS_NAME(etherStatsFragments),
KS_NAME(ifHCInUcastPkts),
KS_NAME(ifHCInMulticastPkts),
KS_NAME(ifHCInBroadcastPkts),
KS_NAME(dot3StatsFCSErrors),
KS_NAME(dot3StatsAlignmentErrors),
KS_NAME(xonPauseFramesReceived),
KS_NAME(xoffPauseFramesReceived),
KS_NAME(macControlFramesReceived),
KS_NAME(xoffStateEntered),
KS_NAME(dot3StatsFrameTooLongs),
KS_NAME(etherStatsJabbers),
KS_NAME(etherStatsUndersizePkts),
{ KS_STAT_REG_SIZE, NULL }
};
static int
bge_statistics_update(kstat_t *ksp, int flag)
{
bge_t *bgep;
bge_statistics_t *bstp;
kstat_named_t *knp;
const bge_ksindex_t *ksip;
if (flag != KSTAT_READ)
return (EACCES);
bgep = ksp->ks_private;
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
bstp = DMA_VPTR(bgep->statistics);
knp = ksp->ks_data;
/*
* Transfer the statistics values from the copy that the
* chip updates via DMA to the named-kstat structure.
*
* As above, we don't bother to sync or stop updates to the
* statistics, 'cos it doesn't really matter if they're a few
* microsends out of date or less than 100% consistent ...
*/
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
for (ksip = bge_statistics; ksip->name != NULL; ++knp, ++ksip)
knp->value.ui64 = bstp->a[ksip->index];
else {
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCOutOctets);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.etherStatsCollisions);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.outXonSent);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.outXoffSent);
(knp++)->value.ui64 =
(uint64_t)(bgep->
stat_val.dot3StatsInternalMacTransmitErrors);
(knp++)->value.ui64 =
(uint64_t)(bgep->
stat_val.dot3StatsSingleCollisionFrames);
(knp++)->value.ui64 =
(uint64_t)(bgep->
stat_val.dot3StatsMultipleCollisionFrames);
(knp++)->value.ui64 =
(uint64_t)(bgep->
stat_val.dot3StatsDeferredTransmissions);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.dot3StatsExcessiveCollisions);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.dot3StatsLateCollisions);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCOutUcastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCOutMulticastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCOutBroadcastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCInOctets);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.etherStatsFragments);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCInUcastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCInMulticastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.ifHCInBroadcastPkts);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.dot3StatsFCSErrors);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.dot3StatsAlignmentErrors);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.xonPauseFramesReceived);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.xoffPauseFramesReceived);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.macControlFramesReceived);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.xoffStateEntered);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.dot3StatsFrameTooLongs);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.etherStatsJabbers);
(knp++)->value.ui64 =
(uint64_t)(bgep->stat_val.etherStatsUndersizePkts);
}
return (0);
}
static int
bge_params_update(kstat_t *ksp, int flag)
{
bge_t *bgep;
kstat_named_t *knp;
int i;
if (flag != KSTAT_READ)
return (EACCES);
bgep = ksp->ks_private;
for (knp = ksp->ks_data, i = 0; i < PARAM_COUNT; ++knp, ++i)
knp->value.ui64 = bgep->nd_params[i].ndp_val;
return (0);
}
static const bge_ksindex_t bge_chipid[] = {
{ 0, "asic_rev" },
{ 1, "businfo" },
{ 2, "command" },
{ 3, "vendor_id" },
{ 4, "device_id" },
{ 5, "subsystem_vendor_id" },
{ 6, "subsystem_device_id" },
{ 7, "revision_id" },
{ 8, "cache_line_size" },
{ 9, "latency_timer" },
{ 10, "flags" },
{ 11, "chip_type" },
{ 12, "mbuf_base" },
{ 13, "mbuf_count" },
{ 14, "hw_mac_addr" },
{ 15, "&bus_type" },
{ 16, "&bus_speed" },
{ 17, "&bus_size" },
{ 18, "&supported" },
{ 19, "&interface" },
{ -1, NULL }
};
static void
bge_set_char_kstat(kstat_named_t *knp, const char *s)
{
(void) strncpy(knp->value.c, s, sizeof (knp->value.c));
}
static int
bge_chipid_update(kstat_t *ksp, int flag)
{
bge_t *bgep;
kstat_named_t *knp;
uint64_t tmp;
if (flag != KSTAT_READ)
return (EACCES);
bgep = ksp->ks_private;
knp = ksp->ks_data;
(knp++)->value.ui64 = bgep->chipid.asic_rev;
(knp++)->value.ui64 = bgep->chipid.businfo;
(knp++)->value.ui64 = bgep->chipid.command;
(knp++)->value.ui64 = bgep->chipid.vendor;
(knp++)->value.ui64 = bgep->chipid.device;
(knp++)->value.ui64 = bgep->chipid.subven;
(knp++)->value.ui64 = bgep->chipid.subdev;
(knp++)->value.ui64 = bgep->chipid.revision;
(knp++)->value.ui64 = bgep->chipid.clsize;
(knp++)->value.ui64 = bgep->chipid.latency;
(knp++)->value.ui64 = bgep->chipid.flags;
(knp++)->value.ui64 = bgep->chipid.chip_label;
(knp++)->value.ui64 = bgep->chipid.mbuf_base;
(knp++)->value.ui64 = bgep->chipid.mbuf_length;
(knp++)->value.ui64 = bgep->chipid.hw_mac_addr;
/*
* Now we interpret some of the above into readable strings
*/
tmp = bgep->chipid.businfo;
bge_set_char_kstat(knp++,
tmp & PCISTATE_BUS_IS_PCI ? "PCI" : "PCI-X");
bge_set_char_kstat(knp++,
tmp & PCISTATE_BUS_IS_FAST ? "fast" : "normal");
bge_set_char_kstat(knp++,
tmp & PCISTATE_BUS_IS_32_BIT ? "32 bit" : "64 bit");
tmp = bgep->chipid.flags;
bge_set_char_kstat(knp++,
tmp & CHIP_FLAG_SUPPORTED ? "yes" : "no");
bge_set_char_kstat(knp++,
tmp & CHIP_FLAG_SERDES ? "serdes" : "copper");
return (0);
}
static const bge_ksindex_t bge_driverinfo[] = {
{ 0, "rx_buff_addr" },
{ 1, "tx_buff_addr" },
{ 2, "rx_desc_addr" },
{ 3, "tx_desc_addr" },
{ 4, "tx_desc_free" },
{ 5, "resched_needed" },
{ 6, "watchdog" },
{ 7, "chip_resets" },
{ 8, "dma_misses" },
{ 9, "misc_host_config" },
{ 10, "dma_rw_control" },
{ 11, "pci_bus_info" },
{ 12, "buff_mgr_status" },
{ 13, "rcv_init_status" },
{ -1, NULL }
};
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;
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->resched_needed;
(knp++)->value.ui64 = bgep->watchdog;
(knp++)->value.ui64 = bgep->chip_resets;
(knp++)->value.ui64 = bgep->missed_dmas;
/*
* 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);
(knp++)->value.ui64 = bge_reg_get32(bgep, BUFFER_MANAGER_STATUS_REG);
(knp++)->value.ui64 = bge_reg_get32(bgep, RCV_INITIATOR_STATUS_REG);
mutex_exit(bgep->genlock);
return (0);
}
static const bge_ksindex_t bge_mii_kstats[] = {
{ 0, "%xcvr_addr" },
{ 1, "%xcvr_id" },
{ 2, "%xcvr_inuse" },
{ 3, "%cap_1000fdx" },
{ 4, "%cap_1000hdx" },
{ 5, "%cap_100fdx" },
{ 6, "%cap_100hdx" },
{ 7, "%cap_10fdx" },
{ 8, "%cap_10hdx" },
{ 9, "%cap_asmpause" },
{ 10, "%cap_pause" },
{ 11, "%cap_rem_fault" },
{ 12, "%cap_autoneg" },
{ 13, "%adv_cap_1000fdx" },
{ 14, "%adv_cap_1000hdx" },
{ 15, "%adv_cap_100fdx" },
{ 16, "%adv_cap_100hdx" },
{ 17, "%adv_cap_10fdx" },
{ 18, "%adv_cap_10hdx" },
{ 19, "%adv_cap_asmpause" },
{ 20, "%adv_cap_pause" },
{ 21, "%adv_rem_fault" },
{ 22, "%adv_cap_autoneg" },
{ 23, "%lp_cap_1000fdx" },
{ 24, "%lp_cap_1000hdx" },
{ 25, "%lp_cap_100fdx" },
{ 26, "%lp_cap_100hdx" },
{ 27, "%lp_cap_10fdx" },
{ 28, "%lp_cap_10hdx" },
{ 29, "%lp_cap_asmpause" },
{ 30, "%lp_cap_pause" },
{ 31, "%lp_rem_fault" },
{ 32, "%lp_cap_autoneg" },
{ 33, "%link_asmpause" },
{ 34, "%link_pause" },
{ 35, "%link_duplex" },
{ 36, "%link_up" },
{ -1, NULL }
};
/*
* Derive and publish the standard "mii" kstats.
*
* The information required is somewhat scattered: some is already held
* in driver softstate, some is available in the MII registers, and some
* has to be computed from combinations of both ...
*/
static int
bge_mii_update(kstat_t *ksp, int flag)
{
bge_t *bgep;
kstat_named_t *knp;
uint16_t anlpar;
uint16_t anar;
uint32_t xcvr_id;
uint32_t xcvr_inuse;
boolean_t asym_pause;
if (flag != KSTAT_READ)
return (EACCES);
bgep = ksp->ks_private;
knp = ksp->ks_data;
/*
* Read all the relevant PHY registers
*/
mutex_enter(bgep->genlock);
anlpar = bge_mii_get16(bgep, MII_AN_LPABLE);
anar = bge_mii_get16(bgep, MII_AN_ADVERT);
/*
* Derive PHY characterisation parameters
*/
xcvr_id = bge_mii_get16(bgep, MII_PHYIDH);
xcvr_id <<= 16;
xcvr_id |= bge_mii_get16(bgep, MII_PHYIDL);
mutex_exit(bgep->genlock);
switch (bgep->param_link_speed) {
case 1000:
if (bgep->chipid.flags & CHIP_FLAG_SERDES)
xcvr_inuse = XCVR_TYPE_1000BASE_X;
else
xcvr_inuse = XCVR_TYPE_1000BASE_T;
break;
case 100:
xcvr_inuse = XCVR_TYPE_100BASE_X;
break;
case 10:
xcvr_inuse = XCVR_TYPE_10BASE_T;
break;
default:
xcvr_inuse = XCVR_TYPE_UNDEFINED;
break;
}
/*
* Other miscellaneous transformations ...
*/
asym_pause = bgep->param_link_rx_pause != bgep->param_link_tx_pause;
/*
* All required values are now available; assign them to the
* actual kstats, in the sequence defined by the table above.
*/
(knp++)->value.ui32 = bgep->phy_mii_addr;
(knp++)->value.ui32 = xcvr_id;
(knp++)->value.ui32 = xcvr_inuse;
/*
* Our capabilities
*/
(knp++)->value.ui32 = bgep->nd_params[PARAM_1000FDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_1000HDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_100FDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_100HDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_10FDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_10HDX_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_ASYM_PAUSE_CAP].ndp_val;
(knp++)->value.ui32 = bgep->nd_params[PARAM_PAUSE_CAP].ndp_val;
(knp++)->value.ui32 = B_TRUE;
(knp++)->value.ui32 = bgep->nd_params[PARAM_AUTONEG_CAP].ndp_val;
/*
* Our *advertised* capabilities
*/
(knp++)->value.ui32 = bgep->param_adv_1000fdx;
(knp++)->value.ui32 = bgep->param_adv_1000hdx;
(knp++)->value.ui32 = bgep->param_adv_100fdx;
(knp++)->value.ui32 = bgep->param_adv_100hdx;
(knp++)->value.ui32 = bgep->param_adv_10fdx;
(knp++)->value.ui32 = bgep->param_adv_10hdx;
(knp++)->value.ui32 = bgep->param_adv_asym_pause;
(knp++)->value.ui32 = bgep->param_adv_pause;
(knp++)->value.ui32 = (anar & MII_AN_ADVERT_REMFAULT) ? 1 : 0;
(knp++)->value.ui32 = bgep->param_adv_autoneg;
/*
* Link Partner's advertised capabilities
*/
(knp++)->value.ui32 = bgep->param_lp_1000fdx;
(knp++)->value.ui32 = bgep->param_lp_1000hdx;
(knp++)->value.ui32 = bgep->param_lp_100fdx;
(knp++)->value.ui32 = bgep->param_lp_100hdx;
(knp++)->value.ui32 = bgep->param_lp_10fdx;
(knp++)->value.ui32 = bgep->param_lp_10hdx;
(knp++)->value.ui32 = bgep->param_lp_asym_pause;
(knp++)->value.ui32 = bgep->param_lp_pause;
(knp++)->value.ui32 = (anlpar & MII_AN_ADVERT_REMFAULT) ? 1 : 0;
(knp++)->value.ui32 = bgep->param_lp_autoneg;
/*
* Current operating modes
*/
(knp++)->value.ui32 = asym_pause;
(knp++)->value.ui32 = bgep->param_link_rx_pause;
(knp++)->value.ui32 = bgep->param_link_duplex;
(knp++)->value.ui32 = bgep->param_link_up;
return (0);
}
static const bge_ksindex_t bge_serdes[] = {
{ 0, "serdes_status" },
{ 1, "serdes_advert" },
{ 2, "serdes_lpadv" },
{ -1, NULL }
};
static int
bge_serdes_update(kstat_t *ksp, int flag)
{
bge_t *bgep;
kstat_named_t *knp;
if (flag != KSTAT_READ)
return (EACCES);
bgep = ksp->ks_private;
knp = ksp->ks_data;
(knp++)->value.ui64 = bgep->serdes_status;
(knp++)->value.ui64 = bgep->serdes_advert;
(knp++)->value.ui64 = bgep->serdes_lpadv;
return (0);
}
static const bge_ksindex_t bge_phydata[] = {
{ MII_CONTROL, "mii_control" },
{ MII_STATUS, "mii_status" },
{ MII_PHYIDH, "phy_identifier" },
{ MII_AN_ADVERT, "an_advert" },
{ MII_AN_LPABLE, "an_lp_ability" },
{ MII_AN_EXPANSION, "an_expansion" },
{ MII_AN_LPNXTPG, "an_lp_nextpage" },
{ MII_1000BASE_T_CONTROL, "gbit_control" },
{ MII_1000BASE_T_STATUS, "gbit_status" },
{ MII_IEEE_EXT_STATUS, "ieee_ext_status" },
{ MII_EXT_CONTROL, "phy_ext_control" },
{ MII_EXT_STATUS, "phy_ext_status" },
{ MII_RCV_ERR_COUNT, "receive_error_count" },
{ MII_FALSE_CARR_COUNT, "false_carrier_count" },
{ MII_RCV_NOT_OK_COUNT, "receiver_not_ok_count" },
{ MII_AUX_CONTROL, "aux_control" },
{ MII_AUX_STATUS, "aux_status" },
{ MII_INTR_STATUS, "intr_status" },
{ MII_INTR_MASK, "intr_mask" },
{ MII_HCD_STATUS, "hcd_status" },
{ -1, NULL }
};
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;
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;
default:
knp->value.ui64 = bge_mii_get16(bgep, ksip->index);
break;
}
mutex_exit(bgep->genlock);
}
return (0);
}
static kstat_t *
bge_setup_named_kstat(bge_t *bgep, int instance, char *name,
const bge_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
{
kstat_t *ksp;
kstat_named_t *knp;
char *np;
int type;
size /= sizeof (bge_ksindex_t);
ksp = kstat_create(BGE_DRIVER_NAME, instance, name, "net",
KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
if (ksp == NULL)
return (NULL);
ksp->ks_private = bgep;
ksp->ks_update = update;
for (knp = ksp->ks_data; (np = ksip->name) != NULL; ++knp, ++ksip) {
switch (*np) {
default:
type = KSTAT_DATA_UINT64;
break;
case '%':
np += 1;
type = KSTAT_DATA_UINT32;
break;
case '$':
np += 1;
type = KSTAT_DATA_STRING;
break;
case '&':
np += 1;
type = KSTAT_DATA_CHAR;
break;
}
kstat_named_init(knp, np, type);
}
kstat_install(ksp);
return (ksp);
}
/*
* Create kstats corresponding to NDD parameters
*/
static kstat_t *
bge_setup_params_kstat(bge_t *bgep, int instance, char *name,
int (*update)(kstat_t *, int))
{
kstat_t *ksp;
kstat_named_t *knp;
int i;
ksp = kstat_create(BGE_DRIVER_NAME, instance, name, "net",
KSTAT_TYPE_NAMED, PARAM_COUNT, KSTAT_FLAG_PERSISTENT);
if (ksp != NULL) {
ksp->ks_private = bgep;
ksp->ks_update = update;
for (knp = ksp->ks_data, i = 0; i < PARAM_COUNT; ++knp, ++i)
kstat_named_init(knp, bgep->nd_params[i].ndp_name+1,
KSTAT_DATA_UINT64);
kstat_install(ksp);
}
return (ksp);
}
void
bge_init_kstats(bge_t *bgep, int instance)
{
kstat_t *ksp;
BGE_TRACE(("bge_init_kstats($%p, %d)", (void *)bgep, instance));
if (bgep->chipid.statistic_type == BGE_STAT_BLK) {
DMA_ZERO(bgep->statistics);
bgep->bge_kstats[BGE_KSTAT_RAW] = ksp =
kstat_create(BGE_DRIVER_NAME, instance,
"raw_statistics", "net", KSTAT_TYPE_RAW,
sizeof (bge_statistics_t), KSTAT_FLAG_VIRTUAL);
if (ksp != NULL) {
ksp->ks_data = DMA_VPTR(bgep->statistics);
kstat_install(ksp);
}
bgep->bge_kstats[BGE_KSTAT_STATS] = bge_setup_named_kstat(bgep,
instance, "statistics", bge_statistics,
sizeof (bge_statistics), bge_statistics_update);
} else {
bgep->bge_kstats[BGE_KSTAT_STATS] = bge_setup_named_kstat(bgep,
instance, "statistics", bge_stat_val,
sizeof (bge_stat_val), bge_statistics_update);
}
bgep->bge_kstats[BGE_KSTAT_CHIPID] = bge_setup_named_kstat(bgep,
instance, "chipid", bge_chipid,
sizeof (bge_chipid), bge_chipid_update);
bgep->bge_kstats[BGE_KSTAT_DRIVER] = bge_setup_named_kstat(bgep,
instance, "driverinfo", bge_driverinfo,
sizeof (bge_driverinfo), bge_driverinfo_update);
bgep->bge_kstats[BGE_KSTAT_MII] = bge_setup_named_kstat(bgep,
instance, "mii", bge_mii_kstats,
sizeof (bge_mii_kstats), bge_mii_update);
if (bgep->chipid.flags & CHIP_FLAG_SERDES)
bgep->bge_kstats[BGE_KSTAT_PHYS] = bge_setup_named_kstat(bgep,
instance, "serdes", bge_serdes,
sizeof (bge_serdes), bge_serdes_update);
else
bgep->bge_kstats[BGE_KSTAT_PHYS] = bge_setup_named_kstat(bgep,
instance, "phydata", bge_phydata,
sizeof (bge_phydata), bge_phydata_update);
bgep->bge_kstats[BGE_KSTAT_PARAMS] = bge_setup_params_kstat(bgep,
instance, "parameters", bge_params_update);
}
void
bge_fini_kstats(bge_t *bgep)
{
int i;
BGE_TRACE(("bge_fini_kstats($%p)", (void *)bgep));
for (i = BGE_KSTAT_COUNT; --i >= 0; )
if (bgep->bge_kstats[i] != NULL)
kstat_delete(bgep->bge_kstats[i]);
}
uint64_t
bge_m_stat(void *arg, enum mac_stat stat)
{
bge_t *bgep = arg;
bge_statistics_t *bstp;
uint64_t val;
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
bstp = DMA_VPTR(bgep->statistics);
else {
bgep->stat_val.ifHCOutOctets +=
bge_reg_get32(bgep, STAT_IFHCOUT_OCTETS_REG);
bgep->stat_val.etherStatsCollisions +=
bge_reg_get32(bgep, STAT_ETHER_COLLIS_REG);
bgep->stat_val.outXonSent +=
bge_reg_get32(bgep, STAT_OUTXON_SENT_REG);
bgep->stat_val.outXoffSent +=
bge_reg_get32(bgep, STAT_OUTXOFF_SENT_REG);
bgep->stat_val.dot3StatsInternalMacTransmitErrors +=
bge_reg_get32(bgep, STAT_DOT3_INTMACTX_ERR_REG);
bgep->stat_val.dot3StatsSingleCollisionFrames +=
bge_reg_get32(bgep, STAT_DOT3_SCOLLI_FRAME_REG);
bgep->stat_val.dot3StatsMultipleCollisionFrames +=
bge_reg_get32(bgep, STAT_DOT3_MCOLLI_FRAME_REG);
bgep->stat_val.dot3StatsDeferredTransmissions +=
bge_reg_get32(bgep, STAT_DOT3_DEFERED_TX_REG);
bgep->stat_val.dot3StatsExcessiveCollisions +=
bge_reg_get32(bgep, STAT_DOT3_EXCE_COLLI_REG);
bgep->stat_val.dot3StatsLateCollisions +=
bge_reg_get32(bgep, STAT_DOT3_LATE_COLLI_REG);
bgep->stat_val.ifHCOutUcastPkts +=
bge_reg_get32(bgep, STAT_IFHCOUT_UPKGS_REG);
bgep->stat_val.ifHCOutMulticastPkts +=
bge_reg_get32(bgep, STAT_IFHCOUT_MPKGS_REG);
bgep->stat_val.ifHCOutBroadcastPkts +=
bge_reg_get32(bgep, STAT_IFHCOUT_BPKGS_REG);
bgep->stat_val.ifHCInOctets +=
bge_reg_get32(bgep, STAT_IFHCIN_OCTETS_REG);
bgep->stat_val.etherStatsFragments +=
bge_reg_get32(bgep, STAT_ETHER_FRAGMENT_REG);
bgep->stat_val.ifHCInUcastPkts +=
bge_reg_get32(bgep, STAT_IFHCIN_UPKGS_REG);
bgep->stat_val.ifHCInMulticastPkts +=
bge_reg_get32(bgep, STAT_IFHCIN_MPKGS_REG);
bgep->stat_val.ifHCInBroadcastPkts +=
bge_reg_get32(bgep, STAT_IFHCIN_BPKGS_REG);
bgep->stat_val.dot3StatsFCSErrors +=
bge_reg_get32(bgep, STAT_DOT3_FCS_ERR_REG);
bgep->stat_val.dot3StatsAlignmentErrors +=
bge_reg_get32(bgep, STAT_DOT3_ALIGN_ERR_REG);
bgep->stat_val.xonPauseFramesReceived +=
bge_reg_get32(bgep, STAT_XON_PAUSE_RX_REG);
bgep->stat_val.xoffPauseFramesReceived +=
bge_reg_get32(bgep, STAT_XOFF_PAUSE_RX_REG);
bgep->stat_val.macControlFramesReceived +=
bge_reg_get32(bgep, STAT_MAC_CTRL_RX_REG);
bgep->stat_val.xoffStateEntered +=
bge_reg_get32(bgep, STAT_XOFF_STATE_ENTER_REG);
bgep->stat_val.dot3StatsFrameTooLongs +=
bge_reg_get32(bgep, STAT_DOT3_FRAME_TOOLONG_REG);
bgep->stat_val.etherStatsJabbers +=
bge_reg_get32(bgep, STAT_ETHER_JABBERS_REG);
bgep->stat_val.etherStatsUndersizePkts +=
bge_reg_get32(bgep, STAT_ETHER_UNDERSIZE_REG);
}
switch (stat) {
case MAC_STAT_IFSPEED:
val = bgep->param_link_speed * 1000000ull;
break;
case MAC_STAT_MULTIRCV:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCInMulticastPkts;
else
val = bgep->stat_val.ifHCInMulticastPkts;
break;
case MAC_STAT_BRDCSTRCV:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCInBroadcastPkts;
else
val = bgep->stat_val.ifHCInBroadcastPkts;
break;
case MAC_STAT_MULTIXMT:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCOutMulticastPkts;
else
val = bgep->stat_val.ifHCOutMulticastPkts;
break;
case MAC_STAT_BRDCSTXMT:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCOutBroadcastPkts;
else
val = bgep->stat_val.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.ifInErrors;
else
val = 0;
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 = bgep->stat_val.etherStatsCollisions;
break;
case MAC_STAT_RBYTES:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCInOctets;
else
val = bgep->stat_val.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 = bgep->stat_val.ifHCInUcastPkts +
bgep->stat_val.ifHCInMulticastPkts +
bgep->stat_val.ifHCInBroadcastPkts;
break;
case MAC_STAT_OBYTES:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.ifHCOutOctets;
else
val = bgep->stat_val.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 = bgep->stat_val.ifHCOutUcastPkts +
bgep->stat_val.ifHCOutMulticastPkts +
bgep->stat_val.ifHCOutBroadcastPkts;
break;
case MAC_STAT_ALIGN_ERRORS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsAlignmentErrors;
else
val = bgep->stat_val.dot3StatsAlignmentErrors;
break;
case MAC_STAT_FCS_ERRORS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsFCSErrors;
else
val = bgep->stat_val.dot3StatsFCSErrors;
break;
case MAC_STAT_FIRST_COLLISIONS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsSingleCollisionFrames;
else
val = bgep->stat_val.dot3StatsSingleCollisionFrames;
break;
case MAC_STAT_MULTI_COLLISIONS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsMultipleCollisionFrames;
else
val = bgep->stat_val.dot3StatsMultipleCollisionFrames;
break;
case MAC_STAT_DEFER_XMTS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsDeferredTransmissions;
else
val = bgep->stat_val.dot3StatsDeferredTransmissions;
break;
case MAC_STAT_TX_LATE_COLLISIONS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsLateCollisions;
else
val = bgep->stat_val.dot3StatsLateCollisions;
break;
case MAC_STAT_EX_COLLISIONS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsExcessiveCollisions;
else
val = bgep->stat_val.dot3StatsExcessiveCollisions;
break;
case MAC_STAT_MACXMT_ERRORS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsInternalMacTransmitErrors;
else
val = bgep->stat_val.dot3StatsInternalMacTransmitErrors;
break;
case MAC_STAT_CARRIER_ERRORS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsCarrierSenseErrors;
else
val = 0;
break;
case MAC_STAT_TOOLONG_ERRORS:
if (bgep->chipid.statistic_type == BGE_STAT_BLK)
val = bstp->s.dot3StatsFrameTooLongs;
else
val = bgep->stat_val.dot3StatsFrameTooLongs;
break;
case MAC_STAT_XCVR_ADDR:
val = bgep->phy_mii_addr;
break;
case MAC_STAT_XCVR_ID:
mutex_enter(bgep->genlock);
val = bge_mii_get16(bgep, MII_PHYIDH);
val <<= 16;
val |= bge_mii_get16(bgep, MII_PHYIDL);
mutex_exit(bgep->genlock);
break;
case MAC_STAT_XCVR_INUSE:
val = XCVR_1000T;
break;
case MAC_STAT_CAP_1000FDX:
val = 1;
break;
case MAC_STAT_CAP_1000HDX:
val = 1;
break;
case MAC_STAT_CAP_100FDX:
val = 1;
break;
case MAC_STAT_CAP_100HDX:
val = 1;
break;
case MAC_STAT_CAP_10FDX:
val = 1;
break;
case MAC_STAT_CAP_10HDX:
val = 1;
break;
case MAC_STAT_CAP_ASMPAUSE:
val = 1;
break;
case MAC_STAT_CAP_PAUSE:
val = 1;
break;
case MAC_STAT_CAP_AUTONEG:
val = 1;
break;
case MAC_STAT_ADV_CAP_1000FDX:
val = bgep->param_adv_1000fdx;
break;
case MAC_STAT_ADV_CAP_1000HDX:
val = bgep->param_adv_1000hdx;
break;
case MAC_STAT_ADV_CAP_100FDX:
val = bgep->param_adv_100fdx;
break;
case MAC_STAT_ADV_CAP_100HDX:
val = bgep->param_adv_100hdx;
break;
case MAC_STAT_ADV_CAP_10FDX:
val = bgep->param_adv_10fdx;
break;
case MAC_STAT_ADV_CAP_10HDX:
val = bgep->param_adv_10hdx;
break;
case MAC_STAT_ADV_CAP_ASMPAUSE:
val = bgep->param_adv_asym_pause;
break;
case MAC_STAT_ADV_CAP_PAUSE:
val = bgep->param_adv_pause;
break;
case MAC_STAT_ADV_CAP_AUTONEG:
val = bgep->param_adv_autoneg;
break;
case MAC_STAT_LP_CAP_1000FDX:
val = bgep->param_lp_1000fdx;
break;
case MAC_STAT_LP_CAP_1000HDX:
val = bgep->param_lp_1000hdx;
break;
case MAC_STAT_LP_CAP_100FDX:
val = bgep->param_lp_100fdx;
break;
case MAC_STAT_LP_CAP_100HDX:
val = bgep->param_lp_100hdx;
break;
case MAC_STAT_LP_CAP_10FDX:
val = bgep->param_lp_10fdx;
break;
case MAC_STAT_LP_CAP_10HDX:
val = bgep->param_lp_10hdx;
break;
case MAC_STAT_LP_CAP_ASMPAUSE:
val = bgep->param_lp_asym_pause;
break;
case MAC_STAT_LP_CAP_PAUSE:
val = bgep->param_lp_pause;
break;
case MAC_STAT_LP_CAP_AUTONEG:
val = bgep->param_lp_autoneg;
break;
case MAC_STAT_LINK_ASMPAUSE:
val = bgep->param_adv_asym_pause &&
bgep->param_lp_asym_pause &&
bgep->param_adv_pause != bgep->param_lp_pause;
break;
case MAC_STAT_LINK_PAUSE:
val = bgep->param_link_rx_pause;
break;
case MAC_STAT_LINK_AUTONEG:
val = bgep->param_link_autoneg;
break;
case MAC_STAT_LINK_DUPLEX:
val = bgep->param_link_duplex;
break;
#ifdef DEBUG
default:
/*
* Shouldn't reach here...
*/
cmn_err(CE_PANIC,
"bge_m_stat: unrecognized parameter value = %d",
stat);
#endif
}
return (val);
}