efe.c revision e65fcc69bb33b3f4525b0c2c9732ece17c90b196
/*
* Copyright (c) 2010 Steven Stallion. 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
* with the distribution.
* 3. Neither the name of the copyright owner nor the names of any
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 OWNER 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.
*/
#include <sys/byteorder.h>
#include <sys/sysmacros.h>
#include <sys/ddi_intr.h>
#include <sys/ethernet.h>
#include <sys/mac_ether.h>
#include <sys/mac_provider.h>
#include "efe.h"
/* Autoconfiguration entry points */
static int efe_quiesce(dev_info_t *);
/* MII entry points */
static void efe_mii_notify(void *, link_state_t);
/* MAC entry points */
static int efe_m_start(void *);
static void efe_m_stop(void *);
static int efe_m_setpromisc(void *, boolean_t);
static int efe_m_unicst(void *, const uint8_t *);
const void *);
void *);
static void efe_m_propinfo(void *, const char *, mac_prop_id_t,
/* Support functions */
static void efe_init_rx_ring(efe_t *);
static void efe_init_tx_ring(efe_t *);
static void efe_stop_dma(efe_t *);
static inline void efe_restart(efe_t *);
static int efe_suspend(efe_t *);
static int efe_resume(efe_t *);
static void efe_ring_free(efe_ring_t **);
static void efe_buf_free(efe_buf_t **);
static void efe_intr_enable(efe_t *);
static void efe_intr_disable(efe_t *);
static void efe_send_done(efe_t *);
static inline int efe_eeprom_readbit(efe_t *);
static inline void efe_eeprom_writebit(efe_t *, int);
static void efe_dprintf(dev_info_t *, int, const char *, ...);
#ifdef DEBUG
#else
#endif
extern struct mod_ops mod_driverops;
&mod_driverops, /* drv_modops */
"EPIC/100 Fast Ethernet", /* drv_linkinfo */
&efe_dev_ops /* drv_dev_ops */
};
static struct modlinkage modlinkage = {
MODREV_1, /* ml_rev */
};
static ddi_device_acc_attr_t efe_regs_acc_attr = {
DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
DDI_STRUCTURE_LE_ACC, /* devacc_attr_endian_flags */
DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
};
static ddi_device_acc_attr_t efe_buf_acc_attr = {
DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
};
static ddi_dma_attr_t efe_dma_attr = {
DMA_ATTR_V0, /* dma_attr_version */
0, /* dma_attr_addr_lo */
0xFFFFFFFFUL, /* dma_attr_addr_hi */
0x7FFFFFFFUL, /* dma_attr_count_max */
4, /* dma_attr_align */
0x7F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0xFFFFFFFFUL, /* dma_attr_maxxfer */
0xFFFFFFFFUL, /* dma_attr_seg */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0 /* dma_attr_flags */
};
static mii_ops_t efe_mii_ops = {
MII_OPS_VERSION, /* mii_version */
efe_mii_read, /* mii_read */
efe_mii_write, /* mii_write */
efe_mii_notify /* mii_notify */
};
static mac_callbacks_t efe_m_callbacks = {
efe_m_getstat, /* mc_getstat */
efe_m_start, /* mc_start */
efe_m_stop, /* mc_stop */
efe_m_setpromisc, /* mc_setpromisc */
efe_m_multicst, /* mc_multicst */
efe_m_unicst, /* mc_unicst */
efe_m_tx, /* mc_tx */
NULL, /* mc_reserved */
NULL, /* mc_ioctl */
NULL, /* mc_getcapab */
NULL, /* mc_open */
NULL, /* mc_close */
efe_m_setprop, /* mc_setprop */
efe_m_getprop, /* mc_getprop */
efe_m_propinfo /* mc_propinfo */
};
static uint8_t efe_broadcast[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static uint16_t efe_mchash_promisc[] = {
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
};
/*
* Loadable module entry points.
*/
int
_init(void)
{
int error;
}
return (error);
}
int
_fini(void)
{
int error;
}
return (error);
}
int
{
}
/*
* Autoconfiguration entry points.
*/
int
{
int types;
int count;
int actual;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (efe_resume(efep));
default:
return (DDI_FAILURE);
}
/*
* PCI configuration.
*/
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* Initialize soft state.
*/
goto failure;
}
goto failure;
}
goto failure;
}
goto failure;
}
pri >= ddi_intr_get_hilevel_pri()) {
goto failure;
}
DDI_INTR_PRI(pri));
DDI_INTR_PRI(pri));
/*
* Initialize device.
*/
/* Use factory address as default */
/*
* Enable the ISR.
*/
!= DDI_SUCCESS) {
goto failure;
}
goto failure;
}
/*
* Allocate MII resources.
*/
goto failure;
}
/*
* Allocate MAC resources.
*/
goto failure;
}
goto failure;
}
return (DDI_SUCCESS);
}
}
}
}
}
}
return (DDI_FAILURE);
}
int
{
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
return (efe_suspend(efep));
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
int
{
return (DDI_SUCCESS);
}
/*
* MII entry points.
*/
{
for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
}
}
return (0);
}
void
{
for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
return;
}
}
}
void
{
}
/*
* MAC entry points.
*/
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_NORCVBUF:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_OERRORS:
break;
case MAC_STAT_COLLISIONS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_UNDERFLOWS:
break;
case MAC_STAT_OVERFLOWS:
break;
case ETHER_STAT_ALIGN_ERRORS:
break;
case ETHER_STAT_FCS_ERRORS:
break;
break;
break;
case ETHER_STAT_DEFER_XMTS:
break;
case ETHER_STAT_EX_COLLISIONS:
break;
case ETHER_STAT_MACXMT_ERRORS:
break;
break;
break;
case ETHER_STAT_MACRCV_ERRORS:
break;
break;
case ETHER_STAT_JABBER_ERRORS:
break;
default:
return (ENOTSUP);
}
return (0);
}
int
efe_m_start(void *arg)
{
return (0);
}
void
efe_m_stop(void *arg)
{
}
int
{
return (0);
}
}
return (0);
}
int
{
int index;
int bit;
return (0);
}
if (add) {
}
} else {
}
}
}
return (0);
}
int
{
return (0);
}
}
return (0);
}
mblk_t *
{
return (mp);
}
break;
}
}
/* Kick the transmitter */
return (mp);
}
int
{
}
int
{
}
void
{
}
/*
*/
{
return (DDI_INTR_UNCLAIMED);
}
if (!(status & INTSTAT_ACTV)) {
return (DDI_INTR_UNCLAIMED);
}
if (status & INTSTAT_RCC) {
}
if (status & INTSTAT_RQE) {
efep->efe_ierrors++;
/* Kick the receiver */
}
if (status & INTSTAT_TXC) {
}
if (status & INTSTAT_FATAL) {
}
}
if (status & INTSTAT_TXC) {
}
if (status & INTSTAT_FATAL) {
}
return (DDI_INTR_CLAIMED);
}
/*
* Support functions.
*/
void
{
#ifdef _BIG_ENDIAN
#endif /* _BIG_ENDIAN */
if (efep->efe_promisc) {
} else {
}
}
void
{
efe_ring_t *rp;
}
efep->efe_rx_desc = 0;
}
void
{
efe_ring_t *rp;
}
efep->efe_tx_desc = 0;
efep->efe_tx_sent = 0;
}
void
{
/* Assert internal clock source (AN 7.15) */
for (int i = 0; i < RESET_TEST_CYCLES; ++i) {
}
}
void
{
}
void
{
}
void
{
for (int i = 0; i < STOP_DELAY_CYCLES; ++i) {
if (status & INTSTAT_RXIDLE &&
status & INTSTAT_TXIDLE) {
return;
}
}
}
static inline void
{
}
int
{
}
return (DDI_SUCCESS);
}
int
{
}
return (DDI_SUCCESS);
}
{
efe_ring_t *rp;
goto failure;
}
goto failure;
}
goto failure;
}
for (int i = 0; i < len; ++i) {
goto failure;
}
}
return (rp);
efe_ring_free(&rp);
return (NULL);
}
void
{
efe_buf_free(&bp);
}
}
}
}
}
}
{
goto failure;
}
goto failure;
}
goto failure;
}
return (bp);
efe_buf_free(&bp);
return (NULL);
}
void
{
}
}
}
}
void
{
}
void
{
}
mblk_t *
{
efe_ring_t *rp;
for (;;) {
efe_desc_t *dp;
/* Stop if device owns descriptor */
if (status & RXSTAT_OWNER) {
break;
}
if (status & RXSTAT_PRI) {
}
} else {
efep->efe_ierrors++;
if (status & RXSTAT_FAE) {
efep->efe_align_errors++;
}
if (status & RXSTAT_CRC) {
efep->efe_fcs_errors++;
}
}
}
/* Release ownership to device */
}
return (mp);
}
mblk_t *
{
efe_ring_t *rp;
efep->efe_ierrors++;
efep->efe_runt_errors++;
return (NULL);
}
efep->efe_ierrors++;
return (NULL);
}
efep->efe_ierrors++;
efep->efe_norcvbuf++;
return (NULL);
}
efep->efe_ipackets++;
if (status & RXSTAT_BAR) {
efep->efe_brdcstrcv++;
} else if (status & RXSTAT_MAR) {
efep->efe_multircv++;
}
return (mp);
}
int
{
efe_ring_t *rp;
efe_desc_t *dp;
efep->efe_oerrors++;
return (DDI_SUCCESS);
}
/* Stop if device owns descriptor */
if (status & TXSTAT_OWNER) {
return (DDI_FAILURE);
}
/*
* Packets must contain at least ETHERMIN octets.
* Padded octets are zeroed out prior to sending.
*/
}
efep->efe_opackets++;
efep->efe_brdcstxmt++;
} else {
efep->efe_multixmt++;
}
}
return (DDI_SUCCESS);
}
void
{
efe_ring_t *rp;
for (;;) {
efe_desc_t *dp;
/* Stop if device owns descriptor */
if (status & TXSTAT_OWNER) {
break;
}
if (status & TXSTAT_PTX) {
efep->efe_defer_xmts++;
}
if (status & TXSTAT_COLL) {
}
} else {
efep->efe_oerrors++;
if (status & TXSTAT_CSL) {
}
if (status & TXSTAT_UFLO) {
}
if (status & TXSTAT_OWC) {
}
if (status & TXSTAT_DEFER) {
}
if (status & TXSTAT_EXCOLL) {
}
}
efep->efe_collisions +=
}
}
void
{
"factory address is %02x:%02x:%02x:%02x:%02x:%02x\n",
}
void
{
}
void
{
}
void
{
int addrlen;
}
}
{
/* Write Start Bit (SB) */
/* Write READ instruction */
efe_eeprom_writebit(efep, 0);
/* Write EEPROM address */
for (int i = addrlen - 1; i >= 0; --i) {
}
/* Read EEPROM word */
for (int i = EEPROM_WORDSZ - 1; i >= 0; --i) {
}
return (val);
}
inline int
{
}
inline void
{
}
void
{
char buf[255];
}