afe.c revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac
/*
* Solaris driver for ethernet cards based on the ADMtek Centaur
*
* Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/ethernet.h>
#include <sys/mac_ether.h>
#include "afe.h"
#include "afeimpl.h"
/*
* Driver globals.
*/
/* table of supported devices */
static afe_card_t afe_cards[] = {
/*
* ADMtek Centaur and Comet
*/
/*
* Accton just relabels other companies' controllers
*/
/*
* Models listed here.
*/
};
/*
* Function prototypes
*/
static int afe_resume(dev_info_t *);
static int afe_quiesce(dev_info_t *);
static int afe_m_unicst(void *, const uint8_t *);
static int afe_m_promisc(void *, boolean_t);
static int afe_m_start(void *);
static void afe_m_stop(void *);
void *);
const void *);
static void afe_m_propinfo(void *, const char *, mac_prop_id_t,
static void afe_startmac(afe_t *);
static void afe_stopmac(afe_t *);
static void afe_resetrings(afe_t *);
static void afe_startall(afe_t *);
static void afe_stopall(afe_t *);
static void afe_resetall(afe_t *);
static void afe_destroytxbuf(afe_txbuf_t *);
static void afe_destroyrxbuf(afe_rxbuf_t *);
static int afe_allocrxring(afe_t *);
static void afe_freerxring(afe_t *);
static int afe_alloctxring(afe_t *);
static void afe_freetxring(afe_t *);
static void afe_error(dev_info_t *, char *, ...);
static void afe_setrxfilt(afe_t *);
static int afe_watchdog(afe_t *);
static void afe_readsrom(afe_t *, unsigned, unsigned, char *);
static void afe_miitristate(afe_t *);
static void afe_mii_notify(void *, link_state_t);
static void afe_mii_reset(void *);
static void afe_disableinterrupts(afe_t *);
static void afe_enableinterrupts(afe_t *);
static void afe_reclaim(afe_t *);
static mii_ops_t afe_mii_ops = {
};
static mac_callbacks_t afe_m_callbacks = {
NULL,
afe_m_ioctl, /* mc_ioctl */
NULL, /* mc_getcapab */
NULL, /* mc_open */
NULL, /* mc_close */
};
/*
* Stream information
*/
/*
* Module linkage information.
*/
static struct modldrv afe_modldrv = {
&mod_driverops, /* drv_modops */
"ADMtek Fast Ethernet", /* drv_linkinfo */
&afe_devops /* drv_dev_ops */
};
static struct modlinkage afe_modlinkage = {
MODREV_1, /* ml_rev */
};
/*
* Device attributes.
*/
static ddi_device_acc_attr_t afe_devattr = {
};
static ddi_device_acc_attr_t afe_bufattr = {
};
static ddi_dma_attr_t afe_dma_attr = {
DMA_ATTR_V0, /* dma_attr_version */
0, /* dma_attr_addr_lo */
0xFFFFFFFFU, /* dma_attr_addr_hi */
0x7FFFFFFFU, /* dma_attr_count_max */
4, /* dma_attr_align */
0x3F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0xFFFFFFFFU, /* dma_attr_maxxfer */
0xFFFFFFFFU, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
/*
* Tx buffers can be arbitrarily aligned. Additionally, they can
* cross a page boundary, so we use the two buffer addresses of the
* chip to provide a two-entry scatter-gather list.
*/
static ddi_dma_attr_t afe_dma_txattr = {
DMA_ATTR_V0, /* dma_attr_version */
0, /* dma_attr_addr_lo */
0xFFFFFFFFU, /* dma_attr_addr_hi */
0x7FFFFFFFU, /* dma_attr_count_max */
1, /* dma_attr_align */
0x3F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0xFFFFFFFFU, /* dma_attr_maxxfer */
0xFFFFFFFFU, /* dma_attr_seg */
2, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
/*
* Ethernet addresses.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/*
* DDI entry points.
*/
int
_init(void)
{
int rv;
}
return (rv);
}
int
_fini(void)
{
int rv;
}
return (rv);
}
int
{
}
int
{
int i;
switch (cmd) {
case DDI_RESUME:
return (afe_resume(dip));
case DDI_ATTACH:
break;
default:
return (DDI_FAILURE);
}
/* this card is a bus master, reject any slave-only slot */
return (DDI_FAILURE);
}
/* PCI devices shouldn't generate hilevel interrupts */
if (ddi_intr_hilevel(dip, 0) != 0) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* Note: ADMtek boards seem to misprogram themselves with bogus
* timings, which do not seem to work properly on SPARC. We
* reprogram them zero (but only if they appear to be broken),
* which seems to at least work. Its unclear that this is a
* legal or wise practice to me, but it certainly works better
* than the original values. (I would love to hear
* suggestions for better values, or a better strategy.)
*/
}
/*
* the last entry in the card table matches every possible
* card, so the for-loop always terminates properly.
*/
for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) {
}
break;
}
}
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* Grab the PCI cachesize -- we use this to program the
* cache-optimization bus access bits.
*/
/* this cannot fail */
/* get the interrupt block cookie */
return (DDI_FAILURE);
}
"fiber", 0);
/*
* Enable bus master, IO space, and memory space accesses.
*/
/* we're done with this now, drop it */
/*
* Initialize interrupt kstat. This should not normally fail, since
* we don't use a persistent stat. We do it this way to avoid having
* to test for it at run time on the hot path.
*/
KSTAT_TYPE_INTR, 1, 0);
goto failed;
}
/*
* Set up the MII.
*/
goto failed;
}
/*
* Centaur can support PAUSE, but Comet can't.
*/
} else {
}
/*
* Map in the device registers.
*/
goto failed;
}
/*
* Allocate DMA resources (descriptor rings and buffers).
*/
goto failed;
}
/* Initialize the chip. */
if (!afe_initialize(afep)) {
goto failed;
}
/* Determine the number of address bits to our EEPROM. */
/*
* Get the factory ethernet address. This becomes the current
* ethernet address (it can be overridden later via ifconfig).
*/
/* make sure we add configure the initial filter */
/*
* Establish interrupt handler.
*/
DDI_SUCCESS) {
goto failed;
}
/* TODO: do the power management stuff */
goto failed;
}
return (DDI_SUCCESS);
}
/* failed to register with MAC */
}
if (afep->afe_intrstat) {
}
}
return (DDI_FAILURE);
}
int
{
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
return (DDI_FAILURE);
}
/* make sure hardware is quiesced */
/* clean up and shut down device */
/* clean up MII layer */
/* clean up kstats */
/* free up any left over buffers or DMA resources */
return (DDI_SUCCESS);
case DDI_SUSPEND:
/* stop MII monitoring */
/* quiesce the hardware */
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
int
{
return (DDI_FAILURE);
}
/* re-initialize chip */
if (!afe_initialize(afep)) {
return (DDI_SUCCESS);
}
/* start the chip */
}
/* drop locks */
return (DDI_SUCCESS);
}
int
{
return (DDI_FAILURE);
}
/*
* At 66 MHz it is 16 nsec per access or more (always more)
* So we need 3,333 times to retry for 50 usec. We just
* round up to 5000 times. Unless the hardware is horked,
* it will always terminate *well* before that anyway.
*/
for (int i = 0; i < 5000; i++) {
return (DDI_SUCCESS);
}
}
/* hardware didn't quiesce - force a full reboot (PCI reset) */
return (DDI_FAILURE);
}
void
{
/* don't touch a suspended interface */
return;
}
/* stop receiver */
if (rxen) {
}
/* program promiscuous mode */
if (afep->afe_promisc)
else
/* program mac address */
if (rxen) {
}
/* program multicast filter */
} else {
}
} else {
}
/* restart receiver */
if (rxen) {
}
}
int
{
if ((afep->afe_txstall_time != 0) &&
afep->afe_txstall_time = 0;
return (DDI_FAILURE);
} else {
return (DDI_SUCCESS);
}
}
int
{
int index;
crc %= AFE_MCHASH;
/* bit within a 32-bit word */
if (add) {
} else {
}
}
return (0);
}
int
{
/* exclusive access to the card while we reprogram it */
/* save current promiscuous mode state for replay in resume */
return (0);
}
int
{
/* exclusive access to the card while we reprogram it */
return (0);
}
mblk_t *
{
}
return (NULL);
}
break;
}
}
return (mp);
}
void
{
return;
}
/*
* Hardware management.
*/
static boolean_t
{
int i;
unsigned val;
for (i = 1; i < 10; i++) {
drv_usecwait(5);
break;
}
}
if (i == 10) {
return (B_FALSE);
}
/*
* Updated Centaur data sheets show that the Comet and Centaur are
* alike here (contrary to earlier versions of the data sheet).
*/
/* XXX:? chip problems */
/* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */
par = 0;
switch (afep->afe_cachesize) {
case 8:
break;
case 16:
break;
case 32:
break;
default:
par |= PAR_BURST_32;
break;
}
/* enable transmit underrun auto-recovery */
/* clear the lost packet counter (cleared on read) */
return (B_TRUE);
}
/*
* Serial EEPROM access - inspired by the FreeBSD implementation.
*/
{
int i;
drv_usecwait(1);
/* command bits first */
for (i = 4; i != 0; i >>= 1) {
drv_usecwait(1);
drv_usecwait(1);
}
drv_usecwait(1);
drv_usecwait(1);
break;
}
drv_usecwait(1);
}
/* turn off accesses to the EEPROM */
}
/*
* The words in EEPROM are stored in little endian order. We
* shift bits out in big endian order, though. This requires
* a byte swap on some platforms.
*/
{
int i;
int eeread;
int readcmd;
/* too big to fit! */
return (0);
}
/* command and address bits */
for (i = 4 + addrlen; i >= 0; i--) {
drv_usecwait(1);
drv_usecwait(1);
}
for (i = 0; i < 16; i++) {
drv_usecwait(1);
word <<= 1;
word |= 1;
}
drv_usecwait(1);
}
/* turn off accesses to the EEPROM */
/*
* Fix up the endianness thing. Note that the values
* are stored in little endian format on the SROM.
*/
return (retval);
}
void
{
int i;
for (i = 0; i < len; i++) {
ptr++;
}
}
void
{
}
/*
* MII management.
*/
void
afe_mii_reset(void *arg)
{
int fiber;
/*
* Its entirely possible that this belongs as a PHY specific
* override.
*/
/* if its not an AN983B, we don't care */
return;
}
fiber = 0;
switch (afep->afe_forcefiber) {
case 0:
/* UTP Port */
fiber = 0;
break;
case 1:
/* Fiber Port */
fiber = 1;
break;
}
switch (fiber) {
case 0:
break;
case 1:
break;
}
drv_usecwait(500);
/*
* work around for errata 983B_0416 -- duplex light flashes
* in 10 HDX. we just disable SQE testing on the device.
*/
pilr |= PILR_NOSQE;
}
void
{
} else {
}
}
}
void
{
drv_usecwait(1);
drv_usecwait(1);
}
void
{
drv_usecwait(1);
drv_usecwait(1);
}
{
drv_usecwait(1);
drv_usecwait(1);
return (bit);
}
{
/*
* ADMtek bugs ignore address decode bits -- they only
* support PHY at 1.
*/
if (phy != 1) {
return (0xffff);
}
case MODEL_COMET:
case MODEL_CENTAUR:
}
return (0xffff);
}
{
int i;
/* send the 32 bit preamble */
for (i = 0; i < 32; i++) {
}
/* send the start code - 01b */
afe_miiwritebit(afep, 0);
/* send the opcode for read, - 10b */
afe_miiwritebit(afep, 0);
/* next we send the 5 bit phy address */
for (i = 0x10; i > 0; i >>= 1) {
}
/* the 5 bit register address goes next */
for (i = 0x10; i > 0; i >>= 1) {
}
/* turnaround - tristate followed by logic 0 */
afe_miiwritebit(afep, 0);
/* read the 16 bit register value */
for (i = 0x8000; i > 0; i >>= 1) {
value <<= 1;
}
return (value);
}
{
if (phy != 1) {
return (0xffff);
}
switch (reg) {
case MII_CONTROL:
break;
case MII_STATUS:
break;
case MII_PHYIDH:
reg = CSR_PHYIDR1;
break;
case MII_PHYIDL:
reg = CSR_PHYIDR2;
break;
case MII_AN_ADVERT:
break;
case MII_AN_LPABLE:
reg = CSR_ANLPAR;
break;
case MII_AN_EXPANSION:
break;
default:
return (0);
}
}
void
{
/*
* ADMtek bugs ignore address decode bits -- they only
* support PHY at 1.
*/
if (phy != 1) {
return;
}
case MODEL_COMET:
break;
case MODEL_CENTAUR:
break;
}
}
void
{
int i;
/* send the 32 bit preamble */
for (i = 0; i < 32; i++) {
}
/* send the start code - 01b */
afe_miiwritebit(afep, 0);
/* send the opcode for write, - 01b */
afe_miiwritebit(afep, 0);
/* next we send the 5 bit phy address */
for (i = 0x10; i > 0; i >>= 1) {
}
/* the 5 bit register address goes next */
for (i = 0x10; i > 0; i >>= 1) {
}
/* turnaround - 1 bit followed by logic 0 */
afe_miiwritebit(afep, 0);
/* now write out our data (16 bits) */
for (i = 0x8000; i > 0; i >>= 1) {
}
/* idle mode */
}
void
{
if (phy != 1) {
return;
}
switch (reg) {
case MII_CONTROL:
break;
case MII_STATUS:
break;
case MII_PHYIDH:
reg = CSR_PHYIDR1;
break;
case MII_PHYIDL:
reg = CSR_PHYIDR2;
break;
case MII_AN_ADVERT:
break;
case MII_AN_LPABLE:
reg = CSR_ANLPAR;
break;
case MII_AN_EXPANSION:
break;
default:
return;
}
}
int
afe_m_start(void *arg)
{
/* grab exclusive access to the card */
return (0);
}
void
afe_m_stop(void *arg)
{
/* exclusive access to the hardware! */
}
void
{
/* verify exclusive access to the card */
/* start the card */
/* tell the mac that we are ready to go! */
/* start watchdog timer */
}
void
{
int i;
/* exclusive access to the hardware! */
/*
* A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
* We just add up to the nearest msec (2), which should be
* plenty to complete.
*
* Note that some chips never seem to indicate the transition to
* the stopped state properly. Experience shows that we can safely
* proceed anyway, after waiting the requisite timeout.
*/
for (i = 2000; i != 0; i -= 10) {
break;
drv_usecwait(10);
}
/* prevent an interrupt */
/* stop the watchdog timer */
}
void
{
int i;
/* now we need to reset the pointers... */
/* reset the descriptor ring pointers */
afep->afe_rxhead = 0;
afep->afe_txreclaim = 0;
afep->afe_txsend = 0;
/* set up transmit descriptor ring */
for (i = 0; i < AFE_TXRING; i++) {
unsigned control = 0;
if (i == (AFE_TXRING - 1)) {
control |= TXCTL_ENDRING;
}
}
/* make the receive buffers available */
for (i = 0; i < AFE_RXRING; i++) {
unsigned control;
if (i == (AFE_RXRING - 1)) {
control |= RXCTL_ENDRING;
}
}
}
void
{
}
void
{
/* make sure interrupts are disabled to begin */
/* initialize the chip */
(void) afe_initialize(afep);
/* now we can enable interrupts */
/* start up the mac */
}
void
{
}
{
unsigned ncookies;
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (txb);
}
void
{
}
}
{
unsigned ccnt;
return (NULL);
}
return (NULL);
}
&ccnt) != DDI_DMA_MAPPED) {
return (NULL);
}
return (rxb);
}
void
{
if (rxb) {
}
}
/*
* Allocate receive resources.
*/
int
{
int rval;
int i;
unsigned ncookies;
if (rval != DDI_SUCCESS) {
"unable to allocate DMA handle for rx descriptors");
return (DDI_FAILURE);
}
&afep->afe_rxdesc_acch);
if (rval != DDI_SUCCESS) {
"unable to allocate DMA memory for rx descriptors");
return (DDI_FAILURE);
}
if (rval != DDI_DMA_MAPPED) {
"unable to bind DMA for rx descriptors");
return (DDI_FAILURE);
}
/* because of afe_dma_attr */
/* we take the 32-bit physical address out of the cookie */
/* allocate buffer pointers (not the buffers themselves, yet) */
KM_SLEEP);
/* now allocate rx buffers */
for (i = 0; i < AFE_RXRING; i++) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Allocate transmit resources.
*/
int
{
int rval;
int i;
unsigned ncookies;
if (rval != DDI_SUCCESS) {
"unable to allocate DMA handle for tx descriptors");
return (DDI_FAILURE);
}
&afep->afe_txdesc_acch);
if (rval != DDI_SUCCESS) {
"unable to allocate DMA memory for tx descriptors");
return (DDI_FAILURE);
}
if (rval != DDI_DMA_MAPPED) {
"unable to bind DMA for tx descriptors");
return (DDI_FAILURE);
}
/* because of afe_dma_attr */
/* we take the 32-bit physical address out of the cookie */
/* allocate buffer pointers (not the buffers themselves, yet) */
KM_SLEEP);
/* now allocate tx buffers */
for (i = 0; i < AFE_TXRING; i++) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
{
int i;
for (i = 0; i < AFE_RXRING; i++) {
}
if (afep->afe_rxbufs) {
AFE_RXRING * sizeof (afe_rxbuf_t *));
}
if (afep->afe_rxdesc_paddr)
if (afep->afe_rxdesc_acch)
if (afep->afe_rxdesc_dmah)
}
void
{
int i;
for (i = 0; i < AFE_TXRING; i++) {
}
if (afep->afe_txbufs) {
AFE_TXRING * sizeof (afe_txbuf_t *));
}
if (afep->afe_txdesc_paddr)
if (afep->afe_txdesc_acch)
if (afep->afe_txdesc_dmah)
}
/*
* Interrupt service routine.
*/
unsigned
{
/* we cannot receive interrupts! */
return (DDI_INTR_UNCLAIMED);
}
/* check interrupt status bits, did we interrupt? */
if (status == 0) {
return (DDI_INTR_UNCLAIMED);
}
/* ack the interrupt */
/* not running, don't touch anything */
return (DDI_INTR_CLAIMED);
}
/* receive packets */
if (status & INT_RXNOBUF)
}
/* transmit completed */
}
}
afep->afe_jabber++;
}
}
if (status & INT_BUSERR) {
case SR_BERR_PARITY:
break;
case SR_BERR_TARGET_ABORT:
break;
case SR_BERR_MASTER_ABORT:
break;
default:
break;
}
/* reset the chip in an attempt to fix things */
}
if (doreset) {
} else {
}
if (status & INT_LINKCHG) {
}
/*
* Send up packets. We do this outside of the intrlock.
*/
if (mp) {
}
return (DDI_INTR_CLAIMED);
}
void
{
unsigned mask = INT_WANTED;
/*
* On the Comet, this is the internal transceiver
* interrupt. We program the Comet's built-in PHY to
* enable certain interrupts.
*/
}
}
void
{
/* disable further interrupts */
/* clear any pending interrupts */
}
{
int txsend;
if (len > ETHERVLANMTU) {
return (B_TRUE);
}
if (afep->afe_txavail == 0) {
/* no more tmds */
/* enable TX interrupt */
return (B_FALSE);
}
/*
* For simplicity, we just do a copy into a preallocated
* DMA buffer.
*/
/*
* Statistics.
*/
afep->afe_opackets++;
afep->afe_multixmt++;
else
afep->afe_brdcstxmt++;
}
/* note len is already known to be a small unsigned */
control |= TXCTL_ENDRING;
/* sync the descriptor out to the device */
/*
* Note the new values of txavail and txsend.
*/
afep->afe_txavail--;
/*
* It should never, ever take more than 5 seconds to drain
* the ring. If it happens, then we are stuck!
*/
/*
* wake up the chip ... inside the lock to protect against DR suspend,
* etc.
*/
return (B_TRUE);
}
/*
* Reclaim buffers that have completed transmission.
*/
void
{
/* sync it before we read it */
if (status & TXSTAT_OWN) {
/* chip is still working on it, we're done */
break;
}
afep->afe_txavail++;
/* in the most common successful case, all bits are clear */
if (status == 0)
continue;
if ((control & TXCTL_LAST) == 0)
continue;
if (status & TXSTAT_TXERR) {
afep->afe_errxmt++;
if (status & TXSTAT_JABBER) {
/* transmit jabber timeout */
}
if (status &
(TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
}
if (status & TXSTAT_UFLOW) {
afep->afe_underflow++;
}
if (status & TXSTAT_LATECOL) {
}
if (status & TXSTAT_EXCOLL) {
}
}
if (status & TXSTAT_DEFER) {
afep->afe_defer_xmts++;
}
/* collision counting */
afep->afe_collisions++;
}
}
/*
* we were able to reclaim some packets, so
* disable tx interrupts
*/
}
}
}
mblk_t *
{
unsigned len;
/* limit the number of packets we process to a half ring size */
if (status & RXSTAT_OWN) {
/* chip is still chewing on it */
break;
}
/* discard the ethernet frame checksum */
(RXSTAT_FIRST | RXSTAT_LAST)) {
afep->afe_errrcv++;
/*
* Abnormal status bits detected, analyze further.
*/
(RXSTAT_LAST|RXSTAT_FIRST)) {
if (status & RXSTAT_FIRST) {
}
} else if (status & RXSTAT_DESCERR) {
} else if (status & RXSTAT_RUNT) {
} else if (status & RXSTAT_COLLSEEN) {
/* this should really be rx_late_collisions */
} else if (status & RXSTAT_DRIBBLE) {
afep->afe_align_errors++;
} else if (status & RXSTAT_CRCERR) {
afep->afe_fcs_errors++;
} else if (status & RXSTAT_OFLOW) {
afep->afe_overflow++;
}
}
else if (len > ETHERVLANMTU) {
afep->afe_errrcv++;
}
/*
* At this point, the chip thinks the packet is OK.
*/
else {
afep->afe_errrcv++;
afep->afe_norcvbuf++;
goto skip;
}
/* sync the buffer before we look at it */
afep->afe_ipackets++;
if (status & RXSTAT_GROUP) {
ETHERADDRL) == 0)
afep->afe_brdcstrcv++;
else
afep->afe_multircv++;
}
}
skip:
/* return ring entry to the hardware */
/* advance to next RMD */
}
return (mpchain);
}
int
{
return (0);
}
switch (stat) {
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_NORCVBUF:
break;
case MAC_STAT_NOXMTBUF:
*val = 0;
break;
case MAC_STAT_COLLISIONS:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_OERRORS:
break;
case ETHER_STAT_ALIGN_ERRORS:
break;
case ETHER_STAT_FCS_ERRORS:
break;
case ETHER_STAT_SQE_ERRORS:
break;
case ETHER_STAT_DEFER_XMTS:
break;
break;
break;
break;
case ETHER_STAT_EX_COLLISIONS:
break;
case ETHER_STAT_MACXMT_ERRORS:
break;
break;
break;
case ETHER_STAT_MACRCV_ERRORS:
break;
case MAC_STAT_OVERFLOWS:
break;
case MAC_STAT_UNDERFLOWS:
break;
break;
case ETHER_STAT_JABBER_ERRORS:
break;
default:
return (ENOTSUP);
}
return (0);
}
int
void *val)
{
}
int
const void *val)
{
}
static void
{
}
/*
* Debugging and error reporting.
*/
void
{
char buf[256];
if (dip) {
} else {
}
}