afe.c revision 96fb08b94cc33de779f46f36c30d77230f1a8c2f
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Solaris driver for ethernet cards based on the ADMtek Centaur
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * All rights reserved.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Redistribution and use in source and binary forms, with or without
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * modification, are permitted provided that the following conditions
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * are met:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 1. Redistributions of source code must retain the above copyright
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * notice, this list of conditions and the following disclaimer.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 2. Redistributions in binary form must reproduce the above copyright
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * notice, this list of conditions and the following disclaimer in the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * documentation and/or other materials provided with the distribution.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 3. Neither the name of the author nor the names of any co-contributors
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * may be used to endorse or promote products derived from this software
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * without specific prior written permission.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * POSSIBILITY OF SUCH DAMAGE.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Use is subject to license terms.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#pragma ident "%Z%%M% %I% %E% SMI"
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Driver globals.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz/* patchable debug flag ... must not be static! */
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey/* table of supported devices */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * ADMtek Centaur and Comet
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Accton just relabels other companies' controllers
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Models listed here.
024b0a258461f282a92b1b1283c3b8b083f9f33fseb { 0x10b7, 0x9300, "3Com 3CSOHO100B-TX", MODEL_CENTAUR },
d62bc4badc1c1f1549c961cfb8b420e650e1272byz { 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR },
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey { 0x1113, 0x9216, "3M VOL-N100VF+TX", MODEL_CENTAUR },
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey { 0x1317, 0x0574, "Linksys LNE100TX", MODEL_CENTAUR },
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey { 0x1317, 0x0570, "Linksys NC100", MODEL_CENTAUR },
d62bc4badc1c1f1549c961cfb8b420e650e1272byz { 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR },
024b0a258461f282a92b1b1283c3b8b083f9f33fseb { 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR },
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Function prototypes
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int afe_m_multicst(void *, boolean_t, const uint8_t *);
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskeystatic int afe_m_promisc(void *, boolean_t);
024b0a258461f282a92b1b1283c3b8b083f9f33fsebstatic int afe_m_start(void *);
024b0a258461f282a92b1b1283c3b8b083f9f33fsebstatic void afe_m_stop(void *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int afe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int afe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz const void *);
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskeystatic void afe_error(dev_info_t *, char *, ...);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void afe_readsrom(afe_t *, unsigned, unsigned, char *);
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskeystatic void afe_miiwritebit(afe_t *, uint8_t);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void afe_miiwritegeneral(afe_t *, int, int, uint16_t);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void afe_miiwritecomet(afe_t *, int, int, uint16_t);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void afe_dprintf(afe_t *, const char *, int, char *, ...);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Stream information
d62bc4badc1c1f1549c961cfb8b420e650e1272byzDDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach,
024b0a258461f282a92b1b1283c3b8b083f9f33fseb * Module linkage information.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Device attributes.
2d4eecfa187a743d7823497136e21cb0568eb77dCathy Zhou 0, /* dma_attr_addr_lo */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 0 /* dma_attr_flags */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Tx buffers can be arbitrarily aligned. Additionally, they can
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey * cross a page boundary, so we use the two buffer addresses of the
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey * chip to provide a two-entry scatter-gather list.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 0, /* dma_attr_addr_lo */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 0 /* dma_attr_flags */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Ethernet addresses.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * DDI entry points.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (rv);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (rv);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz switch (cmd) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* this card is a bus master, reject any slave-only slot */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* PCI devices shouldn't generate hilevel interrupts */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Note: ADMtek boards seem to misprogram themselves with bogus
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * timings, which do not seem to work properly on SPARC. We
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * reprogram them zero (but only if they appear to be broken),
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey * which seems to at least work. Its unclear that this is a
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey * legal or wise practice to me, but it certainly works better
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * than the original values. (I would love to hear
024b0a258461f282a92b1b1283c3b8b083f9f33fseb * suggestions for better values, or a better strategy.)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the last entry in the card table matches every possible
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * card, so the for-loop always terminates properly.
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Grab the PCI cachesize -- we use this to program the
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey * cache-optimization bus access bits.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* this cannot fail */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* get the interrupt block cookie */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* default properties */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_aneg = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_100T4 = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_100fdx = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_100hdx = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_10fdx = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_adv_10hdx = !!ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
024b0a258461f282a92b1b1283c3b8b083f9f33fseb DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD));
024b0a258461f282a92b1b1283c3b8b083f9f33fseb DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT));
d62bc4badc1c1f1549c961cfb8b420e650e1272byz mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Enable bus master, IO space, and memory space accesses.
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* we're done with this now, drop it */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Initialize interrupt kstat. This should not normally fail, since
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * we don't use a persistent stat. We do it this way to avoid having
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * to test for it at run time on the hot path.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller",
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Map in the device registers.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Allocate DMA resources (descriptor rings and buffers).
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* Initialize the chip. */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* Determine the number of address bits to our EEPROM. */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Get the factory ethernet address. This becomes the current
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * ethernet address (it can be overridden later via ifconfig).
024b0a258461f282a92b1b1283c3b8b083f9f33fseb /* make sure we add configure the initial filter */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Establish interrupt handler.
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) !=
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* TODO: do the power management stuff */
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* failed to register with MAC */
4ac67f0276a8313b5cefec38af347b94b7bfb526Anurag S. Maskey afe_error(dip, "no soft state in detach!");
switch (cmd) {
case DDI_DETACH:
return (DDI_FAILURE);
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_SUCCESS);
return (DDI_SUCCESS);
if (rxen) {
if (rxen) {
if (rxen) {
int index;
if (add) {
mblk_t *
return (NULL);
return (mp);
static boolean_t
unsigned val;
return (B_FALSE);
par = 0;
return (B_TRUE);
int eeread;
int readcmd;
return (retval);
for (i = 0; i < len; i++) {
ptr++;
unsigned phyaddr;
unsigned bmcr;
unsigned bmsr;
unsigned anar;
unsigned phyidr1;
unsigned phyidr2;
unsigned nosqe = 0;
int retries;
int fiber;
int cnt;
fiber = 0;
fiber = 0;
fiber = 0;
if (fiber) {
cnt = 0;
cnt++;
cnt++;
cnt++;
cnt++;
cnt++;
if (!cnt) {
if (fiber) {
bmcr = 0;
if (nosqe) {
int changed = 0;
changed++;
changed++;
if (changed)
case MODEL_COMET:
case MODEL_CENTAUR:
int reinit = 0;
reinit++;
if (reinit) {
unsigned opmode;
int reinit = 0;
reinit++;
if (reinit) {
int reinit = 0;
if (reinit) {
return (bit);
case MODEL_COMET:
case MODEL_CENTAUR:
return (value);
switch (reg) {
case MII_CONTROL:
case MII_STATUS:
case MII_PHYIDH:
case MII_PHYIDL:
case MII_AN_ADVERT:
case MII_AN_LPABLE:
case MII_AN_EXPANSION:
case MODEL_COMET:
case MODEL_CENTAUR:
switch (reg) {
case MII_CONTROL:
case MII_STATUS:
case MII_PHYIDH:
case MII_PHYIDL:
case MII_AN_ADVERT:
case MII_AN_LPABLE:
case MII_AN_EXPANSION:
for (i = 0; i < AFE_TXRING; i++) {
unsigned control = 0;
for (i = 0; i < AFE_RXRING; i++) {
unsigned control;
unsigned ncookies;
return (NULL);
return (NULL);
return (NULL);
return (txb);
unsigned ccnt;
return (NULL);
return (NULL);
return (NULL);
return (rxb);
if (rxb) {
int rval;
unsigned ncookies;
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_FAILURE);
KM_SLEEP);
for (i = 0; i < AFE_RXRING; i++) {
return (DDI_FAILURE);
return (DDI_SUCCESS);
int rval;
unsigned ncookies;
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_FAILURE);
KM_SLEEP);
for (i = 0; i < AFE_TXRING; i++) {
return (DDI_FAILURE);
return (DDI_SUCCESS);
for (i = 0; i < AFE_RXRING; i++) {
for (i = 0; i < AFE_TXRING; i++) {
return (DDI_INTR_UNCLAIMED);
if (status == 0) {
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_CLAIMED);
case SR_BERR_PARITY:
case SR_BERR_TARGET_ABORT:
case SR_BERR_MASTER_ABORT:
if (mp) {
return (DDI_INTR_CLAIMED);
int txsend;
return (B_TRUE);
return (B_FALSE);
return (B_TRUE);
if (status == 0)
if (status &
mblk_t *
unsigned len;
goto skip;
ETHERADDRL) == 0)
skip:
return (mpchain);
unsigned val;
switch (stat) {
case MAC_STAT_IFSPEED:
case MAC_STAT_MULTIRCV:
case MAC_STAT_BRDCSTRCV:
case MAC_STAT_MULTIXMT:
case MAC_STAT_BRDCSTXMT:
case MAC_STAT_IPACKETS:
case MAC_STAT_RBYTES:
case MAC_STAT_OPACKETS:
case MAC_STAT_OBYTES:
case MAC_STAT_NORCVBUF:
case MAC_STAT_NOXMTBUF:
*val = 0;
case MAC_STAT_COLLISIONS:
case MAC_STAT_IERRORS:
case MAC_STAT_OERRORS:
case ETHER_STAT_LINK_DUPLEX:
case ETHER_STAT_ALIGN_ERRORS:
case ETHER_STAT_FCS_ERRORS:
case ETHER_STAT_SQE_ERRORS:
case ETHER_STAT_DEFER_XMTS:
case ETHER_STAT_EX_COLLISIONS:
case ETHER_STAT_MACXMT_ERRORS:
case ETHER_STAT_MACRCV_ERRORS:
case MAC_STAT_OVERFLOWS:
case MAC_STAT_UNDERFLOWS:
case ETHER_STAT_JABBER_ERRORS:
case ETHER_STAT_CAP_100T4:
case ETHER_STAT_CAP_100FDX:
case ETHER_STAT_CAP_100HDX:
case ETHER_STAT_CAP_10FDX:
case ETHER_STAT_CAP_10HDX:
case ETHER_STAT_CAP_AUTONEG:
case ETHER_STAT_LINK_AUTONEG:
case ETHER_STAT_ADV_CAP_100T4:
case ETHER_STAT_ADV_CAP_10FDX:
case ETHER_STAT_ADV_CAP_10HDX:
case ETHER_STAT_LP_CAP_100T4:
case ETHER_STAT_LP_CAP_100FDX:
case ETHER_STAT_LP_CAP_100HDX:
case ETHER_STAT_LP_CAP_10FDX:
case ETHER_STAT_LP_CAP_10HDX:
case ETHER_STAT_XCVR_ADDR:
case ETHER_STAT_XCVR_ID:
return (ENOTSUP);
int err = 0;
if (sz == 0)
return (EINVAL);
switch (num) {
case DLD_PROP_DUPLEX:
case DLD_PROP_SPEED:
case DLD_PROP_AUTONEG:
case DLD_PROP_ADV_1000FDX_CAP:
case DLD_PROP_EN_1000FDX_CAP:
case DLD_PROP_ADV_1000HDX_CAP:
case DLD_PROP_EN_1000HDX_CAP:
case DLD_PROP_ADV_100FDX_CAP:
case DLD_PROP_EN_100FDX_CAP:
case DLD_PROP_ADV_100HDX_CAP:
case DLD_PROP_EN_100HDX_CAP:
case DLD_PROP_ADV_10FDX_CAP:
case DLD_PROP_EN_10FDX_CAP:
case DLD_PROP_ADV_10HDX_CAP:
case DLD_PROP_EN_10HDX_CAP:
case DLD_PROP_ADV_100T4_CAP:
case DLD_PROP_EN_100T4_CAP:
return (err);
const void *val)
switch (num) {
case DLD_PROP_EN_100FDX_CAP:
case DLD_PROP_EN_100HDX_CAP:
case DLD_PROP_EN_10FDX_CAP:
case DLD_PROP_EN_10HDX_CAP:
case DLD_PROP_EN_100T4_CAP:
case DLD_PROP_AUTONEG:
return (ENOTSUP);
return (ENOTSUP);
AFE_RUNNING) {
if (dip) {
#ifdef DEBUG