/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "rge.h"
#define RGE_DBG RGE_DBG_STATS /* debug flag for this code */
/*
* Local datatype for defining tables of (Offset, Name) pairs
*/
typedef struct {
offset_t index;
char *name;
} rge_ksindex_t;
static const rge_ksindex_t rge_driverinfo[] = {
{ 0, "rx_ring_addr" },
{ 1, "rx_next" },
{ 2, "rx_free" },
{ 3, "rx_bcopy" },
{ 4, "tx_ring_addr" },
{ 5, "tx_next" },
{ 6, "tx_free" },
{ 7, "tx_flow" },
{ 8, "resched_needed" },
{ 9, "watchdog" },
{ 10, "rx_config" },
{ 11, "tx_config" },
{ 12, "mac_ver" },
{ 13, "phy_ver" },
{ 14, "chip_reset" },
{ 15, "phy_reset" },
{ 16, "loop_mode" },
{ -1, NULL }
};
static int
rge_driverinfo_update(kstat_t *ksp, int flag)
{
rge_t *rgep;
kstat_named_t *knp;
if (flag != KSTAT_READ)
return (EACCES);
rgep = ksp->ks_private;
knp = ksp->ks_data;
(knp++)->value.ui64 = rgep->dma_area_rxdesc.cookie.dmac_laddress;
(knp++)->value.ui64 = rgep->rx_next;
(knp++)->value.ui64 = rgep->rx_free;
(knp++)->value.ui64 = rgep->rx_bcopy;
(knp++)->value.ui64 = rgep->dma_area_txdesc.cookie.dmac_laddress;
(knp++)->value.ui64 = rgep->tx_next;
(knp++)->value.ui64 = rgep->tx_free;
(knp++)->value.ui64 = rgep->tx_flow;
(knp++)->value.ui64 = rgep->resched_needed;
(knp++)->value.ui64 = rgep->watchdog;
(knp++)->value.ui64 = rgep->chipid.rxconfig;
(knp++)->value.ui64 = rgep->chipid.txconfig;
(knp++)->value.ui64 = rgep->chipid.mac_ver;
(knp++)->value.ui64 = rgep->chipid.phy_ver;
(knp++)->value.ui64 = rgep->stats.chip_reset;
(knp++)->value.ui64 = rgep->stats.phy_reset;
(knp++)->value.ui64 = rgep->param_loop_mode;
return (0);
}
static kstat_t *
rge_setup_named_kstat(rge_t *rgep, int instance, char *name,
const rge_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
{
kstat_t *ksp;
kstat_named_t *knp;
char *np;
int type;
size /= sizeof (rge_ksindex_t);
ksp = kstat_create(RGE_DRIVER_NAME, instance, name, "net",
KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
if (ksp == NULL)
return (NULL);
ksp->ks_private = rgep;
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);
}
void
rge_init_kstats(rge_t *rgep, int instance)
{
rgep->rge_kstats[RGE_KSTAT_DRIVER] = rge_setup_named_kstat(rgep,
instance, "driverinfo", rge_driverinfo,
sizeof (rge_driverinfo), rge_driverinfo_update);
}
void
rge_fini_kstats(rge_t *rgep)
{
int i;
for (i = RGE_KSTAT_COUNT; --i >= 0; )
if (rgep->rge_kstats[i] != NULL) {
kstat_delete(rgep->rge_kstats[i]);
}
}
int
rge_m_stat(void *arg, uint_t stat, uint64_t *val)
{
rge_t *rgep = arg;
rge_hw_stats_t *bstp;
mutex_enter(rgep->genlock);
rge_hw_stats_dump(rgep);
mutex_exit(rgep->genlock);
bstp = rgep->hw_stats;
switch (stat) {
case MAC_STAT_IFSPEED:
*val = rgep->param_link_speed * 1000000ull;
break;
case MAC_STAT_MULTIRCV:
*val = RGE_BSWAP_32(bstp->multi_rcv);
break;
case MAC_STAT_BRDCSTRCV:
*val = RGE_BSWAP_64(bstp->brdcst_rcv);
break;
case MAC_STAT_NORCVBUF:
*val = RGE_BSWAP_16(bstp->in_discards);
break;
case MAC_STAT_IERRORS:
*val = RGE_BSWAP_32(bstp->rcv_err);
break;
case MAC_STAT_OERRORS:
*val = RGE_BSWAP_64(bstp->xmt_err);
break;
case MAC_STAT_COLLISIONS:
*val = RGE_BSWAP_32(bstp->xmt_1col + bstp->xmt_mcol);
break;
case MAC_STAT_RBYTES:
*val = rgep->stats.rbytes;
break;
case MAC_STAT_IPACKETS:
*val = RGE_BSWAP_64(bstp->rcv_ok);
break;
case MAC_STAT_OBYTES:
*val = rgep->stats.obytes;
break;
case MAC_STAT_OPACKETS:
*val = RGE_BSWAP_64(bstp->xmt_ok);
break;
case ETHER_STAT_ALIGN_ERRORS:
*val = RGE_BSWAP_16(bstp->frame_err);
break;
case ETHER_STAT_FIRST_COLLISIONS:
*val = RGE_BSWAP_32(bstp->xmt_1col);
break;
case ETHER_STAT_MULTI_COLLISIONS:
*val = RGE_BSWAP_32(bstp->xmt_mcol);
break;
case ETHER_STAT_DEFER_XMTS:
*val = rgep->stats.defer;
break;
case ETHER_STAT_XCVR_ADDR:
*val = rgep->phy_mii_addr;
break;
case ETHER_STAT_XCVR_ID:
mutex_enter(rgep->genlock);
*val = rge_mii_get16(rgep, MII_PHYIDH);
*val <<= 16;
*val |= rge_mii_get16(rgep, MII_PHYIDL);
mutex_exit(rgep->genlock);
break;
case ETHER_STAT_XCVR_INUSE:
*val = XCVR_1000T;
break;
case ETHER_STAT_CAP_1000FDX:
*val = 1;
break;
case ETHER_STAT_CAP_1000HDX:
*val = 0;
break;
case ETHER_STAT_CAP_100FDX:
*val = 1;
break;
case ETHER_STAT_CAP_100HDX:
*val = 1;
break;
case ETHER_STAT_CAP_10FDX:
*val = 1;
break;
case ETHER_STAT_CAP_10HDX:
*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;
case ETHER_STAT_ADV_CAP_1000FDX:
*val = rgep->param_adv_1000fdx;
break;
case ETHER_STAT_ADV_CAP_1000HDX:
*val = rgep->param_adv_1000hdx;
break;
case ETHER_STAT_ADV_CAP_100FDX:
*val = rgep->param_adv_100fdx;
break;
case ETHER_STAT_ADV_CAP_100HDX:
*val = rgep->param_adv_100hdx;
break;
case ETHER_STAT_ADV_CAP_10FDX:
*val = rgep->param_adv_10fdx;
break;
case ETHER_STAT_ADV_CAP_10HDX:
*val = rgep->param_adv_10hdx;
break;
case ETHER_STAT_ADV_CAP_ASMPAUSE:
*val = rgep->param_adv_asym_pause;
break;
case ETHER_STAT_ADV_CAP_PAUSE:
*val = rgep->param_adv_pause;
break;
case ETHER_STAT_ADV_CAP_AUTONEG:
*val = rgep->param_adv_autoneg;
break;
case ETHER_STAT_LINK_DUPLEX:
*val = rgep->param_link_duplex;
break;
default:
return (ENOTSUP);
}
return (0);
}