129e83d4bSgd78059 /* 229e83d4bSgd78059 * Solaris driver for ethernet cards based on the Macronix 98715 329e83d4bSgd78059 * 429e83d4bSgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>. 529e83d4bSgd78059 * All rights reserved. 629e83d4bSgd78059 * 729e83d4bSgd78059 * Redistribution and use in source and binary forms, with or without 829e83d4bSgd78059 * modification, are permitted provided that the following conditions 929e83d4bSgd78059 * are met: 1029e83d4bSgd78059 * 1. Redistributions of source code must retain the above copyright 1129e83d4bSgd78059 * notice, this list of conditions and the following disclaimer. 1229e83d4bSgd78059 * 2. Redistributions in binary form must reproduce the above copyright 1329e83d4bSgd78059 * notice, this list of conditions and the following disclaimer in the 1429e83d4bSgd78059 * documentation and/or other materials provided with the distribution. 1529e83d4bSgd78059 * 3. Neither the name of the author nor the names of any co-contributors 1629e83d4bSgd78059 * may be used to endorse or promote products derived from this software 1729e83d4bSgd78059 * without specific prior written permission. 1829e83d4bSgd78059 * 1929e83d4bSgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' 2029e83d4bSgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2129e83d4bSgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2229e83d4bSgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2329e83d4bSgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2429e83d4bSgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2529e83d4bSgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2629e83d4bSgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2729e83d4bSgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2829e83d4bSgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2929e83d4bSgd78059 * POSSIBILITY OF SUCH DAMAGE. 3029e83d4bSgd78059 */ 3196fb08b9Sgd78059 /* 32*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3396fb08b9Sgd78059 * Use is subject to license terms. 3496fb08b9Sgd78059 */ 3529e83d4bSgd78059 3629e83d4bSgd78059 3729e83d4bSgd78059 #include <sys/varargs.h> 3829e83d4bSgd78059 #include <sys/types.h> 3929e83d4bSgd78059 #include <sys/modctl.h> 4029e83d4bSgd78059 #include <sys/conf.h> 4129e83d4bSgd78059 #include <sys/devops.h> 4229e83d4bSgd78059 #include <sys/stream.h> 4329e83d4bSgd78059 #include <sys/strsun.h> 4429e83d4bSgd78059 #include <sys/cmn_err.h> 4529e83d4bSgd78059 #include <sys/dlpi.h> 4629e83d4bSgd78059 #include <sys/ethernet.h> 4729e83d4bSgd78059 #include <sys/kmem.h> 4829e83d4bSgd78059 #include <sys/time.h> 4929e83d4bSgd78059 #include <sys/miiregs.h> 5029e83d4bSgd78059 #include <sys/strsun.h> 5129e83d4bSgd78059 #include <sys/mac.h> 5229e83d4bSgd78059 #include <sys/mac_ether.h> 5329e83d4bSgd78059 #include <sys/ddi.h> 5429e83d4bSgd78059 #include <sys/sunddi.h> 55d62bc4baSyz147064 #include <sys/vlan.h> 5629e83d4bSgd78059 5729e83d4bSgd78059 #include "mxfe.h" 5829e83d4bSgd78059 #include "mxfeimpl.h" 5929e83d4bSgd78059 6029e83d4bSgd78059 /* 6129e83d4bSgd78059 * Driver globals. 6229e83d4bSgd78059 */ 6329e83d4bSgd78059 6429e83d4bSgd78059 /* patchable debug flag ... must not be static! */ 6529e83d4bSgd78059 #ifdef DEBUG 6629e83d4bSgd78059 unsigned mxfe_debug = DWARN; 6729e83d4bSgd78059 #endif 6829e83d4bSgd78059 6929e83d4bSgd78059 /* table of supported devices */ 7029e83d4bSgd78059 static mxfe_card_t mxfe_cards[] = { 7129e83d4bSgd78059 7229e83d4bSgd78059 /* 7329e83d4bSgd78059 * Lite-On products 7429e83d4bSgd78059 */ 7529e83d4bSgd78059 { 0x11ad, 0xc115, 0, 0, "Lite-On LC82C115", MXFE_PNICII }, 7629e83d4bSgd78059 7729e83d4bSgd78059 /* 7829e83d4bSgd78059 * Macronix chips 7929e83d4bSgd78059 */ 8029e83d4bSgd78059 { 0x10d9, 0x0531, 0x25, 0xff, "Macronix MX98715AEC", MXFE_98715AEC }, 8129e83d4bSgd78059 { 0x10d9, 0x0531, 0x20, 0xff, "Macronix MX98715A", MXFE_98715A }, 8229e83d4bSgd78059 { 0x10d9, 0x0531, 0x60, 0xff, "Macronix MX98715B", MXFE_98715B }, 8329e83d4bSgd78059 { 0x10d9, 0x0531, 0x30, 0xff, "Macronix MX98725", MXFE_98725 }, 8429e83d4bSgd78059 { 0x10d9, 0x0531, 0x00, 0xff, "Macronix MX98715", MXFE_98715 }, 8529e83d4bSgd78059 { 0x10d9, 0x0512, 0, 0, "Macronix MX98713", MXFE_98713 }, 8629e83d4bSgd78059 8729e83d4bSgd78059 /* 8829e83d4bSgd78059 * Compex (relabeled Macronix products) 8929e83d4bSgd78059 */ 9029e83d4bSgd78059 { 0x11fc, 0x9881, 0x00, 0x00, "Compex 9881", MXFE_98713 }, 9129e83d4bSgd78059 { 0x11fc, 0x9881, 0x10, 0xff, "Compex 9881A", MXFE_98713A }, 9229e83d4bSgd78059 /* 9329e83d4bSgd78059 * Models listed here 9429e83d4bSgd78059 */ 9529e83d4bSgd78059 { 0x11ad, 0xc001, 0, 0, "Linksys LNE100TX", MXFE_PNICII }, 9629e83d4bSgd78059 { 0x2646, 0x000b, 0, 0, "Kingston KNE111TX", MXFE_PNICII }, 9729e83d4bSgd78059 { 0x1154, 0x0308, 0, 0, "Buffalo LGY-PCI-TXL", MXFE_98715AEC }, 9829e83d4bSgd78059 }; 9929e83d4bSgd78059 10029e83d4bSgd78059 #define ETHERVLANMTU (ETHERMAX + 4) 10129e83d4bSgd78059 10229e83d4bSgd78059 /* 10329e83d4bSgd78059 * Function prototypes 10429e83d4bSgd78059 */ 10529e83d4bSgd78059 static int mxfe_attach(dev_info_t *, ddi_attach_cmd_t); 10629e83d4bSgd78059 static int mxfe_detach(dev_info_t *, ddi_detach_cmd_t); 10729e83d4bSgd78059 static int mxfe_resume(dev_info_t *); 10877860f66SGarrett D'Amore static int mxfe_quiesce(dev_info_t *); 10929e83d4bSgd78059 static int mxfe_m_unicst(void *, const uint8_t *); 11029e83d4bSgd78059 static int mxfe_m_multicst(void *, boolean_t, const uint8_t *); 11129e83d4bSgd78059 static int mxfe_m_promisc(void *, boolean_t); 11229e83d4bSgd78059 static mblk_t *mxfe_m_tx(void *, mblk_t *); 11329e83d4bSgd78059 static int mxfe_m_stat(void *, uint_t, uint64_t *); 11429e83d4bSgd78059 static int mxfe_m_start(void *); 11529e83d4bSgd78059 static void mxfe_m_stop(void *); 11696fb08b9Sgd78059 static int mxfe_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 117*0dc2366fSVenugopal Iyer void *); 11896fb08b9Sgd78059 static int mxfe_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 11996fb08b9Sgd78059 const void *); 120*0dc2366fSVenugopal Iyer static void mxfe_m_propinfo(void *, const char *, mac_prop_id_t, 121*0dc2366fSVenugopal Iyer mac_prop_info_handle_t); 12229e83d4bSgd78059 static unsigned mxfe_intr(caddr_t); 12329e83d4bSgd78059 static void mxfe_startmac(mxfe_t *); 12429e83d4bSgd78059 static void mxfe_stopmac(mxfe_t *); 12529e83d4bSgd78059 static void mxfe_resetrings(mxfe_t *); 12629e83d4bSgd78059 static boolean_t mxfe_initialize(mxfe_t *); 12729e83d4bSgd78059 static void mxfe_startall(mxfe_t *); 12829e83d4bSgd78059 static void mxfe_stopall(mxfe_t *); 12929e83d4bSgd78059 static void mxfe_resetall(mxfe_t *); 13029e83d4bSgd78059 static mxfe_txbuf_t *mxfe_alloctxbuf(mxfe_t *); 13129e83d4bSgd78059 static void mxfe_destroytxbuf(mxfe_txbuf_t *); 13229e83d4bSgd78059 static mxfe_rxbuf_t *mxfe_allocrxbuf(mxfe_t *); 13329e83d4bSgd78059 static void mxfe_destroyrxbuf(mxfe_rxbuf_t *); 13429e83d4bSgd78059 static void mxfe_send_setup(mxfe_t *); 13529e83d4bSgd78059 static boolean_t mxfe_send(mxfe_t *, mblk_t *); 13629e83d4bSgd78059 static int mxfe_allocrxring(mxfe_t *); 13729e83d4bSgd78059 static void mxfe_freerxring(mxfe_t *); 13829e83d4bSgd78059 static int mxfe_alloctxring(mxfe_t *); 13929e83d4bSgd78059 static void mxfe_freetxring(mxfe_t *); 14029e83d4bSgd78059 static void mxfe_error(dev_info_t *, char *, ...); 14129e83d4bSgd78059 static uint8_t mxfe_sromwidth(mxfe_t *); 14229e83d4bSgd78059 static uint16_t mxfe_readsromword(mxfe_t *, unsigned); 14329e83d4bSgd78059 static void mxfe_readsrom(mxfe_t *, unsigned, unsigned, void *); 14429e83d4bSgd78059 static void mxfe_getfactaddr(mxfe_t *, uchar_t *); 14596fb08b9Sgd78059 static uint8_t mxfe_miireadbit(mxfe_t *); 14696fb08b9Sgd78059 static void mxfe_miiwritebit(mxfe_t *, uint8_t); 14729e83d4bSgd78059 static void mxfe_miitristate(mxfe_t *); 14896fb08b9Sgd78059 static uint16_t mxfe_miiread(mxfe_t *, int, int); 14929e83d4bSgd78059 static void mxfe_miiwrite(mxfe_t *, int, int, uint16_t); 15096fb08b9Sgd78059 static uint16_t mxfe_miireadgeneral(mxfe_t *, int, int); 15129e83d4bSgd78059 static void mxfe_miiwritegeneral(mxfe_t *, int, int, uint16_t); 15296fb08b9Sgd78059 static uint16_t mxfe_miiread98713(mxfe_t *, int, int); 15329e83d4bSgd78059 static void mxfe_miiwrite98713(mxfe_t *, int, int, uint16_t); 15429e83d4bSgd78059 static void mxfe_startphy(mxfe_t *); 15529e83d4bSgd78059 static void mxfe_stopphy(mxfe_t *); 15629e83d4bSgd78059 static void mxfe_startphymii(mxfe_t *); 15729e83d4bSgd78059 static void mxfe_startphynway(mxfe_t *); 15829e83d4bSgd78059 static void mxfe_startnway(mxfe_t *); 15929e83d4bSgd78059 static void mxfe_reportlink(mxfe_t *); 16029e83d4bSgd78059 static void mxfe_checklink(mxfe_t *); 16129e83d4bSgd78059 static void mxfe_checklinkmii(mxfe_t *); 16229e83d4bSgd78059 static void mxfe_checklinknway(mxfe_t *); 16329e83d4bSgd78059 static void mxfe_disableinterrupts(mxfe_t *); 16429e83d4bSgd78059 static void mxfe_enableinterrupts(mxfe_t *); 16529e83d4bSgd78059 static void mxfe_reclaim(mxfe_t *); 16677860f66SGarrett D'Amore static boolean_t mxfe_receive(mxfe_t *, mblk_t **); 16729e83d4bSgd78059 16829e83d4bSgd78059 #ifdef DEBUG 16929e83d4bSgd78059 static void mxfe_dprintf(mxfe_t *, const char *, int, char *, ...); 17029e83d4bSgd78059 #endif 17129e83d4bSgd78059 17229e83d4bSgd78059 #define KIOIP KSTAT_INTR_PTR(mxfep->mxfe_intrstat) 17329e83d4bSgd78059 17429e83d4bSgd78059 static mac_callbacks_t mxfe_m_callbacks = { 175*0dc2366fSVenugopal Iyer MC_SETPROP | MC_GETPROP | MC_PROPINFO, 17629e83d4bSgd78059 mxfe_m_stat, 17729e83d4bSgd78059 mxfe_m_start, 17829e83d4bSgd78059 mxfe_m_stop, 17929e83d4bSgd78059 mxfe_m_promisc, 18029e83d4bSgd78059 mxfe_m_multicst, 18129e83d4bSgd78059 mxfe_m_unicst, 18229e83d4bSgd78059 mxfe_m_tx, 183*0dc2366fSVenugopal Iyer NULL, 18496fb08b9Sgd78059 NULL, /* mc_ioctl */ 18596fb08b9Sgd78059 NULL, /* mc_getcapab */ 18696fb08b9Sgd78059 NULL, /* mc_open */ 18796fb08b9Sgd78059 NULL, /* mc_close */ 18896fb08b9Sgd78059 mxfe_m_setprop, 189*0dc2366fSVenugopal Iyer mxfe_m_getprop, 190*0dc2366fSVenugopal Iyer mxfe_m_propinfo 19129e83d4bSgd78059 }; 19229e83d4bSgd78059 19329e83d4bSgd78059 /* 19429e83d4bSgd78059 * Stream information 19529e83d4bSgd78059 */ 19629e83d4bSgd78059 DDI_DEFINE_STREAM_OPS(mxfe_devops, nulldev, nulldev, mxfe_attach, mxfe_detach, 19777860f66SGarrett D'Amore nodev, NULL, D_MP, NULL, mxfe_quiesce); 19829e83d4bSgd78059 19929e83d4bSgd78059 /* 20029e83d4bSgd78059 * Module linkage information. 20129e83d4bSgd78059 */ 20229e83d4bSgd78059 20329e83d4bSgd78059 static struct modldrv mxfe_modldrv = { 20429e83d4bSgd78059 &mod_driverops, /* drv_modops */ 20529e83d4bSgd78059 "Macronix Fast Ethernet", /* drv_linkinfo */ 20629e83d4bSgd78059 &mxfe_devops /* drv_dev_ops */ 20729e83d4bSgd78059 }; 20829e83d4bSgd78059 20929e83d4bSgd78059 static struct modlinkage mxfe_modlinkage = { 21029e83d4bSgd78059 MODREV_1, /* ml_rev */ 21129e83d4bSgd78059 { &mxfe_modldrv, NULL } /* ml_linkage */ 21229e83d4bSgd78059 }; 21329e83d4bSgd78059 21429e83d4bSgd78059 /* 21529e83d4bSgd78059 * Device attributes. 21629e83d4bSgd78059 */ 21729e83d4bSgd78059 static ddi_device_acc_attr_t mxfe_devattr = { 21829e83d4bSgd78059 DDI_DEVICE_ATTR_V0, 21929e83d4bSgd78059 DDI_STRUCTURE_LE_ACC, 22029e83d4bSgd78059 DDI_STRICTORDER_ACC 22129e83d4bSgd78059 }; 22229e83d4bSgd78059 22329e83d4bSgd78059 static ddi_device_acc_attr_t mxfe_bufattr = { 22429e83d4bSgd78059 DDI_DEVICE_ATTR_V0, 22529e83d4bSgd78059 DDI_NEVERSWAP_ACC, 22629e83d4bSgd78059 DDI_STRICTORDER_ACC 22729e83d4bSgd78059 }; 22829e83d4bSgd78059 22929e83d4bSgd78059 static ddi_dma_attr_t mxfe_dma_attr = { 23029e83d4bSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 23129e83d4bSgd78059 0, /* dma_attr_addr_lo */ 23229e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 23329e83d4bSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 23429e83d4bSgd78059 4, /* dma_attr_align */ 23529e83d4bSgd78059 0x3F, /* dma_attr_burstsizes */ 23629e83d4bSgd78059 1, /* dma_attr_minxfer */ 23729e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 23829e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 23929e83d4bSgd78059 1, /* dma_attr_sgllen */ 24029e83d4bSgd78059 1, /* dma_attr_granular */ 24129e83d4bSgd78059 0 /* dma_attr_flags */ 24229e83d4bSgd78059 }; 24329e83d4bSgd78059 24429e83d4bSgd78059 /* 24529e83d4bSgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can 24629e83d4bSgd78059 * cross a page boundary, so we use the two buffer addresses of the 24729e83d4bSgd78059 * chip to provide a two-entry scatter-gather list. 24829e83d4bSgd78059 */ 24929e83d4bSgd78059 static ddi_dma_attr_t mxfe_dma_txattr = { 25029e83d4bSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 25129e83d4bSgd78059 0, /* dma_attr_addr_lo */ 25229e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 25329e83d4bSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 25429e83d4bSgd78059 1, /* dma_attr_align */ 25529e83d4bSgd78059 0x3F, /* dma_attr_burstsizes */ 25629e83d4bSgd78059 1, /* dma_attr_minxfer */ 25729e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 25829e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 25929e83d4bSgd78059 2, /* dma_attr_sgllen */ 26029e83d4bSgd78059 1, /* dma_attr_granular */ 26129e83d4bSgd78059 0 /* dma_attr_flags */ 26229e83d4bSgd78059 }; 26329e83d4bSgd78059 26429e83d4bSgd78059 /* 26529e83d4bSgd78059 * Ethernet addresses. 26629e83d4bSgd78059 */ 26729e83d4bSgd78059 static uchar_t mxfe_broadcast[ETHERADDRL] = { 26829e83d4bSgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 26929e83d4bSgd78059 }; 27029e83d4bSgd78059 27129e83d4bSgd78059 /* 27229e83d4bSgd78059 * DDI entry points. 27329e83d4bSgd78059 */ 27429e83d4bSgd78059 int 27529e83d4bSgd78059 _init(void) 27629e83d4bSgd78059 { 27729e83d4bSgd78059 int rv; 27829e83d4bSgd78059 mac_init_ops(&mxfe_devops, "mxfe"); 27929e83d4bSgd78059 if ((rv = mod_install(&mxfe_modlinkage)) != DDI_SUCCESS) { 28029e83d4bSgd78059 mac_fini_ops(&mxfe_devops); 28129e83d4bSgd78059 } 28229e83d4bSgd78059 return (rv); 28329e83d4bSgd78059 } 28429e83d4bSgd78059 28529e83d4bSgd78059 int 28629e83d4bSgd78059 _fini(void) 28729e83d4bSgd78059 { 28829e83d4bSgd78059 int rv; 28929e83d4bSgd78059 if ((rv = mod_remove(&mxfe_modlinkage)) == DDI_SUCCESS) { 29029e83d4bSgd78059 mac_fini_ops(&mxfe_devops); 29129e83d4bSgd78059 } 29229e83d4bSgd78059 return (rv); 29329e83d4bSgd78059 } 29429e83d4bSgd78059 29529e83d4bSgd78059 int 29629e83d4bSgd78059 _info(struct modinfo *modinfop) 29729e83d4bSgd78059 { 29829e83d4bSgd78059 return (mod_info(&mxfe_modlinkage, modinfop)); 29929e83d4bSgd78059 } 30029e83d4bSgd78059 30129e83d4bSgd78059 int 30229e83d4bSgd78059 mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 30329e83d4bSgd78059 { 30429e83d4bSgd78059 mxfe_t *mxfep; 30529e83d4bSgd78059 mac_register_t *macp; 30629e83d4bSgd78059 int inst = ddi_get_instance(dip); 30729e83d4bSgd78059 ddi_acc_handle_t pci; 30829e83d4bSgd78059 uint16_t venid; 30929e83d4bSgd78059 uint16_t devid; 31029e83d4bSgd78059 uint16_t revid; 31129e83d4bSgd78059 uint16_t svid; 31229e83d4bSgd78059 uint16_t ssid; 31329e83d4bSgd78059 uint16_t cachesize; 31429e83d4bSgd78059 mxfe_card_t *cardp; 31529e83d4bSgd78059 int i; 31629e83d4bSgd78059 31729e83d4bSgd78059 switch (cmd) { 31829e83d4bSgd78059 case DDI_RESUME: 31929e83d4bSgd78059 return (mxfe_resume(dip)); 32029e83d4bSgd78059 32129e83d4bSgd78059 case DDI_ATTACH: 32229e83d4bSgd78059 break; 32329e83d4bSgd78059 32429e83d4bSgd78059 default: 32529e83d4bSgd78059 return (DDI_FAILURE); 32629e83d4bSgd78059 } 32729e83d4bSgd78059 32829e83d4bSgd78059 /* this card is a bus master, reject any slave-only slot */ 32929e83d4bSgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) { 33029e83d4bSgd78059 mxfe_error(dip, "slot does not support PCI bus-master"); 33129e83d4bSgd78059 return (DDI_FAILURE); 33229e83d4bSgd78059 } 33329e83d4bSgd78059 /* PCI devices shouldn't generate hilevel interrupts */ 33429e83d4bSgd78059 if (ddi_intr_hilevel(dip, 0) != 0) { 33529e83d4bSgd78059 mxfe_error(dip, "hilevel interrupts not supported"); 33629e83d4bSgd78059 return (DDI_FAILURE); 33729e83d4bSgd78059 } 33829e83d4bSgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 33929e83d4bSgd78059 mxfe_error(dip, "unable to setup PCI config handle"); 34029e83d4bSgd78059 return (DDI_FAILURE); 34129e83d4bSgd78059 } 34229e83d4bSgd78059 34329e83d4bSgd78059 venid = pci_config_get16(pci, PCI_VID); 34429e83d4bSgd78059 devid = pci_config_get16(pci, PCI_DID); 34529e83d4bSgd78059 revid = pci_config_get16(pci, PCI_RID); 34629e83d4bSgd78059 svid = pci_config_get16(pci, PCI_SVID); 34729e83d4bSgd78059 ssid = pci_config_get16(pci, PCI_SSID); 34829e83d4bSgd78059 34929e83d4bSgd78059 /* 35029e83d4bSgd78059 * the last entry in the card table matches every possible 35129e83d4bSgd78059 * card, so the for-loop always terminates properly. 35229e83d4bSgd78059 */ 35329e83d4bSgd78059 cardp = NULL; 35429e83d4bSgd78059 for (i = 0; i < (sizeof (mxfe_cards) / sizeof (mxfe_card_t)); i++) { 35529e83d4bSgd78059 if ((venid == mxfe_cards[i].card_venid) && 35629e83d4bSgd78059 (devid == mxfe_cards[i].card_devid) && 35729e83d4bSgd78059 ((revid & mxfe_cards[i].card_revmask) == 35829e83d4bSgd78059 mxfe_cards[i].card_revid)) { 35929e83d4bSgd78059 cardp = &mxfe_cards[i]; 36029e83d4bSgd78059 } 36129e83d4bSgd78059 if ((svid == mxfe_cards[i].card_venid) && 36229e83d4bSgd78059 (ssid == mxfe_cards[i].card_devid) && 36329e83d4bSgd78059 ((revid & mxfe_cards[i].card_revmask) == 36429e83d4bSgd78059 mxfe_cards[i].card_revid)) { 36529e83d4bSgd78059 cardp = &mxfe_cards[i]; 36629e83d4bSgd78059 break; 36729e83d4bSgd78059 } 36829e83d4bSgd78059 } 36929e83d4bSgd78059 37029e83d4bSgd78059 if (cardp == NULL) { 37129e83d4bSgd78059 pci_config_teardown(&pci); 37229e83d4bSgd78059 mxfe_error(dip, "Unable to identify PCI card"); 37329e83d4bSgd78059 return (DDI_FAILURE); 37429e83d4bSgd78059 } 37529e83d4bSgd78059 37629e83d4bSgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model", 37729e83d4bSgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) { 37829e83d4bSgd78059 pci_config_teardown(&pci); 37929e83d4bSgd78059 mxfe_error(dip, "Unable to create model property"); 38029e83d4bSgd78059 return (DDI_FAILURE); 38129e83d4bSgd78059 } 38229e83d4bSgd78059 38329e83d4bSgd78059 /* 38429e83d4bSgd78059 * Grab the PCI cachesize -- we use this to program the 38529e83d4bSgd78059 * cache-optimization bus access bits. 38629e83d4bSgd78059 */ 38729e83d4bSgd78059 cachesize = pci_config_get8(pci, PCI_CLS); 38829e83d4bSgd78059 38929e83d4bSgd78059 /* this cannot fail */ 39029e83d4bSgd78059 mxfep = kmem_zalloc(sizeof (mxfe_t), KM_SLEEP); 39129e83d4bSgd78059 ddi_set_driver_private(dip, mxfep); 39229e83d4bSgd78059 39329e83d4bSgd78059 /* get the interrupt block cookie */ 39429e83d4bSgd78059 if (ddi_get_iblock_cookie(dip, 0, &mxfep->mxfe_icookie) 39529e83d4bSgd78059 != DDI_SUCCESS) { 39629e83d4bSgd78059 mxfe_error(dip, "ddi_get_iblock_cookie failed"); 39729e83d4bSgd78059 pci_config_teardown(&pci); 39829e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 39929e83d4bSgd78059 return (DDI_FAILURE); 40029e83d4bSgd78059 } 40129e83d4bSgd78059 40229e83d4bSgd78059 mxfep->mxfe_dip = dip; 40329e83d4bSgd78059 mxfep->mxfe_cardp = cardp; 40429e83d4bSgd78059 mxfep->mxfe_phyaddr = -1; 40529e83d4bSgd78059 mxfep->mxfe_cachesize = cachesize; 40629e83d4bSgd78059 40729e83d4bSgd78059 /* default properties */ 40829e83d4bSgd78059 mxfep->mxfe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 40929e83d4bSgd78059 "adv_autoneg_cap", 1); 41029e83d4bSgd78059 mxfep->mxfe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 41129e83d4bSgd78059 "adv_100T4_cap", 1); 41229e83d4bSgd78059 mxfep->mxfe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 41329e83d4bSgd78059 "adv_100fdx_cap", 1); 41429e83d4bSgd78059 mxfep->mxfe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 41529e83d4bSgd78059 "adv_100hdx_cap", 1); 41629e83d4bSgd78059 mxfep->mxfe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 41729e83d4bSgd78059 "adv_10fdx_cap", 1); 41829e83d4bSgd78059 mxfep->mxfe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 41929e83d4bSgd78059 "adv_10hdx_cap", 1); 42029e83d4bSgd78059 42129e83d4bSgd78059 DBG(DPCI, "PCI vendor id = %x", venid); 42229e83d4bSgd78059 DBG(DPCI, "PCI device id = %x", devid); 42329e83d4bSgd78059 DBG(DPCI, "PCI revision id = %x", revid); 42429e83d4bSgd78059 DBG(DPCI, "PCI cachesize = %d", cachesize); 42529e83d4bSgd78059 DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD)); 42629e83d4bSgd78059 DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT)); 42729e83d4bSgd78059 42829e83d4bSgd78059 mutex_init(&mxfep->mxfe_xmtlock, NULL, MUTEX_DRIVER, 42929e83d4bSgd78059 mxfep->mxfe_icookie); 43029e83d4bSgd78059 mutex_init(&mxfep->mxfe_intrlock, NULL, MUTEX_DRIVER, 43129e83d4bSgd78059 mxfep->mxfe_icookie); 43229e83d4bSgd78059 43329e83d4bSgd78059 /* 43429e83d4bSgd78059 * Enable bus master, IO space, and memory space accesses. 43529e83d4bSgd78059 */ 43629e83d4bSgd78059 pci_config_put16(pci, PCI_CMD, 43729e83d4bSgd78059 pci_config_get16(pci, PCI_CMD) | 43829e83d4bSgd78059 PCI_CMD_BME | PCI_CMD_MAE | PCI_CMD_MWIE); 43929e83d4bSgd78059 44029e83d4bSgd78059 /* we're done with this now, drop it */ 44129e83d4bSgd78059 pci_config_teardown(&pci); 44229e83d4bSgd78059 44329e83d4bSgd78059 /* 44429e83d4bSgd78059 * Initialize interrupt kstat. This should not normally fail, since 44529e83d4bSgd78059 * we don't use a persistent stat. We do it this way to avoid having 44629e83d4bSgd78059 * to test for it at run time on the hot path. 44729e83d4bSgd78059 */ 44829e83d4bSgd78059 mxfep->mxfe_intrstat = kstat_create("mxfe", inst, "intr", "controller", 44929e83d4bSgd78059 KSTAT_TYPE_INTR, 1, 0); 45029e83d4bSgd78059 if (mxfep->mxfe_intrstat == NULL) { 45129e83d4bSgd78059 mxfe_error(dip, "kstat_create failed"); 45229e83d4bSgd78059 goto failed; 45329e83d4bSgd78059 } 45429e83d4bSgd78059 kstat_install(mxfep->mxfe_intrstat); 45529e83d4bSgd78059 45629e83d4bSgd78059 /* 45729e83d4bSgd78059 * Map in the device registers. 45829e83d4bSgd78059 */ 45929e83d4bSgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mxfep->mxfe_regs, 46029e83d4bSgd78059 0, 0, &mxfe_devattr, &mxfep->mxfe_regshandle)) { 46129e83d4bSgd78059 mxfe_error(dip, "ddi_regs_map_setup failed"); 46229e83d4bSgd78059 goto failed; 46329e83d4bSgd78059 } 46429e83d4bSgd78059 46529e83d4bSgd78059 /* 46629e83d4bSgd78059 * Allocate DMA resources (descriptor rings and buffers). 46729e83d4bSgd78059 */ 46829e83d4bSgd78059 if ((mxfe_allocrxring(mxfep) != DDI_SUCCESS) || 46929e83d4bSgd78059 (mxfe_alloctxring(mxfep) != DDI_SUCCESS)) { 47029e83d4bSgd78059 mxfe_error(dip, "unable to allocate DMA resources"); 47129e83d4bSgd78059 goto failed; 47229e83d4bSgd78059 } 47329e83d4bSgd78059 47429e83d4bSgd78059 /* Initialize the chip. */ 47529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 47629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 47729e83d4bSgd78059 if (!mxfe_initialize(mxfep)) { 47829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 47929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 48029e83d4bSgd78059 goto failed; 48129e83d4bSgd78059 } 48229e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 48329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 48429e83d4bSgd78059 48529e83d4bSgd78059 /* Determine the number of address bits to our EEPROM. */ 48629e83d4bSgd78059 mxfep->mxfe_sromwidth = mxfe_sromwidth(mxfep); 48729e83d4bSgd78059 48829e83d4bSgd78059 /* 48929e83d4bSgd78059 * Get the factory ethernet address. This becomes the current 49029e83d4bSgd78059 * ethernet address (it can be overridden later via ifconfig). 49129e83d4bSgd78059 */ 49229e83d4bSgd78059 mxfe_getfactaddr(mxfep, mxfep->mxfe_curraddr); 49329e83d4bSgd78059 mxfep->mxfe_promisc = B_FALSE; 49429e83d4bSgd78059 49529e83d4bSgd78059 /* 49629e83d4bSgd78059 * Establish interrupt handler. 49729e83d4bSgd78059 */ 49829e83d4bSgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, mxfe_intr, (caddr_t)mxfep) != 49929e83d4bSgd78059 DDI_SUCCESS) { 50029e83d4bSgd78059 mxfe_error(dip, "unable to add interrupt"); 50129e83d4bSgd78059 goto failed; 50229e83d4bSgd78059 } 50329e83d4bSgd78059 50429e83d4bSgd78059 /* TODO: do the power management stuff */ 50529e83d4bSgd78059 50629e83d4bSgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 50729e83d4bSgd78059 mxfe_error(dip, "mac_alloc failed"); 50829e83d4bSgd78059 goto failed; 50929e83d4bSgd78059 } 51029e83d4bSgd78059 51129e83d4bSgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 51229e83d4bSgd78059 macp->m_driver = mxfep; 51329e83d4bSgd78059 macp->m_dip = dip; 51429e83d4bSgd78059 macp->m_src_addr = mxfep->mxfe_curraddr; 51529e83d4bSgd78059 macp->m_callbacks = &mxfe_m_callbacks; 51629e83d4bSgd78059 macp->m_min_sdu = 0; 51729e83d4bSgd78059 macp->m_max_sdu = ETHERMTU; 518d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ; 51929e83d4bSgd78059 52029e83d4bSgd78059 if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) { 52129e83d4bSgd78059 mac_free(macp); 52229e83d4bSgd78059 return (DDI_SUCCESS); 52329e83d4bSgd78059 } 52429e83d4bSgd78059 52529e83d4bSgd78059 /* failed to register with MAC */ 52629e83d4bSgd78059 mac_free(macp); 52729e83d4bSgd78059 failed: 52829e83d4bSgd78059 if (mxfep->mxfe_icookie != NULL) { 52929e83d4bSgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie); 53029e83d4bSgd78059 } 53129e83d4bSgd78059 if (mxfep->mxfe_intrstat) { 53229e83d4bSgd78059 kstat_delete(mxfep->mxfe_intrstat); 53329e83d4bSgd78059 } 53429e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_intrlock); 53529e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_xmtlock); 53629e83d4bSgd78059 53729e83d4bSgd78059 mxfe_freerxring(mxfep); 53829e83d4bSgd78059 mxfe_freetxring(mxfep); 53929e83d4bSgd78059 54029e83d4bSgd78059 if (mxfep->mxfe_regshandle != NULL) { 54129e83d4bSgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle); 54229e83d4bSgd78059 } 54329e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 54429e83d4bSgd78059 return (DDI_FAILURE); 54529e83d4bSgd78059 } 54629e83d4bSgd78059 54729e83d4bSgd78059 int 54829e83d4bSgd78059 mxfe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 54929e83d4bSgd78059 { 55029e83d4bSgd78059 mxfe_t *mxfep; 55129e83d4bSgd78059 55229e83d4bSgd78059 mxfep = ddi_get_driver_private(dip); 55329e83d4bSgd78059 if (mxfep == NULL) { 55429e83d4bSgd78059 mxfe_error(dip, "no soft state in detach!"); 55529e83d4bSgd78059 return (DDI_FAILURE); 55629e83d4bSgd78059 } 55729e83d4bSgd78059 55829e83d4bSgd78059 switch (cmd) { 55929e83d4bSgd78059 case DDI_DETACH: 56029e83d4bSgd78059 56129e83d4bSgd78059 if (mac_unregister(mxfep->mxfe_mh) != 0) { 56229e83d4bSgd78059 return (DDI_FAILURE); 56329e83d4bSgd78059 } 56429e83d4bSgd78059 56529e83d4bSgd78059 /* make sure hardware is quiesced */ 56629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 56729e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 56829e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING; 56929e83d4bSgd78059 mxfe_stopall(mxfep); 57029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 57129e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 57229e83d4bSgd78059 57329e83d4bSgd78059 /* clean up and shut down device */ 57429e83d4bSgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie); 57529e83d4bSgd78059 57629e83d4bSgd78059 /* clean up kstats */ 57729e83d4bSgd78059 kstat_delete(mxfep->mxfe_intrstat); 57829e83d4bSgd78059 57929e83d4bSgd78059 ddi_prop_remove_all(dip); 58029e83d4bSgd78059 58129e83d4bSgd78059 /* free up any left over buffers or DMA resources */ 58229e83d4bSgd78059 mxfe_freerxring(mxfep); 58329e83d4bSgd78059 mxfe_freetxring(mxfep); 58429e83d4bSgd78059 58529e83d4bSgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle); 58629e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_intrlock); 58729e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_xmtlock); 58829e83d4bSgd78059 58929e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 59029e83d4bSgd78059 return (DDI_SUCCESS); 59129e83d4bSgd78059 59229e83d4bSgd78059 case DDI_SUSPEND: 59329e83d4bSgd78059 /* quiesce the hardware */ 59429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 59529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 59629e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED; 59729e83d4bSgd78059 mxfe_stopall(mxfep); 59829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 59929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 60029e83d4bSgd78059 return (DDI_SUCCESS); 60129e83d4bSgd78059 default: 60229e83d4bSgd78059 return (DDI_FAILURE); 60329e83d4bSgd78059 } 60429e83d4bSgd78059 } 60529e83d4bSgd78059 60629e83d4bSgd78059 int 60729e83d4bSgd78059 mxfe_resume(dev_info_t *dip) 60829e83d4bSgd78059 { 60929e83d4bSgd78059 mxfe_t *mxfep; 61029e83d4bSgd78059 61129e83d4bSgd78059 if ((mxfep = ddi_get_driver_private(dip)) == NULL) { 61229e83d4bSgd78059 return (DDI_FAILURE); 61329e83d4bSgd78059 } 61429e83d4bSgd78059 61529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 61629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 61729e83d4bSgd78059 61829e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_SUSPENDED; 61929e83d4bSgd78059 62029e83d4bSgd78059 /* re-initialize chip */ 62129e83d4bSgd78059 if (!mxfe_initialize(mxfep)) { 62229e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "unable to resume chip!"); 62329e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED; 62429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 62529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 62629e83d4bSgd78059 return (DDI_SUCCESS); 62729e83d4bSgd78059 } 62829e83d4bSgd78059 62929e83d4bSgd78059 /* start the chip */ 63029e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) { 63129e83d4bSgd78059 mxfe_startall(mxfep); 63229e83d4bSgd78059 } 63329e83d4bSgd78059 63429e83d4bSgd78059 /* drop locks */ 63529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 63629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 63729e83d4bSgd78059 63829e83d4bSgd78059 return (DDI_SUCCESS); 63929e83d4bSgd78059 } 64029e83d4bSgd78059 64177860f66SGarrett D'Amore int 64277860f66SGarrett D'Amore mxfe_quiesce(dev_info_t *dip) 64377860f66SGarrett D'Amore { 64477860f66SGarrett D'Amore mxfe_t *mxfep; 64577860f66SGarrett D'Amore 64677860f66SGarrett D'Amore if ((mxfep = ddi_get_driver_private(dip)) == NULL) { 64777860f66SGarrett D'Amore return (DDI_FAILURE); 64877860f66SGarrett D'Amore } 64977860f66SGarrett D'Amore 65077860f66SGarrett D'Amore /* just do a hard reset of everything */ 65177860f66SGarrett D'Amore SETBIT(mxfep, CSR_PAR, PAR_RESET); 65277860f66SGarrett D'Amore 65377860f66SGarrett D'Amore return (DDI_SUCCESS); 65477860f66SGarrett D'Amore } 65577860f66SGarrett D'Amore 65629e83d4bSgd78059 /*ARGSUSED*/ 65729e83d4bSgd78059 int 65829e83d4bSgd78059 mxfe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 65929e83d4bSgd78059 { 66029e83d4bSgd78059 /* we already receive all multicast frames */ 66129e83d4bSgd78059 return (0); 66229e83d4bSgd78059 } 66329e83d4bSgd78059 66429e83d4bSgd78059 int 66529e83d4bSgd78059 mxfe_m_promisc(void *arg, boolean_t on) 66629e83d4bSgd78059 { 66729e83d4bSgd78059 mxfe_t *mxfep = arg; 66829e83d4bSgd78059 66929e83d4bSgd78059 /* exclusive access to the card while we reprogram it */ 67029e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 67129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 67229e83d4bSgd78059 /* save current promiscuous mode state for replay in resume */ 67329e83d4bSgd78059 mxfep->mxfe_promisc = on; 67429e83d4bSgd78059 67529e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == 67629e83d4bSgd78059 MXFE_RUNNING) { 67729e83d4bSgd78059 if (on) 67829e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 67929e83d4bSgd78059 else 68029e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 68129e83d4bSgd78059 } 68229e83d4bSgd78059 68329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 68429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 68529e83d4bSgd78059 68629e83d4bSgd78059 return (0); 68729e83d4bSgd78059 } 68829e83d4bSgd78059 68929e83d4bSgd78059 int 69029e83d4bSgd78059 mxfe_m_unicst(void *arg, const uint8_t *macaddr) 69129e83d4bSgd78059 { 69229e83d4bSgd78059 mxfe_t *mxfep = arg; 69329e83d4bSgd78059 69429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 69529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 69629e83d4bSgd78059 bcopy(macaddr, mxfep->mxfe_curraddr, ETHERADDRL); 69729e83d4bSgd78059 69829e83d4bSgd78059 mxfe_resetall(mxfep); 69929e83d4bSgd78059 70029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 70129e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 70229e83d4bSgd78059 70329e83d4bSgd78059 return (0); 70429e83d4bSgd78059 } 70529e83d4bSgd78059 70629e83d4bSgd78059 mblk_t * 70729e83d4bSgd78059 mxfe_m_tx(void *arg, mblk_t *mp) 70829e83d4bSgd78059 { 70929e83d4bSgd78059 mxfe_t *mxfep = arg; 71029e83d4bSgd78059 mblk_t *nmp; 71129e83d4bSgd78059 71229e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 71329e83d4bSgd78059 71429e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) { 71529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 71629e83d4bSgd78059 return (mp); 71729e83d4bSgd78059 } 71829e83d4bSgd78059 71929e83d4bSgd78059 while (mp != NULL) { 72029e83d4bSgd78059 nmp = mp->b_next; 72129e83d4bSgd78059 mp->b_next = NULL; 72229e83d4bSgd78059 72329e83d4bSgd78059 if (!mxfe_send(mxfep, mp)) { 72429e83d4bSgd78059 mp->b_next = nmp; 72529e83d4bSgd78059 break; 72629e83d4bSgd78059 } 72729e83d4bSgd78059 mp = nmp; 72829e83d4bSgd78059 } 72929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 73029e83d4bSgd78059 73129e83d4bSgd78059 return (mp); 73229e83d4bSgd78059 } 73329e83d4bSgd78059 73429e83d4bSgd78059 /* 73529e83d4bSgd78059 * Hardware management. 73629e83d4bSgd78059 */ 73729e83d4bSgd78059 boolean_t 73829e83d4bSgd78059 mxfe_initialize(mxfe_t *mxfep) 73929e83d4bSgd78059 { 74029e83d4bSgd78059 int i; 74129e83d4bSgd78059 unsigned val; 74229e83d4bSgd78059 uint32_t par, nar; 74329e83d4bSgd78059 74429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 74529e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 74629e83d4bSgd78059 74729e83d4bSgd78059 DBG(DCHATTY, "resetting!"); 74829e83d4bSgd78059 SETBIT(mxfep, CSR_PAR, PAR_RESET); 74929e83d4bSgd78059 for (i = 1; i < 10; i++) { 75029e83d4bSgd78059 drv_usecwait(5); 75129e83d4bSgd78059 val = GETCSR(mxfep, CSR_PAR); 75229e83d4bSgd78059 if (!(val & PAR_RESET)) { 75329e83d4bSgd78059 break; 75429e83d4bSgd78059 } 75529e83d4bSgd78059 } 75629e83d4bSgd78059 if (i == 10) { 75729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "timed out waiting for reset!"); 75829e83d4bSgd78059 return (B_FALSE); 75929e83d4bSgd78059 } 76029e83d4bSgd78059 76129e83d4bSgd78059 /* initialize busctl register */ 76229e83d4bSgd78059 par = PAR_BAR | PAR_MRME | PAR_MRLE | PAR_MWIE; 76329e83d4bSgd78059 76429e83d4bSgd78059 /* set the cache alignment if its supported */ 76529e83d4bSgd78059 switch (mxfep->mxfe_cachesize) { 76629e83d4bSgd78059 case 8: 76729e83d4bSgd78059 par |= PAR_CALIGN_8; 76829e83d4bSgd78059 break; 76929e83d4bSgd78059 case 16: 77029e83d4bSgd78059 par |= PAR_CALIGN_16; 77129e83d4bSgd78059 break; 77229e83d4bSgd78059 case 32: 77329e83d4bSgd78059 par |= PAR_CALIGN_32; 77429e83d4bSgd78059 break; 77529e83d4bSgd78059 default: 77629e83d4bSgd78059 par &= ~(PAR_MWIE | PAR_MRME | PAR_MRLE); 77729e83d4bSgd78059 } 77829e83d4bSgd78059 77929e83d4bSgd78059 /* leave the burst length at zero, indicating infinite burst */ 78029e83d4bSgd78059 PUTCSR(mxfep, CSR_PAR, par); 78129e83d4bSgd78059 78229e83d4bSgd78059 mxfe_resetrings(mxfep); 78329e83d4bSgd78059 78429e83d4bSgd78059 /* clear the lost packet counter (cleared on read) */ 78529e83d4bSgd78059 (void) GETCSR(mxfep, CSR_LPC); 78629e83d4bSgd78059 78729e83d4bSgd78059 /* a few other NAR bits */ 78829e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 78929e83d4bSgd78059 nar &= ~NAR_RX_HO; /* disable hash only filtering */ 79029e83d4bSgd78059 nar |= NAR_RX_HP; /* hash perfect forwarding */ 79129e83d4bSgd78059 nar |= NAR_RX_MULTI; /* receive all multicast */ 79229e83d4bSgd78059 nar |= NAR_SF; /* store-and-forward */ 79329e83d4bSgd78059 79429e83d4bSgd78059 if (mxfep->mxfe_promisc) { 79529e83d4bSgd78059 nar |= NAR_RX_PROMISC; 79629e83d4bSgd78059 } else { 79729e83d4bSgd78059 nar &= ~NAR_RX_PROMISC; 79829e83d4bSgd78059 } 79929e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 80029e83d4bSgd78059 80129e83d4bSgd78059 mxfe_send_setup(mxfep); 80229e83d4bSgd78059 80329e83d4bSgd78059 return (B_TRUE); 80429e83d4bSgd78059 } 80529e83d4bSgd78059 80629e83d4bSgd78059 /* 80729e83d4bSgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation. 80829e83d4bSgd78059 */ 80929e83d4bSgd78059 81029e83d4bSgd78059 uint8_t 81129e83d4bSgd78059 mxfe_sromwidth(mxfe_t *mxfep) 81229e83d4bSgd78059 { 81329e83d4bSgd78059 int i; 81429e83d4bSgd78059 int eeread; 81529e83d4bSgd78059 uint8_t addrlen = 8; 81629e83d4bSgd78059 81729e83d4bSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 81829e83d4bSgd78059 81929e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 82029e83d4bSgd78059 drv_usecwait(1); 82129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 82229e83d4bSgd78059 82329e83d4bSgd78059 /* command bits first */ 82429e83d4bSgd78059 for (i = 4; i != 0; i >>= 1) { 82529e83d4bSgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0; 82629e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val); 82729e83d4bSgd78059 drv_usecwait(1); 82829e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 82929e83d4bSgd78059 drv_usecwait(1); 83029e83d4bSgd78059 } 83129e83d4bSgd78059 83229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 83329e83d4bSgd78059 83429e83d4bSgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) { 83529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK); 83629e83d4bSgd78059 drv_usecwait(1); 83729e83d4bSgd78059 if (!(GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT)) { 83829e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 83929e83d4bSgd78059 drv_usecwait(1); 84029e83d4bSgd78059 break; 84129e83d4bSgd78059 } 84229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 84329e83d4bSgd78059 drv_usecwait(1); 84429e83d4bSgd78059 } 84529e83d4bSgd78059 84629e83d4bSgd78059 /* turn off accesses to the EEPROM */ 84729e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 84829e83d4bSgd78059 84929e83d4bSgd78059 DBG(DSROM, "detected srom width = %d bits", addrlen); 85029e83d4bSgd78059 85129e83d4bSgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen); 85229e83d4bSgd78059 } 85329e83d4bSgd78059 85429e83d4bSgd78059 /* 85529e83d4bSgd78059 * The words in EEPROM are stored in little endian order. We 85629e83d4bSgd78059 * shift bits out in big endian order, though. This requires 85729e83d4bSgd78059 * a byte swap on some platforms. 85829e83d4bSgd78059 */ 85929e83d4bSgd78059 uint16_t 86029e83d4bSgd78059 mxfe_readsromword(mxfe_t *mxfep, unsigned romaddr) 86129e83d4bSgd78059 { 86229e83d4bSgd78059 int i; 86329e83d4bSgd78059 uint16_t word = 0; 86429e83d4bSgd78059 uint16_t retval; 86529e83d4bSgd78059 int eeread; 86629e83d4bSgd78059 uint8_t addrlen; 86729e83d4bSgd78059 int readcmd; 86829e83d4bSgd78059 uchar_t *ptr; 86929e83d4bSgd78059 87029e83d4bSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 87129e83d4bSgd78059 addrlen = mxfep->mxfe_sromwidth; 87229e83d4bSgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr; 87329e83d4bSgd78059 87429e83d4bSgd78059 if (romaddr >= (1 << addrlen)) { 87529e83d4bSgd78059 /* too big to fit! */ 87629e83d4bSgd78059 return (0); 87729e83d4bSgd78059 } 87829e83d4bSgd78059 87929e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 88029e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 88129e83d4bSgd78059 88229e83d4bSgd78059 /* command and address bits */ 88329e83d4bSgd78059 for (i = 4 + addrlen; i >= 0; i--) { 88429e83d4bSgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0; 88529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val); 88629e83d4bSgd78059 drv_usecwait(1); 88729e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 88829e83d4bSgd78059 drv_usecwait(1); 88929e83d4bSgd78059 } 89029e83d4bSgd78059 89129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 89229e83d4bSgd78059 89329e83d4bSgd78059 for (i = 0; i < 16; i++) { 89429e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK); 89529e83d4bSgd78059 drv_usecwait(1); 89629e83d4bSgd78059 word <<= 1; 89729e83d4bSgd78059 if (GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT) { 89829e83d4bSgd78059 word |= 1; 89929e83d4bSgd78059 } 90029e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 90129e83d4bSgd78059 drv_usecwait(1); 90229e83d4bSgd78059 } 90329e83d4bSgd78059 90429e83d4bSgd78059 /* turn off accesses to the EEPROM */ 90529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 90629e83d4bSgd78059 90729e83d4bSgd78059 /* 90829e83d4bSgd78059 * Fix up the endianness thing. Note that the values 90929e83d4bSgd78059 * are stored in little endian format on the SROM. 91029e83d4bSgd78059 */ 91129e83d4bSgd78059 DBG(DSROM, "got value %d from SROM (before swap)", word); 91229e83d4bSgd78059 ptr = (uchar_t *)&word; 91329e83d4bSgd78059 retval = (ptr[1] << 8) | ptr[0]; 91429e83d4bSgd78059 return (retval); 91529e83d4bSgd78059 } 91629e83d4bSgd78059 91729e83d4bSgd78059 void 91829e83d4bSgd78059 mxfe_readsrom(mxfe_t *mxfep, unsigned romaddr, unsigned len, void *dest) 91929e83d4bSgd78059 { 92029e83d4bSgd78059 char *ptr = dest; 92129e83d4bSgd78059 int i; 92229e83d4bSgd78059 uint16_t word; 92329e83d4bSgd78059 92429e83d4bSgd78059 for (i = 0; i < len; i++) { 92529e83d4bSgd78059 word = mxfe_readsromword(mxfep, romaddr + i); 92629e83d4bSgd78059 bcopy(&word, ptr, 2); 92729e83d4bSgd78059 ptr += 2; 92829e83d4bSgd78059 DBG(DSROM, "word at %d is 0x%x", romaddr + i, word); 92929e83d4bSgd78059 } 93029e83d4bSgd78059 } 93129e83d4bSgd78059 93229e83d4bSgd78059 void 93329e83d4bSgd78059 mxfe_getfactaddr(mxfe_t *mxfep, uchar_t *eaddr) 93429e83d4bSgd78059 { 93529e83d4bSgd78059 uint16_t word; 93629e83d4bSgd78059 uchar_t *ptr; 93729e83d4bSgd78059 93829e83d4bSgd78059 /* first read to get the location of mac address in srom */ 93929e83d4bSgd78059 word = mxfe_readsromword(mxfep, SROM_ENADDR / 2); 94029e83d4bSgd78059 ptr = (uchar_t *)&word; 94129e83d4bSgd78059 word = (ptr[1] << 8) | ptr[0]; 94229e83d4bSgd78059 94329e83d4bSgd78059 /* then read the actual mac address */ 94429e83d4bSgd78059 mxfe_readsrom(mxfep, word / 2, ETHERADDRL / 2, eaddr); 94529e83d4bSgd78059 DBG(DMACID, 94629e83d4bSgd78059 "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x", 94729e83d4bSgd78059 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 94829e83d4bSgd78059 } 94929e83d4bSgd78059 95029e83d4bSgd78059 void 95129e83d4bSgd78059 mxfe_startphy(mxfe_t *mxfep) 95229e83d4bSgd78059 { 95329e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) { 95429e83d4bSgd78059 case MXFE_98713A: 95529e83d4bSgd78059 mxfe_startphymii(mxfep); 95629e83d4bSgd78059 break; 95729e83d4bSgd78059 default: 95829e83d4bSgd78059 mxfe_startphynway(mxfep); 95929e83d4bSgd78059 break; 96029e83d4bSgd78059 } 96129e83d4bSgd78059 } 96229e83d4bSgd78059 96329e83d4bSgd78059 void 96429e83d4bSgd78059 mxfe_stopphy(mxfe_t *mxfep) 96529e83d4bSgd78059 { 96629e83d4bSgd78059 uint32_t nar; 96729e83d4bSgd78059 int i; 96829e83d4bSgd78059 96929e83d4bSgd78059 /* stop the phy timer */ 97029e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, 0); 97129e83d4bSgd78059 97229e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) { 97329e83d4bSgd78059 case MXFE_98713A: 97429e83d4bSgd78059 for (i = 0; i < 32; i++) { 97529e83d4bSgd78059 mxfe_miiwrite(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL, 97629e83d4bSgd78059 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE); 97729e83d4bSgd78059 } 97829e83d4bSgd78059 break; 97929e83d4bSgd78059 default: 98029e83d4bSgd78059 DBG(DPHY, "resetting SIA"); 98129e83d4bSgd78059 PUTCSR(mxfep, CSR_SIA, SIA_RESET); 98229e83d4bSgd78059 drv_usecwait(500); 98329e83d4bSgd78059 CLRBIT(mxfep, CSR_TCTL, TCTL_PWR | TCTL_ANE); 98429e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 98529e83d4bSgd78059 nar &= ~(NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX); 98629e83d4bSgd78059 nar |= NAR_SPEED; 98729e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 98829e83d4bSgd78059 break; 98929e83d4bSgd78059 } 99029e83d4bSgd78059 99129e83d4bSgd78059 /* 99229e83d4bSgd78059 * mark the link state unknown 99329e83d4bSgd78059 */ 99429e83d4bSgd78059 if (!mxfep->mxfe_resetting) { 99529e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UNKNOWN; 99629e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 99729e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 99829e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 99929e83d4bSgd78059 mxfe_reportlink(mxfep); 100029e83d4bSgd78059 } 100129e83d4bSgd78059 } 100229e83d4bSgd78059 100329e83d4bSgd78059 /* 100429e83d4bSgd78059 * NWay support. 100529e83d4bSgd78059 */ 100629e83d4bSgd78059 void 100729e83d4bSgd78059 mxfe_startnway(mxfe_t *mxfep) 100829e83d4bSgd78059 { 100929e83d4bSgd78059 unsigned nar; 101029e83d4bSgd78059 unsigned tctl; 101129e83d4bSgd78059 unsigned restart; 101229e83d4bSgd78059 101329e83d4bSgd78059 /* this should not happen in a healthy system */ 101496fb08b9Sgd78059 if (mxfep->mxfe_nwaystate != MXFE_NOLINK) { 101529e83d4bSgd78059 DBG(DWARN, "link start called out of state (%x)", 101696fb08b9Sgd78059 mxfep->mxfe_nwaystate); 101729e83d4bSgd78059 return; 101829e83d4bSgd78059 } 101929e83d4bSgd78059 102029e83d4bSgd78059 if (mxfep->mxfe_adv_aneg == 0) { 102129e83d4bSgd78059 /* not done for forced mode */ 102229e83d4bSgd78059 return; 102329e83d4bSgd78059 } 102429e83d4bSgd78059 102529e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 102629e83d4bSgd78059 restart = nar & (NAR_TX_ENABLE | NAR_RX_ENABLE); 102729e83d4bSgd78059 nar &= ~restart; 102829e83d4bSgd78059 102929e83d4bSgd78059 if (restart != 0) 103029e83d4bSgd78059 mxfe_stopmac(mxfep); 103129e83d4bSgd78059 103229e83d4bSgd78059 nar |= NAR_SCR | NAR_PCS | NAR_HBD; 103329e83d4bSgd78059 nar &= ~(NAR_FDX); 103429e83d4bSgd78059 103529e83d4bSgd78059 tctl = GETCSR(mxfep, CSR_TCTL); 103629e83d4bSgd78059 tctl &= ~(TCTL_100FDX | TCTL_100HDX | TCTL_HDX); 103729e83d4bSgd78059 103829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) { 103929e83d4bSgd78059 tctl |= TCTL_100FDX; 104029e83d4bSgd78059 } 104129e83d4bSgd78059 if (mxfep->mxfe_adv_100hdx) { 104229e83d4bSgd78059 tctl |= TCTL_100HDX; 104329e83d4bSgd78059 } 104429e83d4bSgd78059 if (mxfep->mxfe_adv_10fdx) { 104529e83d4bSgd78059 nar |= NAR_FDX; 104629e83d4bSgd78059 } 104729e83d4bSgd78059 if (mxfep->mxfe_adv_10hdx) { 104829e83d4bSgd78059 tctl |= TCTL_HDX; 104929e83d4bSgd78059 } 105029e83d4bSgd78059 tctl |= TCTL_PWR | TCTL_ANE | TCTL_LTE | TCTL_RSQ; 105129e83d4bSgd78059 105229e83d4bSgd78059 /* possibly we should add in support for PAUSE frames */ 105329e83d4bSgd78059 DBG(DPHY, "writing nar = 0x%x", nar); 105429e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 105529e83d4bSgd78059 105629e83d4bSgd78059 DBG(DPHY, "writing tctl = 0x%x", tctl); 105729e83d4bSgd78059 PUTCSR(mxfep, CSR_TCTL, tctl); 105829e83d4bSgd78059 105929e83d4bSgd78059 /* restart autonegotation */ 106029e83d4bSgd78059 DBG(DPHY, "writing tstat = 0x%x", TSTAT_ANS_START); 106129e83d4bSgd78059 PUTCSR(mxfep, CSR_TSTAT, TSTAT_ANS_START); 106229e83d4bSgd78059 106329e83d4bSgd78059 /* restart tx/rx processes... */ 106429e83d4bSgd78059 if (restart != 0) 106529e83d4bSgd78059 mxfe_startmac(mxfep); 106629e83d4bSgd78059 106729e83d4bSgd78059 /* Macronix initializations from Bolo Tsai */ 106829e83d4bSgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000); 106929e83d4bSgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000); 107029e83d4bSgd78059 107196fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NWAYCHECK; 107229e83d4bSgd78059 } 107329e83d4bSgd78059 107429e83d4bSgd78059 void 107529e83d4bSgd78059 mxfe_checklinknway(mxfe_t *mxfep) 107629e83d4bSgd78059 { 107796fb08b9Sgd78059 unsigned tstat; 107896fb08b9Sgd78059 uint16_t lpar; 107929e83d4bSgd78059 108096fb08b9Sgd78059 DBG(DPHY, "NWay check, state %x", mxfep->mxfe_nwaystate); 108129e83d4bSgd78059 tstat = GETCSR(mxfep, CSR_TSTAT); 108229e83d4bSgd78059 lpar = TSTAT_LPAR(tstat); 108329e83d4bSgd78059 108429e83d4bSgd78059 mxfep->mxfe_anlpar = lpar; 108529e83d4bSgd78059 if (tstat & TSTAT_LPN) { 108629e83d4bSgd78059 mxfep->mxfe_aner |= MII_AN_EXP_LPCANAN; 108729e83d4bSgd78059 } else { 108829e83d4bSgd78059 mxfep->mxfe_aner &= ~(MII_AN_EXP_LPCANAN); 108929e83d4bSgd78059 } 109029e83d4bSgd78059 109129e83d4bSgd78059 DBG(DPHY, "tstat(CSR12) = 0x%x", tstat); 109229e83d4bSgd78059 DBG(DPHY, "ANEG state = 0x%x", (tstat & TSTAT_ANS) >> 12); 109329e83d4bSgd78059 109429e83d4bSgd78059 if ((tstat & TSTAT_ANS) != TSTAT_ANS_OK) { 109529e83d4bSgd78059 /* autoneg did not complete */ 109629e83d4bSgd78059 mxfep->mxfe_bmsr &= ~MII_STATUS_ANDONE; 109729e83d4bSgd78059 } else { 109829e83d4bSgd78059 mxfep->mxfe_bmsr |= ~MII_STATUS_ANDONE; 109929e83d4bSgd78059 } 110029e83d4bSgd78059 110129e83d4bSgd78059 if ((tstat & TSTAT_100F) && (tstat & TSTAT_10F)) { 110229e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 110329e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 110429e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 110596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK; 110629e83d4bSgd78059 mxfe_reportlink(mxfep); 110729e83d4bSgd78059 mxfe_startnway(mxfep); 110829e83d4bSgd78059 return; 110929e83d4bSgd78059 } 111029e83d4bSgd78059 111129e83d4bSgd78059 /* 111229e83d4bSgd78059 * if the link is newly up, then we might need to set various 111329e83d4bSgd78059 * mode bits, or negotiate for parameters, etc. 111429e83d4bSgd78059 */ 111529e83d4bSgd78059 if (mxfep->mxfe_adv_aneg) { 111629e83d4bSgd78059 111729e83d4bSgd78059 uint16_t anlpar; 111829e83d4bSgd78059 111929e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 112029e83d4bSgd78059 anlpar = mxfep->mxfe_anlpar; 112129e83d4bSgd78059 112229e83d4bSgd78059 if (tstat & TSTAT_LPN) { 112329e83d4bSgd78059 /* partner has NWay */ 112429e83d4bSgd78059 112529e83d4bSgd78059 if ((anlpar & MII_ABILITY_100BASE_TX_FD) && 112629e83d4bSgd78059 mxfep->mxfe_adv_100fdx) { 112729e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 112829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 112929e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_100BASE_TX) && 113029e83d4bSgd78059 mxfep->mxfe_adv_100hdx) { 113129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 113229e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 113329e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T_FD) && 113429e83d4bSgd78059 mxfep->mxfe_adv_10fdx) { 113529e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 113629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 113729e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T) && 113829e83d4bSgd78059 mxfep->mxfe_adv_10hdx) { 113929e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 114029e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 114129e83d4bSgd78059 } else { 114229e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 114329e83d4bSgd78059 } 114429e83d4bSgd78059 } else { 114529e83d4bSgd78059 /* link partner does not have NWay */ 114629e83d4bSgd78059 /* just assume half duplex, since we can't detect */ 114729e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 114829e83d4bSgd78059 if (!(tstat & TSTAT_100F)) { 114929e83d4bSgd78059 DBG(DPHY, "Partner doesn't have NWAY"); 115029e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 115129e83d4bSgd78059 } else { 115229e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 115329e83d4bSgd78059 } 115429e83d4bSgd78059 } 115529e83d4bSgd78059 } else { 115629e83d4bSgd78059 /* forced modes */ 115729e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 115829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) { 115929e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 116029e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 116129e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) { 116229e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 116329e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 116429e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) { 116529e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 116629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 116729e83d4bSgd78059 } else if (mxfep->mxfe_adv_10hdx) { 116829e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 116929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 117029e83d4bSgd78059 } else { 117129e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 117229e83d4bSgd78059 } 117329e83d4bSgd78059 } 117429e83d4bSgd78059 mxfe_reportlink(mxfep); 117596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_GOODLINK; 117629e83d4bSgd78059 } 117729e83d4bSgd78059 117829e83d4bSgd78059 void 117929e83d4bSgd78059 mxfe_startphynway(mxfe_t *mxfep) 118029e83d4bSgd78059 { 118129e83d4bSgd78059 /* take NWay and PHY out of reset */ 118229e83d4bSgd78059 PUTCSR(mxfep, CSR_SIA, SIA_NRESET); 118329e83d4bSgd78059 drv_usecwait(500); 118429e83d4bSgd78059 118596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK; 118629e83d4bSgd78059 mxfep->mxfe_bmsr = MII_STATUS_CANAUTONEG | 118729e83d4bSgd78059 MII_STATUS_100_BASEX_FD | MII_STATUS_100_BASEX | 118829e83d4bSgd78059 MII_STATUS_10_FD | MII_STATUS_10; 118996fb08b9Sgd78059 mxfep->mxfe_cap_aneg = 119096fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx = 119196fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1; 119229e83d4bSgd78059 119329e83d4bSgd78059 /* lie about the transceiver... its not really 802.3u compliant */ 119429e83d4bSgd78059 mxfep->mxfe_phyaddr = 0; 119529e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100X; 119629e83d4bSgd78059 mxfep->mxfe_phyid = 0; 119729e83d4bSgd78059 119829e83d4bSgd78059 /* 100-T4 not supported with NWay */ 119929e83d4bSgd78059 mxfep->mxfe_adv_100T4 = 0; 120096fb08b9Sgd78059 mxfep->mxfe_cap_100T4 = 0; 120129e83d4bSgd78059 120229e83d4bSgd78059 /* make sure at least one valid mode is selected */ 120329e83d4bSgd78059 if ((!mxfep->mxfe_adv_100fdx) && 120429e83d4bSgd78059 (!mxfep->mxfe_adv_100hdx) && 120529e83d4bSgd78059 (!mxfep->mxfe_adv_10fdx) && 120629e83d4bSgd78059 (!mxfep->mxfe_adv_10hdx)) { 120729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected."); 120829e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY."); 120929e83d4bSgd78059 mxfe_stopphy(mxfep); 121029e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 121129e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 121229e83d4bSgd78059 mxfe_reportlink(mxfep); 121329e83d4bSgd78059 return; 121429e83d4bSgd78059 } 121529e83d4bSgd78059 121629e83d4bSgd78059 if (mxfep->mxfe_adv_aneg == 0) { 121729e83d4bSgd78059 /* forced mode */ 121829e83d4bSgd78059 unsigned nar; 121929e83d4bSgd78059 unsigned tctl; 122029e83d4bSgd78059 122129e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 122229e83d4bSgd78059 tctl = GETCSR(mxfep, CSR_TCTL); 122329e83d4bSgd78059 122429e83d4bSgd78059 ASSERT((nar & (NAR_TX_ENABLE | NAR_RX_ENABLE)) == 0); 122529e83d4bSgd78059 122629e83d4bSgd78059 nar &= ~(NAR_FDX | NAR_PORTSEL | NAR_SCR | NAR_SPEED); 122729e83d4bSgd78059 tctl &= ~TCTL_ANE; 122829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) { 122929e83d4bSgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX; 123029e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) { 123129e83d4bSgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR; 123229e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) { 123329e83d4bSgd78059 nar |= NAR_FDX | NAR_SPEED; 123429e83d4bSgd78059 } else { /* mxfep->mxfe_adv_10hdx */ 123529e83d4bSgd78059 nar |= NAR_SPEED; 123629e83d4bSgd78059 } 123729e83d4bSgd78059 123829e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 123929e83d4bSgd78059 PUTCSR(mxfep, CSR_TCTL, tctl); 124029e83d4bSgd78059 124129e83d4bSgd78059 /* Macronix initializations from Bolo Tsai */ 124229e83d4bSgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000); 124329e83d4bSgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000); 124429e83d4bSgd78059 } else { 124529e83d4bSgd78059 mxfe_startnway(mxfep); 124629e83d4bSgd78059 } 124729e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP | 124829e83d4bSgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC)); 124929e83d4bSgd78059 } 125029e83d4bSgd78059 125129e83d4bSgd78059 /* 125229e83d4bSgd78059 * MII management. 125329e83d4bSgd78059 */ 125429e83d4bSgd78059 void 125529e83d4bSgd78059 mxfe_startphymii(mxfe_t *mxfep) 125629e83d4bSgd78059 { 125729e83d4bSgd78059 unsigned phyaddr; 125829e83d4bSgd78059 unsigned bmcr; 125929e83d4bSgd78059 unsigned bmsr; 126029e83d4bSgd78059 unsigned anar; 126129e83d4bSgd78059 unsigned phyidr1; 126229e83d4bSgd78059 unsigned phyidr2; 126329e83d4bSgd78059 int retries; 126429e83d4bSgd78059 int cnt; 126529e83d4bSgd78059 126629e83d4bSgd78059 mxfep->mxfe_phyaddr = -1; 126729e83d4bSgd78059 126829e83d4bSgd78059 /* search for first PHY we can find */ 126929e83d4bSgd78059 for (phyaddr = 0; phyaddr < 32; phyaddr++) { 127029e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS); 127129e83d4bSgd78059 if ((bmsr != 0) && (bmsr != 0xffff)) { 127229e83d4bSgd78059 mxfep->mxfe_phyaddr = phyaddr; 127329e83d4bSgd78059 break; 127429e83d4bSgd78059 } 127529e83d4bSgd78059 } 127629e83d4bSgd78059 127729e83d4bSgd78059 phyidr1 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDH); 127829e83d4bSgd78059 phyidr2 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDL); 127929e83d4bSgd78059 mxfep->mxfe_phyid = (phyidr1 << 16) | (phyidr2); 128029e83d4bSgd78059 128129e83d4bSgd78059 /* 128229e83d4bSgd78059 * Generally, all Macronix based devices use an internal 128329e83d4bSgd78059 * 100BASE-TX internal transceiver. If we ever run into a 128429e83d4bSgd78059 * variation on this, then the following logic will need to be 128529e83d4bSgd78059 * enhanced. 128629e83d4bSgd78059 * 128729e83d4bSgd78059 * One could question the value of the XCVR_INUSE field in the 128829e83d4bSgd78059 * MII statistics. 128929e83d4bSgd78059 */ 129029e83d4bSgd78059 if (bmsr & MII_STATUS_100_BASE_T4) { 129129e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100T4; 129229e83d4bSgd78059 } else { 129329e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100X; 129429e83d4bSgd78059 } 129529e83d4bSgd78059 129696fb08b9Sgd78059 /* assume we support everything to start */ 129796fb08b9Sgd78059 mxfep->mxfe_cap_aneg = mxfep->mxfe_cap_100T4 = 129896fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx = 129996fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1; 130096fb08b9Sgd78059 130129e83d4bSgd78059 DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2); 130229e83d4bSgd78059 DBG(DPHY, "bmsr = %x", mxfe_miiread(mxfep, 130329e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_STATUS)); 130429e83d4bSgd78059 DBG(DPHY, "anar = %x", mxfe_miiread(mxfep, 130529e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_ADVERT)); 130629e83d4bSgd78059 DBG(DPHY, "anlpar = %x", mxfe_miiread(mxfep, 130729e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_LPABLE)); 130829e83d4bSgd78059 DBG(DPHY, "aner = %x", mxfe_miiread(mxfep, 130929e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_EXPANSION)); 131029e83d4bSgd78059 131129e83d4bSgd78059 DBG(DPHY, "resetting phy"); 131229e83d4bSgd78059 131329e83d4bSgd78059 /* we reset the phy block */ 131429e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, MII_CONTROL_RESET); 131529e83d4bSgd78059 /* 131629e83d4bSgd78059 * wait for it to complete -- 500usec is still to short to 131729e83d4bSgd78059 * bother getting the system clock involved. 131829e83d4bSgd78059 */ 131929e83d4bSgd78059 drv_usecwait(500); 132029e83d4bSgd78059 for (retries = 0; retries < 10; retries++) { 132129e83d4bSgd78059 if (mxfe_miiread(mxfep, phyaddr, MII_CONTROL) & 132229e83d4bSgd78059 MII_CONTROL_RESET) { 132329e83d4bSgd78059 drv_usecwait(500); 132429e83d4bSgd78059 continue; 132529e83d4bSgd78059 } 132629e83d4bSgd78059 break; 132729e83d4bSgd78059 } 132829e83d4bSgd78059 if (retries == 100) { 132929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "timeout waiting on phy to reset"); 133029e83d4bSgd78059 return; 133129e83d4bSgd78059 } 133229e83d4bSgd78059 133329e83d4bSgd78059 DBG(DPHY, "phy reset complete"); 133429e83d4bSgd78059 133529e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS); 133629e83d4bSgd78059 bmcr = mxfe_miiread(mxfep, phyaddr, MII_CONTROL); 133729e83d4bSgd78059 anar = mxfe_miiread(mxfep, phyaddr, MII_AN_ADVERT); 133829e83d4bSgd78059 133929e83d4bSgd78059 anar &= ~(MII_ABILITY_100BASE_T4 | 134029e83d4bSgd78059 MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX | 134129e83d4bSgd78059 MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T); 134229e83d4bSgd78059 134329e83d4bSgd78059 /* disable modes not supported in hardware */ 134429e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASE_T4)) { 134529e83d4bSgd78059 mxfep->mxfe_adv_100T4 = 0; 134696fb08b9Sgd78059 mxfep->mxfe_cap_100T4 = 0; 134729e83d4bSgd78059 } 134829e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASEX_FD)) { 134929e83d4bSgd78059 mxfep->mxfe_adv_100fdx = 0; 135096fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = 0; 135129e83d4bSgd78059 } 135229e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASEX)) { 135329e83d4bSgd78059 mxfep->mxfe_adv_100hdx = 0; 135496fb08b9Sgd78059 mxfep->mxfe_cap_100hdx = 0; 135529e83d4bSgd78059 } 135629e83d4bSgd78059 if (!(bmsr & MII_STATUS_10_FD)) { 135729e83d4bSgd78059 mxfep->mxfe_adv_10fdx = 0; 135896fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = 0; 135929e83d4bSgd78059 } 136029e83d4bSgd78059 if (!(bmsr & MII_STATUS_10)) { 136129e83d4bSgd78059 mxfep->mxfe_adv_10hdx = 0; 136296fb08b9Sgd78059 mxfep->mxfe_cap_10hdx = 0; 136329e83d4bSgd78059 } 136429e83d4bSgd78059 if (!(bmsr & MII_STATUS_CANAUTONEG)) { 136529e83d4bSgd78059 mxfep->mxfe_adv_aneg = 0; 136696fb08b9Sgd78059 mxfep->mxfe_cap_aneg = 0; 136729e83d4bSgd78059 } 136829e83d4bSgd78059 136929e83d4bSgd78059 cnt = 0; 137029e83d4bSgd78059 if (mxfep->mxfe_adv_100T4) { 137129e83d4bSgd78059 anar |= MII_ABILITY_100BASE_T4; 137229e83d4bSgd78059 cnt++; 137329e83d4bSgd78059 } 137429e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) { 137529e83d4bSgd78059 anar |= MII_ABILITY_100BASE_TX_FD; 137629e83d4bSgd78059 cnt++; 137729e83d4bSgd78059 } 137829e83d4bSgd78059 if (mxfep->mxfe_adv_100hdx) { 137929e83d4bSgd78059 anar |= MII_ABILITY_100BASE_TX; 138029e83d4bSgd78059 cnt++; 138129e83d4bSgd78059 } 138229e83d4bSgd78059 if (mxfep->mxfe_adv_10fdx) { 138329e83d4bSgd78059 anar |= MII_ABILITY_10BASE_T_FD; 138429e83d4bSgd78059 cnt++; 138529e83d4bSgd78059 } 138629e83d4bSgd78059 if (mxfep->mxfe_adv_10hdx) { 138729e83d4bSgd78059 anar |= MII_ABILITY_10BASE_T; 138829e83d4bSgd78059 cnt++; 138929e83d4bSgd78059 } 139029e83d4bSgd78059 139129e83d4bSgd78059 /* 139229e83d4bSgd78059 * Make certain at least one valid link mode is selected. 139329e83d4bSgd78059 */ 139429e83d4bSgd78059 if (!cnt) { 139529e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected."); 139629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY."); 139729e83d4bSgd78059 mxfe_stopphy(mxfep); 139829e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 139929e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 140029e83d4bSgd78059 mxfe_reportlink(mxfep); 140129e83d4bSgd78059 return; 140229e83d4bSgd78059 } 140329e83d4bSgd78059 140429e83d4bSgd78059 if ((mxfep->mxfe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) { 140529e83d4bSgd78059 DBG(DPHY, "using autoneg mode"); 140629e83d4bSgd78059 bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN); 140729e83d4bSgd78059 } else { 140829e83d4bSgd78059 DBG(DPHY, "using forced mode"); 140929e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) { 141029e83d4bSgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 141129e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) { 141229e83d4bSgd78059 bmcr = MII_CONTROL_100MB; 141329e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) { 141429e83d4bSgd78059 bmcr = MII_CONTROL_FDUPLEX; 141529e83d4bSgd78059 } else { 141629e83d4bSgd78059 /* 10HDX */ 141729e83d4bSgd78059 bmcr = 0; 141829e83d4bSgd78059 } 141929e83d4bSgd78059 } 142029e83d4bSgd78059 142129e83d4bSgd78059 DBG(DPHY, "programming anar to 0x%x", anar); 142229e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_AN_ADVERT, anar); 142329e83d4bSgd78059 DBG(DPHY, "programming bmcr to 0x%x", bmcr); 142429e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, bmcr); 142529e83d4bSgd78059 142629e83d4bSgd78059 /* 142729e83d4bSgd78059 * schedule a query of the link status 142829e83d4bSgd78059 */ 142929e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP | 143029e83d4bSgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC)); 143129e83d4bSgd78059 } 143229e83d4bSgd78059 143329e83d4bSgd78059 void 143429e83d4bSgd78059 mxfe_reportlink(mxfe_t *mxfep) 143529e83d4bSgd78059 { 143629e83d4bSgd78059 int changed = 0; 143729e83d4bSgd78059 143829e83d4bSgd78059 if (mxfep->mxfe_ifspeed != mxfep->mxfe_lastifspeed) { 143929e83d4bSgd78059 mxfep->mxfe_lastifspeed = mxfep->mxfe_ifspeed; 144029e83d4bSgd78059 changed++; 144129e83d4bSgd78059 } 144229e83d4bSgd78059 if (mxfep->mxfe_duplex != mxfep->mxfe_lastduplex) { 144329e83d4bSgd78059 mxfep->mxfe_lastduplex = mxfep->mxfe_duplex; 144429e83d4bSgd78059 changed++; 144529e83d4bSgd78059 } 144629e83d4bSgd78059 if (mxfep->mxfe_linkup != mxfep->mxfe_lastlinkup) { 144729e83d4bSgd78059 mxfep->mxfe_lastlinkup = mxfep->mxfe_linkup; 144829e83d4bSgd78059 changed++; 144929e83d4bSgd78059 } 145029e83d4bSgd78059 if (changed) 145129e83d4bSgd78059 mac_link_update(mxfep->mxfe_mh, mxfep->mxfe_linkup); 145229e83d4bSgd78059 } 145329e83d4bSgd78059 145429e83d4bSgd78059 void 145529e83d4bSgd78059 mxfe_checklink(mxfe_t *mxfep) 145629e83d4bSgd78059 { 145729e83d4bSgd78059 if ((mxfep->mxfe_flags & MXFE_RUNNING) == 0) 145829e83d4bSgd78059 return; 145929e83d4bSgd78059 146029e83d4bSgd78059 if ((mxfep->mxfe_txstall_time != 0) && 146129e83d4bSgd78059 (gethrtime() > mxfep->mxfe_txstall_time) && 146229e83d4bSgd78059 (mxfep->mxfe_txavail != MXFE_TXRING)) { 146329e83d4bSgd78059 mxfep->mxfe_txstall_time = 0; 146429e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "TX stall detected!"); 146529e83d4bSgd78059 mxfe_resetall(mxfep); 146629e83d4bSgd78059 return; 146729e83d4bSgd78059 } 146829e83d4bSgd78059 146929e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) { 147029e83d4bSgd78059 case MXFE_98713A: 147129e83d4bSgd78059 mxfe_checklinkmii(mxfep); 147229e83d4bSgd78059 break; 147329e83d4bSgd78059 default: 147429e83d4bSgd78059 mxfe_checklinknway(mxfep); 147529e83d4bSgd78059 } 147629e83d4bSgd78059 } 147729e83d4bSgd78059 147829e83d4bSgd78059 void 147929e83d4bSgd78059 mxfe_checklinkmii(mxfe_t *mxfep) 148029e83d4bSgd78059 { 148129e83d4bSgd78059 /* read MII state registers */ 148229e83d4bSgd78059 uint16_t bmsr; 148329e83d4bSgd78059 uint16_t bmcr; 148429e83d4bSgd78059 uint16_t anar; 148529e83d4bSgd78059 uint16_t anlpar; 148629e83d4bSgd78059 uint16_t aner; 148729e83d4bSgd78059 148829e83d4bSgd78059 /* read this twice, to clear latched link state */ 148929e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS); 149029e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS); 149129e83d4bSgd78059 bmcr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL); 149229e83d4bSgd78059 anar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_ADVERT); 149329e83d4bSgd78059 anlpar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_LPABLE); 149429e83d4bSgd78059 aner = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_EXPANSION); 149529e83d4bSgd78059 149629e83d4bSgd78059 mxfep->mxfe_bmsr = bmsr; 149729e83d4bSgd78059 mxfep->mxfe_anlpar = anlpar; 149829e83d4bSgd78059 mxfep->mxfe_aner = aner; 149929e83d4bSgd78059 150029e83d4bSgd78059 if (bmsr & MII_STATUS_REMFAULT) { 150129e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Remote fault detected."); 150229e83d4bSgd78059 } 150329e83d4bSgd78059 if (bmsr & MII_STATUS_JABBERING) { 150429e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Jabber condition detected."); 150529e83d4bSgd78059 } 150629e83d4bSgd78059 if ((bmsr & MII_STATUS_LINKUP) == 0) { 150729e83d4bSgd78059 /* no link */ 150829e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 150929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 151029e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 151129e83d4bSgd78059 mxfe_reportlink(mxfep); 151229e83d4bSgd78059 return; 151329e83d4bSgd78059 } 151429e83d4bSgd78059 151529e83d4bSgd78059 DBG(DCHATTY, "link up!"); 151629e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 151729e83d4bSgd78059 151829e83d4bSgd78059 if (!(bmcr & MII_CONTROL_ANE)) { 151929e83d4bSgd78059 /* forced mode */ 152029e83d4bSgd78059 if (bmcr & MII_CONTROL_100MB) { 152129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 152229e83d4bSgd78059 } else { 152329e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 152429e83d4bSgd78059 } 152529e83d4bSgd78059 if (bmcr & MII_CONTROL_FDUPLEX) { 152629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 152729e83d4bSgd78059 } else { 152829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 152929e83d4bSgd78059 } 153029e83d4bSgd78059 } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) || 153129e83d4bSgd78059 (!(bmsr & MII_STATUS_ANDONE))) { 153229e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 153329e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 153429e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) { 153529e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 153629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 153729e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_T4) { 153829e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 153929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 154029e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX) { 154129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000; 154229e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 154329e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) { 154429e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 154529e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 154629e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T) { 154729e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000; 154829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 154929e83d4bSgd78059 } else { 155029e83d4bSgd78059 mxfep->mxfe_ifspeed = 0; 155129e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 155229e83d4bSgd78059 } 155329e83d4bSgd78059 155429e83d4bSgd78059 mxfe_reportlink(mxfep); 155529e83d4bSgd78059 } 155629e83d4bSgd78059 155729e83d4bSgd78059 void 155829e83d4bSgd78059 mxfe_miitristate(mxfe_t *mxfep) 155929e83d4bSgd78059 { 156029e83d4bSgd78059 unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL; 156129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val); 156229e83d4bSgd78059 drv_usecwait(1); 156329e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 156429e83d4bSgd78059 drv_usecwait(1); 156529e83d4bSgd78059 } 156629e83d4bSgd78059 156729e83d4bSgd78059 void 156896fb08b9Sgd78059 mxfe_miiwritebit(mxfe_t *mxfep, uint8_t bit) 156929e83d4bSgd78059 { 157029e83d4bSgd78059 unsigned val = bit ? SPR_MII_DOUT : 0; 157129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val); 157229e83d4bSgd78059 drv_usecwait(1); 157329e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 157429e83d4bSgd78059 drv_usecwait(1); 157529e83d4bSgd78059 } 157629e83d4bSgd78059 157796fb08b9Sgd78059 uint8_t 157829e83d4bSgd78059 mxfe_miireadbit(mxfe_t *mxfep) 157929e83d4bSgd78059 { 158029e83d4bSgd78059 unsigned val = SPR_MII_CTRL | SPR_SROM_READ; 158196fb08b9Sgd78059 uint8_t bit; 158229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val); 158329e83d4bSgd78059 drv_usecwait(1); 158429e83d4bSgd78059 bit = (GETCSR(mxfep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0; 158529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 158629e83d4bSgd78059 drv_usecwait(1); 158729e83d4bSgd78059 return (bit); 158829e83d4bSgd78059 } 158929e83d4bSgd78059 159096fb08b9Sgd78059 uint16_t 159129e83d4bSgd78059 mxfe_miiread(mxfe_t *mxfep, int phy, int reg) 159229e83d4bSgd78059 { 159329e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) { 159429e83d4bSgd78059 case MXFE_98713A: 159529e83d4bSgd78059 return (mxfe_miiread98713(mxfep, phy, reg)); 159629e83d4bSgd78059 default: 159729e83d4bSgd78059 return (0xffff); 159829e83d4bSgd78059 } 159929e83d4bSgd78059 } 160029e83d4bSgd78059 160196fb08b9Sgd78059 uint16_t 160229e83d4bSgd78059 mxfe_miireadgeneral(mxfe_t *mxfep, int phy, int reg) 160329e83d4bSgd78059 { 160496fb08b9Sgd78059 uint16_t value = 0; 160529e83d4bSgd78059 int i; 160629e83d4bSgd78059 160729e83d4bSgd78059 /* send the 32 bit preamble */ 160829e83d4bSgd78059 for (i = 0; i < 32; i++) { 160929e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 161029e83d4bSgd78059 } 161129e83d4bSgd78059 161229e83d4bSgd78059 /* send the start code - 01b */ 161329e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 161429e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 161529e83d4bSgd78059 161629e83d4bSgd78059 /* send the opcode for read, - 10b */ 161729e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 161829e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 161929e83d4bSgd78059 162029e83d4bSgd78059 /* next we send the 5 bit phy address */ 162129e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) { 162229e83d4bSgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0); 162329e83d4bSgd78059 } 162429e83d4bSgd78059 162529e83d4bSgd78059 /* the 5 bit register address goes next */ 162629e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) { 162729e83d4bSgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0); 162829e83d4bSgd78059 } 162929e83d4bSgd78059 163029e83d4bSgd78059 /* turnaround - tristate followed by logic 0 */ 163129e83d4bSgd78059 mxfe_miitristate(mxfep); 163229e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 163329e83d4bSgd78059 163429e83d4bSgd78059 /* read the 16 bit register value */ 163529e83d4bSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 163629e83d4bSgd78059 value <<= 1; 163729e83d4bSgd78059 value |= mxfe_miireadbit(mxfep); 163829e83d4bSgd78059 } 163929e83d4bSgd78059 mxfe_miitristate(mxfep); 164029e83d4bSgd78059 return (value); 164129e83d4bSgd78059 } 164229e83d4bSgd78059 164396fb08b9Sgd78059 uint16_t 164429e83d4bSgd78059 mxfe_miiread98713(mxfe_t *mxfep, int phy, int reg) 164529e83d4bSgd78059 { 164629e83d4bSgd78059 unsigned nar; 164796fb08b9Sgd78059 uint16_t retval; 164829e83d4bSgd78059 /* 164929e83d4bSgd78059 * like an ordinary MII, but we have to turn off portsel while 165029e83d4bSgd78059 * we read it. 165129e83d4bSgd78059 */ 165229e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 165329e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL); 165429e83d4bSgd78059 retval = mxfe_miireadgeneral(mxfep, phy, reg); 165529e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 165629e83d4bSgd78059 return (retval); 165729e83d4bSgd78059 } 165829e83d4bSgd78059 165929e83d4bSgd78059 void 166029e83d4bSgd78059 mxfe_miiwrite(mxfe_t *mxfep, int phy, int reg, uint16_t val) 166129e83d4bSgd78059 { 166229e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) { 166329e83d4bSgd78059 case MXFE_98713A: 166429e83d4bSgd78059 mxfe_miiwrite98713(mxfep, phy, reg, val); 166529e83d4bSgd78059 break; 166629e83d4bSgd78059 default: 166729e83d4bSgd78059 break; 166829e83d4bSgd78059 } 166929e83d4bSgd78059 } 167029e83d4bSgd78059 167129e83d4bSgd78059 void 167229e83d4bSgd78059 mxfe_miiwritegeneral(mxfe_t *mxfep, int phy, int reg, uint16_t val) 167329e83d4bSgd78059 { 167429e83d4bSgd78059 int i; 167529e83d4bSgd78059 167629e83d4bSgd78059 /* send the 32 bit preamble */ 167729e83d4bSgd78059 for (i = 0; i < 32; i++) { 167829e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 167929e83d4bSgd78059 } 168029e83d4bSgd78059 168129e83d4bSgd78059 /* send the start code - 01b */ 168229e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 168329e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 168429e83d4bSgd78059 168529e83d4bSgd78059 /* send the opcode for write, - 01b */ 168629e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 168729e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1); 168829e83d4bSgd78059 168929e83d4bSgd78059 /* next we send the 5 bit phy address */ 169029e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) { 169129e83d4bSgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0); 169229e83d4bSgd78059 } 169329e83d4bSgd78059 169429e83d4bSgd78059 /* the 5 bit register address goes next */ 169529e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) { 169629e83d4bSgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0); 169729e83d4bSgd78059 } 169829e83d4bSgd78059 169929e83d4bSgd78059 /* turnaround - tristate followed by logic 0 */ 170029e83d4bSgd78059 mxfe_miitristate(mxfep); 170129e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0); 170229e83d4bSgd78059 170329e83d4bSgd78059 /* now write out our data (16 bits) */ 170429e83d4bSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 170529e83d4bSgd78059 mxfe_miiwritebit(mxfep, (val & i) ? 1 : 0); 170629e83d4bSgd78059 } 170729e83d4bSgd78059 170829e83d4bSgd78059 /* idle mode */ 170929e83d4bSgd78059 mxfe_miitristate(mxfep); 171029e83d4bSgd78059 } 171129e83d4bSgd78059 171229e83d4bSgd78059 void 171329e83d4bSgd78059 mxfe_miiwrite98713(mxfe_t *mxfep, int phy, int reg, uint16_t val) 171429e83d4bSgd78059 { 171529e83d4bSgd78059 unsigned nar; 171629e83d4bSgd78059 /* 171729e83d4bSgd78059 * like an ordinary MII, but we have to turn off portsel while 171829e83d4bSgd78059 * we read it. 171929e83d4bSgd78059 */ 172029e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR); 172129e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL); 172229e83d4bSgd78059 mxfe_miiwritegeneral(mxfep, phy, reg, val); 172329e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar); 172429e83d4bSgd78059 } 172529e83d4bSgd78059 172629e83d4bSgd78059 int 172729e83d4bSgd78059 mxfe_m_start(void *arg) 172829e83d4bSgd78059 { 172929e83d4bSgd78059 mxfe_t *mxfep = arg; 173029e83d4bSgd78059 173129e83d4bSgd78059 /* grab exclusive access to the card */ 173229e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 173329e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 173429e83d4bSgd78059 173529e83d4bSgd78059 mxfe_startall(mxfep); 173629e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_RUNNING; 173729e83d4bSgd78059 173829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 173929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 174029e83d4bSgd78059 return (0); 174129e83d4bSgd78059 } 174229e83d4bSgd78059 174329e83d4bSgd78059 void 174429e83d4bSgd78059 mxfe_m_stop(void *arg) 174529e83d4bSgd78059 { 174629e83d4bSgd78059 mxfe_t *mxfep = arg; 174729e83d4bSgd78059 174829e83d4bSgd78059 /* exclusive access to the hardware! */ 174929e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 175029e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 175129e83d4bSgd78059 175229e83d4bSgd78059 mxfe_stopall(mxfep); 175329e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING; 175429e83d4bSgd78059 175529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 175629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 175729e83d4bSgd78059 } 175829e83d4bSgd78059 175929e83d4bSgd78059 void 176029e83d4bSgd78059 mxfe_startmac(mxfe_t *mxfep) 176129e83d4bSgd78059 { 176229e83d4bSgd78059 /* verify exclusive access to the card */ 176329e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 176429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 176529e83d4bSgd78059 176629e83d4bSgd78059 /* start the card */ 176729e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 176829e83d4bSgd78059 176929e83d4bSgd78059 if (mxfep->mxfe_txavail != MXFE_TXRING) 177029e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0); 177129e83d4bSgd78059 177229e83d4bSgd78059 /* tell the mac that we are ready to go! */ 177329e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 177429e83d4bSgd78059 mac_tx_update(mxfep->mxfe_mh); 177529e83d4bSgd78059 } 177629e83d4bSgd78059 177729e83d4bSgd78059 void 177829e83d4bSgd78059 mxfe_stopmac(mxfe_t *mxfep) 177929e83d4bSgd78059 { 178029e83d4bSgd78059 int i; 178129e83d4bSgd78059 178229e83d4bSgd78059 /* exclusive access to the hardware! */ 178329e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 178429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 178529e83d4bSgd78059 178629e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 178729e83d4bSgd78059 178829e83d4bSgd78059 /* 178929e83d4bSgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain. 179029e83d4bSgd78059 * We just add up to the nearest msec (2), which should be 179129e83d4bSgd78059 * plenty to complete. 179229e83d4bSgd78059 * 179329e83d4bSgd78059 * Note that some chips never seem to indicate the transition to 179429e83d4bSgd78059 * the stopped state properly. Experience shows that we can safely 179529e83d4bSgd78059 * proceed anyway, after waiting the requisite timeout. 179629e83d4bSgd78059 */ 179729e83d4bSgd78059 for (i = 2000; i != 0; i -= 10) { 179829e83d4bSgd78059 if ((GETCSR(mxfep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0) 179929e83d4bSgd78059 break; 180029e83d4bSgd78059 drv_usecwait(10); 180129e83d4bSgd78059 } 180229e83d4bSgd78059 180329e83d4bSgd78059 /* prevent an interrupt */ 180429e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, INT_RXSTOPPED | INT_TXSTOPPED); 180529e83d4bSgd78059 } 180629e83d4bSgd78059 180729e83d4bSgd78059 void 180829e83d4bSgd78059 mxfe_resetrings(mxfe_t *mxfep) 180929e83d4bSgd78059 { 181029e83d4bSgd78059 int i; 181129e83d4bSgd78059 181229e83d4bSgd78059 /* now we need to reset the pointers... */ 181329e83d4bSgd78059 PUTCSR(mxfep, CSR_RDB, 0); 181429e83d4bSgd78059 PUTCSR(mxfep, CSR_TDB, 0); 181529e83d4bSgd78059 181629e83d4bSgd78059 /* reset the descriptor ring pointers */ 181729e83d4bSgd78059 mxfep->mxfe_rxhead = 0; 181829e83d4bSgd78059 mxfep->mxfe_txreclaim = 0; 181929e83d4bSgd78059 mxfep->mxfe_txsend = 0; 182029e83d4bSgd78059 mxfep->mxfe_txavail = MXFE_TXRING; 182129e83d4bSgd78059 182229e83d4bSgd78059 /* set up transmit descriptor ring */ 182329e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) { 182429e83d4bSgd78059 mxfe_desc_t *tmdp = &mxfep->mxfe_txdescp[i]; 182529e83d4bSgd78059 unsigned control = 0; 182629e83d4bSgd78059 if (i == (MXFE_TXRING - 1)) { 182729e83d4bSgd78059 control |= TXCTL_ENDRING; 182829e83d4bSgd78059 } 182929e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_status, 0); 183029e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_control, control); 183129e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, 0); 183229e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0); 183329e83d4bSgd78059 SYNCTXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV); 183429e83d4bSgd78059 } 183529e83d4bSgd78059 PUTCSR(mxfep, CSR_TDB, mxfep->mxfe_txdesc_paddr); 183629e83d4bSgd78059 183729e83d4bSgd78059 /* make the receive buffers available */ 183829e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) { 183929e83d4bSgd78059 mxfe_rxbuf_t *rxb = mxfep->mxfe_rxbufs[i]; 184029e83d4bSgd78059 mxfe_desc_t *rmdp = &mxfep->mxfe_rxdescp[i]; 184129e83d4bSgd78059 unsigned control; 184229e83d4bSgd78059 184329e83d4bSgd78059 control = MXFE_BUFSZ & RXCTL_BUFLEN1; 184429e83d4bSgd78059 if (i == (MXFE_RXRING - 1)) { 184529e83d4bSgd78059 control |= RXCTL_ENDRING; 184629e83d4bSgd78059 } 184729e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer1, rxb->rxb_paddr); 184829e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer2, 0); 184929e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_control, control); 185029e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_status, RXSTAT_OWN); 185129e83d4bSgd78059 SYNCRXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV); 185229e83d4bSgd78059 } 185329e83d4bSgd78059 PUTCSR(mxfep, CSR_RDB, mxfep->mxfe_rxdesc_paddr); 185429e83d4bSgd78059 } 185529e83d4bSgd78059 185629e83d4bSgd78059 void 185729e83d4bSgd78059 mxfe_stopall(mxfe_t *mxfep) 185829e83d4bSgd78059 { 185929e83d4bSgd78059 mxfe_disableinterrupts(mxfep); 186029e83d4bSgd78059 186129e83d4bSgd78059 mxfe_stopmac(mxfep); 186229e83d4bSgd78059 186329e83d4bSgd78059 /* stop the phy */ 186429e83d4bSgd78059 mxfe_stopphy(mxfep); 186529e83d4bSgd78059 } 186629e83d4bSgd78059 186729e83d4bSgd78059 void 186829e83d4bSgd78059 mxfe_startall(mxfe_t *mxfep) 186929e83d4bSgd78059 { 187029e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 187129e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 187229e83d4bSgd78059 187329e83d4bSgd78059 /* make sure interrupts are disabled to begin */ 187429e83d4bSgd78059 mxfe_disableinterrupts(mxfep); 187529e83d4bSgd78059 187629e83d4bSgd78059 /* initialize the chip */ 187729e83d4bSgd78059 (void) mxfe_initialize(mxfep); 187829e83d4bSgd78059 187929e83d4bSgd78059 /* now we can enable interrupts */ 188029e83d4bSgd78059 mxfe_enableinterrupts(mxfep); 188129e83d4bSgd78059 188229e83d4bSgd78059 /* start up the phy */ 188329e83d4bSgd78059 mxfe_startphy(mxfep); 188429e83d4bSgd78059 188529e83d4bSgd78059 /* start up the mac */ 188629e83d4bSgd78059 mxfe_startmac(mxfep); 188729e83d4bSgd78059 } 188829e83d4bSgd78059 188929e83d4bSgd78059 void 189029e83d4bSgd78059 mxfe_resetall(mxfe_t *mxfep) 189129e83d4bSgd78059 { 189229e83d4bSgd78059 mxfep->mxfe_resetting = B_TRUE; 189329e83d4bSgd78059 mxfe_stopall(mxfep); 189429e83d4bSgd78059 mxfep->mxfe_resetting = B_FALSE; 189529e83d4bSgd78059 mxfe_startall(mxfep); 189629e83d4bSgd78059 } 189729e83d4bSgd78059 189829e83d4bSgd78059 mxfe_txbuf_t * 189929e83d4bSgd78059 mxfe_alloctxbuf(mxfe_t *mxfep) 190029e83d4bSgd78059 { 190129e83d4bSgd78059 ddi_dma_cookie_t dmac; 190229e83d4bSgd78059 unsigned ncookies; 190329e83d4bSgd78059 mxfe_txbuf_t *txb; 190429e83d4bSgd78059 size_t len; 190529e83d4bSgd78059 190629e83d4bSgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP); 190729e83d4bSgd78059 190829e83d4bSgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_txattr, 190929e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) { 191029e83d4bSgd78059 return (NULL); 191129e83d4bSgd78059 } 191229e83d4bSgd78059 191329e83d4bSgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, MXFE_BUFSZ, &mxfe_bufattr, 191429e83d4bSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, 191529e83d4bSgd78059 &len, &txb->txb_acch) != DDI_SUCCESS) { 191629e83d4bSgd78059 return (NULL); 191729e83d4bSgd78059 } 191829e83d4bSgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf, 191929e83d4bSgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 192029e83d4bSgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) { 192129e83d4bSgd78059 return (NULL); 192229e83d4bSgd78059 } 192329e83d4bSgd78059 txb->txb_paddr = dmac.dmac_address; 192429e83d4bSgd78059 192529e83d4bSgd78059 return (txb); 192629e83d4bSgd78059 } 192729e83d4bSgd78059 192829e83d4bSgd78059 void 192929e83d4bSgd78059 mxfe_destroytxbuf(mxfe_txbuf_t *txb) 193029e83d4bSgd78059 { 193129e83d4bSgd78059 if (txb != NULL) { 193229e83d4bSgd78059 if (txb->txb_paddr) 193329e83d4bSgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah); 193429e83d4bSgd78059 if (txb->txb_acch) 193529e83d4bSgd78059 ddi_dma_mem_free(&txb->txb_acch); 193629e83d4bSgd78059 if (txb->txb_dmah) 193729e83d4bSgd78059 ddi_dma_free_handle(&txb->txb_dmah); 193829e83d4bSgd78059 kmem_free(txb, sizeof (*txb)); 193929e83d4bSgd78059 } 194029e83d4bSgd78059 } 194129e83d4bSgd78059 194229e83d4bSgd78059 mxfe_rxbuf_t * 194329e83d4bSgd78059 mxfe_allocrxbuf(mxfe_t *mxfep) 194429e83d4bSgd78059 { 194529e83d4bSgd78059 mxfe_rxbuf_t *rxb; 194629e83d4bSgd78059 size_t len; 194729e83d4bSgd78059 unsigned ccnt; 194829e83d4bSgd78059 ddi_dma_cookie_t dmac; 194929e83d4bSgd78059 195029e83d4bSgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP); 195129e83d4bSgd78059 195229e83d4bSgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 195329e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) { 195429e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb)); 195529e83d4bSgd78059 return (NULL); 195629e83d4bSgd78059 } 195729e83d4bSgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, MXFE_BUFSZ, &mxfe_bufattr, 195829e83d4bSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 195929e83d4bSgd78059 &rxb->rxb_buf, &len, &rxb->rxb_acch) != DDI_SUCCESS) { 196029e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 196129e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb)); 196229e83d4bSgd78059 return (NULL); 196329e83d4bSgd78059 } 196429e83d4bSgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len, 196529e83d4bSgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac, 196629e83d4bSgd78059 &ccnt) != DDI_DMA_MAPPED) { 196729e83d4bSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 196829e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 196929e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb)); 197029e83d4bSgd78059 return (NULL); 197129e83d4bSgd78059 } 197229e83d4bSgd78059 rxb->rxb_paddr = dmac.dmac_address; 197329e83d4bSgd78059 197429e83d4bSgd78059 return (rxb); 197529e83d4bSgd78059 } 197629e83d4bSgd78059 197729e83d4bSgd78059 void 197829e83d4bSgd78059 mxfe_destroyrxbuf(mxfe_rxbuf_t *rxb) 197929e83d4bSgd78059 { 198029e83d4bSgd78059 if (rxb != NULL) { 198129e83d4bSgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah); 198229e83d4bSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 198329e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 198429e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb)); 198529e83d4bSgd78059 } 198629e83d4bSgd78059 } 198729e83d4bSgd78059 198829e83d4bSgd78059 /* 198929e83d4bSgd78059 * Allocate receive resources. 199029e83d4bSgd78059 */ 199129e83d4bSgd78059 int 199229e83d4bSgd78059 mxfe_allocrxring(mxfe_t *mxfep) 199329e83d4bSgd78059 { 199429e83d4bSgd78059 int rval; 199529e83d4bSgd78059 int i; 199629e83d4bSgd78059 size_t size; 199729e83d4bSgd78059 size_t len; 199829e83d4bSgd78059 ddi_dma_cookie_t dmac; 199929e83d4bSgd78059 unsigned ncookies; 200029e83d4bSgd78059 caddr_t kaddr; 200129e83d4bSgd78059 200229e83d4bSgd78059 size = MXFE_RXRING * sizeof (mxfe_desc_t); 200329e83d4bSgd78059 200429e83d4bSgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 200529e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_rxdesc_dmah); 200629e83d4bSgd78059 if (rval != DDI_SUCCESS) { 200729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 200829e83d4bSgd78059 "unable to allocate DMA handle for rx descriptors"); 200929e83d4bSgd78059 return (DDI_FAILURE); 201029e83d4bSgd78059 } 201129e83d4bSgd78059 201229e83d4bSgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_rxdesc_dmah, size, &mxfe_devattr, 201329e83d4bSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 201429e83d4bSgd78059 &mxfep->mxfe_rxdesc_acch); 201529e83d4bSgd78059 if (rval != DDI_SUCCESS) { 201629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 201729e83d4bSgd78059 "unable to allocate DMA memory for rx descriptors"); 201829e83d4bSgd78059 return (DDI_FAILURE); 201929e83d4bSgd78059 } 202029e83d4bSgd78059 202129e83d4bSgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_rxdesc_dmah, NULL, kaddr, 202229e83d4bSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 202329e83d4bSgd78059 &dmac, &ncookies); 202429e83d4bSgd78059 if (rval != DDI_DMA_MAPPED) { 202529e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 202629e83d4bSgd78059 "unable to bind DMA for rx descriptors"); 202729e83d4bSgd78059 return (DDI_FAILURE); 202829e83d4bSgd78059 } 202929e83d4bSgd78059 203029e83d4bSgd78059 /* because of mxfe_dma_attr */ 203129e83d4bSgd78059 ASSERT(ncookies == 1); 203229e83d4bSgd78059 203329e83d4bSgd78059 /* we take the 32-bit physical address out of the cookie */ 203429e83d4bSgd78059 mxfep->mxfe_rxdesc_paddr = dmac.dmac_address; 203529e83d4bSgd78059 mxfep->mxfe_rxdescp = (void *)kaddr; 203629e83d4bSgd78059 203729e83d4bSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 203829e83d4bSgd78059 mxfep->mxfe_rxbufs = kmem_zalloc(MXFE_RXRING * sizeof (mxfe_rxbuf_t *), 203929e83d4bSgd78059 KM_SLEEP); 204029e83d4bSgd78059 204129e83d4bSgd78059 /* now allocate rx buffers */ 204229e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) { 204329e83d4bSgd78059 mxfe_rxbuf_t *rxb = mxfe_allocrxbuf(mxfep); 204429e83d4bSgd78059 if (rxb == NULL) 204529e83d4bSgd78059 return (DDI_FAILURE); 204629e83d4bSgd78059 mxfep->mxfe_rxbufs[i] = rxb; 204729e83d4bSgd78059 } 204829e83d4bSgd78059 204929e83d4bSgd78059 return (DDI_SUCCESS); 205029e83d4bSgd78059 } 205129e83d4bSgd78059 205229e83d4bSgd78059 /* 205329e83d4bSgd78059 * Allocate transmit resources. 205429e83d4bSgd78059 */ 205529e83d4bSgd78059 int 205629e83d4bSgd78059 mxfe_alloctxring(mxfe_t *mxfep) 205729e83d4bSgd78059 { 205829e83d4bSgd78059 int rval; 205929e83d4bSgd78059 int i; 206029e83d4bSgd78059 size_t size; 206129e83d4bSgd78059 size_t len; 206229e83d4bSgd78059 ddi_dma_cookie_t dmac; 206329e83d4bSgd78059 unsigned ncookies; 206429e83d4bSgd78059 caddr_t kaddr; 206529e83d4bSgd78059 206629e83d4bSgd78059 size = MXFE_TXRING * sizeof (mxfe_desc_t); 206729e83d4bSgd78059 206829e83d4bSgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 206929e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_txdesc_dmah); 207029e83d4bSgd78059 if (rval != DDI_SUCCESS) { 207129e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 207229e83d4bSgd78059 "unable to allocate DMA handle for tx descriptors"); 207329e83d4bSgd78059 return (DDI_FAILURE); 207429e83d4bSgd78059 } 207529e83d4bSgd78059 207629e83d4bSgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_txdesc_dmah, size, &mxfe_devattr, 207729e83d4bSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 207829e83d4bSgd78059 &mxfep->mxfe_txdesc_acch); 207929e83d4bSgd78059 if (rval != DDI_SUCCESS) { 208029e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 208129e83d4bSgd78059 "unable to allocate DMA memory for tx descriptors"); 208229e83d4bSgd78059 return (DDI_FAILURE); 208329e83d4bSgd78059 } 208429e83d4bSgd78059 208529e83d4bSgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_txdesc_dmah, NULL, kaddr, 208629e83d4bSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 208729e83d4bSgd78059 &dmac, &ncookies); 208829e83d4bSgd78059 if (rval != DDI_DMA_MAPPED) { 208929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, 209029e83d4bSgd78059 "unable to bind DMA for tx descriptors"); 209129e83d4bSgd78059 return (DDI_FAILURE); 209229e83d4bSgd78059 } 209329e83d4bSgd78059 209429e83d4bSgd78059 /* because of mxfe_dma_attr */ 209529e83d4bSgd78059 ASSERT(ncookies == 1); 209629e83d4bSgd78059 209729e83d4bSgd78059 /* we take the 32-bit physical address out of the cookie */ 209829e83d4bSgd78059 mxfep->mxfe_txdesc_paddr = dmac.dmac_address; 209929e83d4bSgd78059 mxfep->mxfe_txdescp = (void *)kaddr; 210029e83d4bSgd78059 210129e83d4bSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 210229e83d4bSgd78059 mxfep->mxfe_txbufs = kmem_zalloc(MXFE_TXRING * sizeof (mxfe_txbuf_t *), 210329e83d4bSgd78059 KM_SLEEP); 210429e83d4bSgd78059 210529e83d4bSgd78059 /* now allocate tx buffers */ 210629e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) { 210729e83d4bSgd78059 mxfe_txbuf_t *txb = mxfe_alloctxbuf(mxfep); 210829e83d4bSgd78059 if (txb == NULL) 210929e83d4bSgd78059 return (DDI_FAILURE); 211029e83d4bSgd78059 /* stick it in the stack */ 211129e83d4bSgd78059 mxfep->mxfe_txbufs[i] = txb; 211229e83d4bSgd78059 } 211329e83d4bSgd78059 211429e83d4bSgd78059 return (DDI_SUCCESS); 211529e83d4bSgd78059 } 211629e83d4bSgd78059 211729e83d4bSgd78059 void 211829e83d4bSgd78059 mxfe_freerxring(mxfe_t *mxfep) 211929e83d4bSgd78059 { 212029e83d4bSgd78059 int i; 212129e83d4bSgd78059 212229e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) { 212329e83d4bSgd78059 mxfe_destroyrxbuf(mxfep->mxfe_rxbufs[i]); 212429e83d4bSgd78059 } 212529e83d4bSgd78059 212629e83d4bSgd78059 if (mxfep->mxfe_rxbufs) { 212729e83d4bSgd78059 kmem_free(mxfep->mxfe_rxbufs, 212829e83d4bSgd78059 MXFE_RXRING * sizeof (mxfe_rxbuf_t *)); 212929e83d4bSgd78059 } 213029e83d4bSgd78059 213129e83d4bSgd78059 if (mxfep->mxfe_rxdesc_paddr) 213229e83d4bSgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_rxdesc_dmah); 213329e83d4bSgd78059 if (mxfep->mxfe_rxdesc_acch) 213429e83d4bSgd78059 ddi_dma_mem_free(&mxfep->mxfe_rxdesc_acch); 213529e83d4bSgd78059 if (mxfep->mxfe_rxdesc_dmah) 213629e83d4bSgd78059 ddi_dma_free_handle(&mxfep->mxfe_rxdesc_dmah); 213729e83d4bSgd78059 } 213829e83d4bSgd78059 213929e83d4bSgd78059 void 214029e83d4bSgd78059 mxfe_freetxring(mxfe_t *mxfep) 214129e83d4bSgd78059 { 214229e83d4bSgd78059 int i; 214329e83d4bSgd78059 214429e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) { 214529e83d4bSgd78059 mxfe_destroytxbuf(mxfep->mxfe_txbufs[i]); 214629e83d4bSgd78059 } 214729e83d4bSgd78059 214829e83d4bSgd78059 if (mxfep->mxfe_txbufs) { 214929e83d4bSgd78059 kmem_free(mxfep->mxfe_txbufs, 215029e83d4bSgd78059 MXFE_TXRING * sizeof (mxfe_txbuf_t *)); 215129e83d4bSgd78059 } 215229e83d4bSgd78059 if (mxfep->mxfe_txdesc_paddr) 215329e83d4bSgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_txdesc_dmah); 215429e83d4bSgd78059 if (mxfep->mxfe_txdesc_acch) 215529e83d4bSgd78059 ddi_dma_mem_free(&mxfep->mxfe_txdesc_acch); 215629e83d4bSgd78059 if (mxfep->mxfe_txdesc_dmah) 215729e83d4bSgd78059 ddi_dma_free_handle(&mxfep->mxfe_txdesc_dmah); 215829e83d4bSgd78059 } 215929e83d4bSgd78059 216029e83d4bSgd78059 /* 216129e83d4bSgd78059 * Interrupt service routine. 216229e83d4bSgd78059 */ 216329e83d4bSgd78059 unsigned 216429e83d4bSgd78059 mxfe_intr(caddr_t arg) 216529e83d4bSgd78059 { 216629e83d4bSgd78059 mxfe_t *mxfep = (void *)arg; 216729e83d4bSgd78059 uint32_t status; 216829e83d4bSgd78059 mblk_t *mp = NULL; 216977860f66SGarrett D'Amore boolean_t error = B_FALSE; 217029e83d4bSgd78059 217129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 217229e83d4bSgd78059 217329e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) { 217429e83d4bSgd78059 /* we cannot receive interrupts! */ 217529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 217629e83d4bSgd78059 return (DDI_INTR_UNCLAIMED); 217729e83d4bSgd78059 } 217829e83d4bSgd78059 217929e83d4bSgd78059 /* check interrupt status bits, did we interrupt? */ 218029e83d4bSgd78059 status = GETCSR(mxfep, CSR_SR) & INT_ALL; 218129e83d4bSgd78059 218229e83d4bSgd78059 if (status == 0) { 218329e83d4bSgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 218429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 218529e83d4bSgd78059 return (DDI_INTR_UNCLAIMED); 218629e83d4bSgd78059 } 218729e83d4bSgd78059 /* ack the interrupt */ 218829e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, status); 218929e83d4bSgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++; 219029e83d4bSgd78059 219129e83d4bSgd78059 if (!(mxfep->mxfe_flags & MXFE_RUNNING)) { 219229e83d4bSgd78059 /* not running, don't touch anything */ 219329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 219429e83d4bSgd78059 return (DDI_INTR_CLAIMED); 219529e83d4bSgd78059 } 219629e83d4bSgd78059 219729e83d4bSgd78059 if (status & INT_RXOK) { 219829e83d4bSgd78059 /* receive packets */ 219977860f66SGarrett D'Amore if (mxfe_receive(mxfep, &mp)) { 220077860f66SGarrett D'Amore error = B_TRUE; 220177860f66SGarrett D'Amore } 220229e83d4bSgd78059 } 220329e83d4bSgd78059 220429e83d4bSgd78059 if (status & INT_TXOK) { 220529e83d4bSgd78059 /* transmit completed */ 220629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 220729e83d4bSgd78059 mxfe_reclaim(mxfep); 220829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 220929e83d4bSgd78059 } 221029e83d4bSgd78059 221129e83d4bSgd78059 if (((status & (INT_TIMER|INT_ANEG)) != 0) || 221229e83d4bSgd78059 ((mxfep->mxfe_linkup == LINK_STATE_UP) && 221329e83d4bSgd78059 ((status & (INT_10LINK|INT_100LINK)) != 0))) { 221429e83d4bSgd78059 /* rescan the link */ 221529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 221629e83d4bSgd78059 mxfe_checklink(mxfep); 221729e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 221829e83d4bSgd78059 } 221929e83d4bSgd78059 222029e83d4bSgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED|INT_RXNOBUF| 222129e83d4bSgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) { 222229e83d4bSgd78059 222329e83d4bSgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) { 222429e83d4bSgd78059 mxfep->mxfe_jabber++; 222529e83d4bSgd78059 } 222677860f66SGarrett D'Amore DBG(DWARN, "error interrupt: status %x", status); 222777860f66SGarrett D'Amore error = B_TRUE; 222829e83d4bSgd78059 } 222929e83d4bSgd78059 223029e83d4bSgd78059 if (status & INT_BUSERR) { 223129e83d4bSgd78059 switch (status & SR_BERR_TYPE) { 223229e83d4bSgd78059 case SR_BERR_PARITY: 223329e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI parity error"); 223429e83d4bSgd78059 break; 223529e83d4bSgd78059 case SR_BERR_TARGET_ABORT: 223629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI target abort"); 223729e83d4bSgd78059 break; 223829e83d4bSgd78059 case SR_BERR_MASTER_ABORT: 223929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI master abort"); 224029e83d4bSgd78059 break; 224129e83d4bSgd78059 default: 224229e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Unknown PCI error"); 224329e83d4bSgd78059 break; 224429e83d4bSgd78059 } 224529e83d4bSgd78059 224677860f66SGarrett D'Amore error = B_TRUE; 224777860f66SGarrett D'Amore } 224877860f66SGarrett D'Amore 224977860f66SGarrett D'Amore if (error) { 225029e83d4bSgd78059 /* reset the chip in an attempt to fix things */ 225129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 225229e83d4bSgd78059 mxfe_resetall(mxfep); 225329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 225429e83d4bSgd78059 } 225529e83d4bSgd78059 225629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 225729e83d4bSgd78059 225829e83d4bSgd78059 /* 225929e83d4bSgd78059 * Send up packets. We do this outside of the intrlock. 226029e83d4bSgd78059 */ 226129e83d4bSgd78059 if (mp) { 226229e83d4bSgd78059 mac_rx(mxfep->mxfe_mh, NULL, mp); 226329e83d4bSgd78059 } 226429e83d4bSgd78059 226529e83d4bSgd78059 return (DDI_INTR_CLAIMED); 226629e83d4bSgd78059 } 226729e83d4bSgd78059 226829e83d4bSgd78059 void 226929e83d4bSgd78059 mxfe_enableinterrupts(mxfe_t *mxfep) 227029e83d4bSgd78059 { 227129e83d4bSgd78059 unsigned mask = INT_WANTED; 227229e83d4bSgd78059 227329e83d4bSgd78059 if (mxfep->mxfe_wantw) 227429e83d4bSgd78059 mask |= INT_TXOK; 227529e83d4bSgd78059 227629e83d4bSgd78059 if (MXFE_MODEL(mxfep) != MXFE_98713A) 227729e83d4bSgd78059 mask |= INT_LINKSTATUS; 227829e83d4bSgd78059 227929e83d4bSgd78059 DBG(DINTR, "setting int mask to 0x%x", mask); 228029e83d4bSgd78059 PUTCSR(mxfep, CSR_IER, mask); 228129e83d4bSgd78059 } 228229e83d4bSgd78059 228329e83d4bSgd78059 void 228429e83d4bSgd78059 mxfe_disableinterrupts(mxfe_t *mxfep) 228529e83d4bSgd78059 { 228629e83d4bSgd78059 /* disable further interrupts */ 228729e83d4bSgd78059 PUTCSR(mxfep, CSR_IER, 0); 228829e83d4bSgd78059 228929e83d4bSgd78059 /* clear any pending interrupts */ 229029e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, INT_ALL); 229129e83d4bSgd78059 } 229229e83d4bSgd78059 229329e83d4bSgd78059 void 229429e83d4bSgd78059 mxfe_send_setup(mxfe_t *mxfep) 229529e83d4bSgd78059 { 229629e83d4bSgd78059 mxfe_txbuf_t *txb; 229729e83d4bSgd78059 mxfe_desc_t *tmdp; 229829e83d4bSgd78059 229929e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 230029e83d4bSgd78059 230129e83d4bSgd78059 /* setup frame -- must be at head of list -- guaranteed by caller! */ 230229e83d4bSgd78059 ASSERT(mxfep->mxfe_txsend == 0); 230329e83d4bSgd78059 230429e83d4bSgd78059 txb = mxfep->mxfe_txbufs[0]; 230529e83d4bSgd78059 tmdp = &mxfep->mxfe_txdescp[0]; 230629e83d4bSgd78059 230729e83d4bSgd78059 bzero(txb->txb_buf, MXFE_SETUP_LEN); 230829e83d4bSgd78059 230929e83d4bSgd78059 /* program the unicast address */ 231029e83d4bSgd78059 txb->txb_buf[156] = mxfep->mxfe_curraddr[0]; 231129e83d4bSgd78059 txb->txb_buf[157] = mxfep->mxfe_curraddr[1]; 231229e83d4bSgd78059 txb->txb_buf[160] = mxfep->mxfe_curraddr[2]; 231329e83d4bSgd78059 txb->txb_buf[161] = mxfep->mxfe_curraddr[3]; 231429e83d4bSgd78059 txb->txb_buf[164] = mxfep->mxfe_curraddr[4]; 231529e83d4bSgd78059 txb->txb_buf[165] = mxfep->mxfe_curraddr[5]; 231629e83d4bSgd78059 231729e83d4bSgd78059 /* make sure that the hardware can see it */ 231829e83d4bSgd78059 SYNCTXBUF(txb, MXFE_SETUP_LEN, DDI_DMA_SYNC_FORDEV); 231929e83d4bSgd78059 232029e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_control, 232129e83d4bSgd78059 TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE | TXCTL_HASHPERF | 232229e83d4bSgd78059 TXCTL_SETUP | MXFE_SETUP_LEN); 232329e83d4bSgd78059 232429e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, txb->txb_paddr); 232529e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0); 232629e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_status, TXSTAT_OWN); 232729e83d4bSgd78059 232829e83d4bSgd78059 /* sync the descriptor out to the device */ 232929e83d4bSgd78059 SYNCTXDESC(mxfep, 0, DDI_DMA_SYNC_FORDEV); 233029e83d4bSgd78059 233129e83d4bSgd78059 /* 233229e83d4bSgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 233329e83d4bSgd78059 * etc. 233429e83d4bSgd78059 */ 233529e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0); 233629e83d4bSgd78059 mxfep->mxfe_txsend++; 233729e83d4bSgd78059 mxfep->mxfe_txavail--; 233829e83d4bSgd78059 233929e83d4bSgd78059 /* 234029e83d4bSgd78059 * Program promiscuous mode. 234129e83d4bSgd78059 */ 234229e83d4bSgd78059 if (mxfep->mxfe_promisc) { 234329e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 234429e83d4bSgd78059 } else { 234529e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 234629e83d4bSgd78059 } 234729e83d4bSgd78059 } 234829e83d4bSgd78059 234929e83d4bSgd78059 boolean_t 235029e83d4bSgd78059 mxfe_send(mxfe_t *mxfep, mblk_t *mp) 235129e83d4bSgd78059 { 235229e83d4bSgd78059 size_t len; 235329e83d4bSgd78059 mxfe_txbuf_t *txb; 235429e83d4bSgd78059 mxfe_desc_t *tmd; 235529e83d4bSgd78059 uint32_t control; 235629e83d4bSgd78059 int txsend; 235729e83d4bSgd78059 235829e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 235929e83d4bSgd78059 ASSERT(mp != NULL); 236029e83d4bSgd78059 236129e83d4bSgd78059 len = msgsize(mp); 236229e83d4bSgd78059 if (len > ETHERVLANMTU) { 236329e83d4bSgd78059 DBG(DXMIT, "frame too long: %d", len); 236429e83d4bSgd78059 mxfep->mxfe_macxmt_errors++; 236529e83d4bSgd78059 freemsg(mp); 236629e83d4bSgd78059 return (B_TRUE); 236729e83d4bSgd78059 } 236829e83d4bSgd78059 236929e83d4bSgd78059 if (mxfep->mxfe_txavail < MXFE_TXRECLAIM) 237029e83d4bSgd78059 mxfe_reclaim(mxfep); 237129e83d4bSgd78059 237229e83d4bSgd78059 if (mxfep->mxfe_txavail == 0) { 237329e83d4bSgd78059 /* no more tmds */ 237429e83d4bSgd78059 mxfep->mxfe_wantw = B_TRUE; 237529e83d4bSgd78059 /* enable TX interrupt */ 237629e83d4bSgd78059 mxfe_enableinterrupts(mxfep); 237729e83d4bSgd78059 return (B_FALSE); 237829e83d4bSgd78059 } 237929e83d4bSgd78059 238029e83d4bSgd78059 txsend = mxfep->mxfe_txsend; 238129e83d4bSgd78059 238229e83d4bSgd78059 /* 238329e83d4bSgd78059 * For simplicity, we just do a copy into a preallocated 238429e83d4bSgd78059 * DMA buffer. 238529e83d4bSgd78059 */ 238629e83d4bSgd78059 238729e83d4bSgd78059 txb = mxfep->mxfe_txbufs[txsend]; 238829e83d4bSgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */ 238929e83d4bSgd78059 239029e83d4bSgd78059 /* 239129e83d4bSgd78059 * Statistics. 239229e83d4bSgd78059 */ 239329e83d4bSgd78059 mxfep->mxfe_opackets++; 239429e83d4bSgd78059 mxfep->mxfe_obytes += len; 239529e83d4bSgd78059 if (txb->txb_buf[0] & 0x1) { 239629e83d4bSgd78059 if (bcmp(txb->txb_buf, mxfe_broadcast, ETHERADDRL) != 0) 239729e83d4bSgd78059 mxfep->mxfe_multixmt++; 239829e83d4bSgd78059 else 239929e83d4bSgd78059 mxfep->mxfe_brdcstxmt++; 240029e83d4bSgd78059 } 240129e83d4bSgd78059 240229e83d4bSgd78059 /* note len is already known to be a small unsigned */ 240329e83d4bSgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE; 240429e83d4bSgd78059 240529e83d4bSgd78059 if (txsend == (MXFE_TXRING - 1)) 240629e83d4bSgd78059 control |= TXCTL_ENDRING; 240729e83d4bSgd78059 240829e83d4bSgd78059 tmd = &mxfep->mxfe_txdescp[txsend]; 240929e83d4bSgd78059 241029e83d4bSgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV); 241129e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_control, control); 241229e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_buffer1, txb->txb_paddr); 241329e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_buffer2, 0); 241429e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_status, TXSTAT_OWN); 241529e83d4bSgd78059 /* sync the descriptor out to the device */ 241629e83d4bSgd78059 SYNCTXDESC(mxfep, txsend, DDI_DMA_SYNC_FORDEV); 241729e83d4bSgd78059 241829e83d4bSgd78059 /* 241929e83d4bSgd78059 * Note the new values of txavail and txsend. 242029e83d4bSgd78059 */ 242129e83d4bSgd78059 mxfep->mxfe_txavail--; 242229e83d4bSgd78059 mxfep->mxfe_txsend = (txsend + 1) % MXFE_TXRING; 242329e83d4bSgd78059 242429e83d4bSgd78059 /* 242529e83d4bSgd78059 * It should never, ever take more than 5 seconds to drain 242629e83d4bSgd78059 * the ring. If it happens, then we are stuck! 242729e83d4bSgd78059 */ 242829e83d4bSgd78059 mxfep->mxfe_txstall_time = gethrtime() + (5 * 1000000000ULL); 242929e83d4bSgd78059 243029e83d4bSgd78059 /* 243129e83d4bSgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 243229e83d4bSgd78059 * etc. 243329e83d4bSgd78059 */ 243429e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0); 243529e83d4bSgd78059 243629e83d4bSgd78059 return (B_TRUE); 243729e83d4bSgd78059 } 243829e83d4bSgd78059 243929e83d4bSgd78059 /* 244029e83d4bSgd78059 * Reclaim buffers that have completed transmission. 244129e83d4bSgd78059 */ 244229e83d4bSgd78059 void 244329e83d4bSgd78059 mxfe_reclaim(mxfe_t *mxfep) 244429e83d4bSgd78059 { 244529e83d4bSgd78059 mxfe_desc_t *tmdp; 244629e83d4bSgd78059 244729e83d4bSgd78059 while (mxfep->mxfe_txavail != MXFE_TXRING) { 244829e83d4bSgd78059 uint32_t status; 244929e83d4bSgd78059 uint32_t control; 245029e83d4bSgd78059 int index = mxfep->mxfe_txreclaim; 245129e83d4bSgd78059 245229e83d4bSgd78059 tmdp = &mxfep->mxfe_txdescp[index]; 245329e83d4bSgd78059 245429e83d4bSgd78059 /* sync it before we read it */ 245529e83d4bSgd78059 SYNCTXDESC(mxfep, index, DDI_DMA_SYNC_FORKERNEL); 245629e83d4bSgd78059 245729e83d4bSgd78059 control = GETTXDESC(mxfep, tmdp->desc_control); 245829e83d4bSgd78059 status = GETTXDESC(mxfep, tmdp->desc_status); 245929e83d4bSgd78059 246029e83d4bSgd78059 if (status & TXSTAT_OWN) { 246129e83d4bSgd78059 /* chip is still working on it, we're done */ 246229e83d4bSgd78059 break; 246329e83d4bSgd78059 } 246429e83d4bSgd78059 246529e83d4bSgd78059 mxfep->mxfe_txavail++; 246629e83d4bSgd78059 mxfep->mxfe_txreclaim = (index + 1) % MXFE_TXRING; 246729e83d4bSgd78059 246829e83d4bSgd78059 /* in the most common successful case, all bits are clear */ 246929e83d4bSgd78059 if (status == 0) 247029e83d4bSgd78059 continue; 247129e83d4bSgd78059 247229e83d4bSgd78059 if (((control & TXCTL_SETUP) != 0) || 247329e83d4bSgd78059 ((control & TXCTL_LAST) == 0)) { 247429e83d4bSgd78059 /* no interesting statistics here */ 247529e83d4bSgd78059 continue; 247629e83d4bSgd78059 } 247729e83d4bSgd78059 247829e83d4bSgd78059 if (status & TXSTAT_TXERR) { 247929e83d4bSgd78059 mxfep->mxfe_errxmt++; 248029e83d4bSgd78059 248129e83d4bSgd78059 if (status & TXSTAT_JABBER) { 248229e83d4bSgd78059 /* transmit jabber timeout */ 248329e83d4bSgd78059 mxfep->mxfe_macxmt_errors++; 248429e83d4bSgd78059 } 248529e83d4bSgd78059 if (status & (TXSTAT_CARRLOST | TXSTAT_NOCARR)) { 248629e83d4bSgd78059 mxfep->mxfe_carrier_errors++; 248729e83d4bSgd78059 } 248829e83d4bSgd78059 if (status & TXSTAT_UFLOW) { 248929e83d4bSgd78059 mxfep->mxfe_underflow++; 249029e83d4bSgd78059 } 249129e83d4bSgd78059 if (status & TXSTAT_LATECOL) { 249229e83d4bSgd78059 mxfep->mxfe_tx_late_collisions++; 249329e83d4bSgd78059 } 249429e83d4bSgd78059 if (status & TXSTAT_EXCOLL) { 249529e83d4bSgd78059 mxfep->mxfe_ex_collisions++; 249629e83d4bSgd78059 mxfep->mxfe_collisions += 16; 249729e83d4bSgd78059 } 249829e83d4bSgd78059 } 249929e83d4bSgd78059 250029e83d4bSgd78059 if (status & TXSTAT_DEFER) { 250129e83d4bSgd78059 mxfep->mxfe_defer_xmts++; 250229e83d4bSgd78059 } 250329e83d4bSgd78059 250429e83d4bSgd78059 /* collision counting */ 250529e83d4bSgd78059 if (TXCOLLCNT(status) == 1) { 250629e83d4bSgd78059 mxfep->mxfe_collisions++; 250729e83d4bSgd78059 mxfep->mxfe_first_collisions++; 250829e83d4bSgd78059 } else if (TXCOLLCNT(status)) { 250929e83d4bSgd78059 mxfep->mxfe_collisions += TXCOLLCNT(status); 251029e83d4bSgd78059 mxfep->mxfe_multi_collisions += TXCOLLCNT(status); 251129e83d4bSgd78059 } 251229e83d4bSgd78059 } 251329e83d4bSgd78059 251429e83d4bSgd78059 if (mxfep->mxfe_txavail >= MXFE_TXRESCHED) { 251529e83d4bSgd78059 if (mxfep->mxfe_wantw) { 251629e83d4bSgd78059 /* 251729e83d4bSgd78059 * we were able to reclaim some packets, so 251829e83d4bSgd78059 * disable tx interrupts 251929e83d4bSgd78059 */ 252029e83d4bSgd78059 mxfep->mxfe_wantw = B_FALSE; 252129e83d4bSgd78059 mxfe_enableinterrupts(mxfep); 252229e83d4bSgd78059 mac_tx_update(mxfep->mxfe_mh); 252329e83d4bSgd78059 } 252429e83d4bSgd78059 } 252529e83d4bSgd78059 } 252629e83d4bSgd78059 252777860f66SGarrett D'Amore boolean_t 252877860f66SGarrett D'Amore mxfe_receive(mxfe_t *mxfep, mblk_t **rxchain) 252929e83d4bSgd78059 { 253029e83d4bSgd78059 unsigned len; 253129e83d4bSgd78059 mxfe_rxbuf_t *rxb; 253229e83d4bSgd78059 mxfe_desc_t *rmd; 253329e83d4bSgd78059 uint32_t status; 253429e83d4bSgd78059 mblk_t *mpchain, **mpp, *mp; 253529e83d4bSgd78059 int head, cnt; 253677860f66SGarrett D'Amore boolean_t error = B_FALSE; 253729e83d4bSgd78059 253829e83d4bSgd78059 mpchain = NULL; 253929e83d4bSgd78059 mpp = &mpchain; 254029e83d4bSgd78059 head = mxfep->mxfe_rxhead; 254129e83d4bSgd78059 254229e83d4bSgd78059 /* limit the number of packets we process to a ring size */ 254329e83d4bSgd78059 for (cnt = 0; cnt < MXFE_RXRING; cnt++) { 254429e83d4bSgd78059 254529e83d4bSgd78059 DBG(DRECV, "receive at index %d", head); 254629e83d4bSgd78059 254729e83d4bSgd78059 rmd = &mxfep->mxfe_rxdescp[head]; 254829e83d4bSgd78059 rxb = mxfep->mxfe_rxbufs[head]; 254929e83d4bSgd78059 255029e83d4bSgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORKERNEL); 255129e83d4bSgd78059 status = GETRXDESC(mxfep, rmd->desc_status); 255229e83d4bSgd78059 if (status & RXSTAT_OWN) { 255329e83d4bSgd78059 /* chip is still chewing on it */ 255429e83d4bSgd78059 break; 255529e83d4bSgd78059 } 255629e83d4bSgd78059 255729e83d4bSgd78059 /* discard the ethernet frame checksum */ 255829e83d4bSgd78059 len = RXLENGTH(status) - ETHERFCSL; 255929e83d4bSgd78059 256029e83d4bSgd78059 DBG(DRECV, "recv length %d, status %x", len, status); 256129e83d4bSgd78059 256229e83d4bSgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) != 256329e83d4bSgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) { 256429e83d4bSgd78059 256529e83d4bSgd78059 mxfep->mxfe_errrcv++; 256629e83d4bSgd78059 256729e83d4bSgd78059 /* 256829e83d4bSgd78059 * Abnormal status bits detected, analyze further. 256929e83d4bSgd78059 */ 257029e83d4bSgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) != 257129e83d4bSgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) { 257277860f66SGarrett D'Amore /* someone trying to send jumbo frames? */ 257329e83d4bSgd78059 DBG(DRECV, "rx packet overspill"); 257429e83d4bSgd78059 if (status & RXSTAT_FIRST) { 257529e83d4bSgd78059 mxfep->mxfe_toolong_errors++; 257629e83d4bSgd78059 } 257729e83d4bSgd78059 } else if (status & RXSTAT_DESCERR) { 257877860f66SGarrett D'Amore /* this should never occur! */ 257929e83d4bSgd78059 mxfep->mxfe_macrcv_errors++; 258077860f66SGarrett D'Amore error = B_TRUE; 258129e83d4bSgd78059 258229e83d4bSgd78059 } else if (status & RXSTAT_RUNT) { 258329e83d4bSgd78059 mxfep->mxfe_runt++; 258429e83d4bSgd78059 258529e83d4bSgd78059 } else if (status & RXSTAT_COLLSEEN) { 258629e83d4bSgd78059 /* this should really be rx_late_collisions */ 258729e83d4bSgd78059 mxfep->mxfe_macrcv_errors++; 258829e83d4bSgd78059 258929e83d4bSgd78059 } else if (status & RXSTAT_DRIBBLE) { 259029e83d4bSgd78059 mxfep->mxfe_align_errors++; 259129e83d4bSgd78059 259229e83d4bSgd78059 } else if (status & RXSTAT_CRCERR) { 259329e83d4bSgd78059 mxfep->mxfe_fcs_errors++; 259429e83d4bSgd78059 259529e83d4bSgd78059 } else if (status & RXSTAT_OFLOW) { 259677860f66SGarrett D'Amore /* this is a MAC FIFO error, need to reset */ 259729e83d4bSgd78059 mxfep->mxfe_overflow++; 259877860f66SGarrett D'Amore error = B_TRUE; 259929e83d4bSgd78059 } 260029e83d4bSgd78059 } 260129e83d4bSgd78059 260229e83d4bSgd78059 else if (len > ETHERVLANMTU) { 260329e83d4bSgd78059 mxfep->mxfe_errrcv++; 260429e83d4bSgd78059 mxfep->mxfe_toolong_errors++; 260529e83d4bSgd78059 } 260629e83d4bSgd78059 260729e83d4bSgd78059 /* 260829e83d4bSgd78059 * At this point, the chip thinks the packet is OK. 260929e83d4bSgd78059 */ 261029e83d4bSgd78059 else { 261129e83d4bSgd78059 mp = allocb(len + MXFE_HEADROOM, 0); 261229e83d4bSgd78059 if (mp == NULL) { 261329e83d4bSgd78059 mxfep->mxfe_errrcv++; 261429e83d4bSgd78059 mxfep->mxfe_norcvbuf++; 261529e83d4bSgd78059 goto skip; 261629e83d4bSgd78059 } 261729e83d4bSgd78059 261829e83d4bSgd78059 /* sync the buffer before we look at it */ 261929e83d4bSgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL); 262029e83d4bSgd78059 mp->b_rptr += MXFE_HEADROOM; 262129e83d4bSgd78059 mp->b_wptr = mp->b_rptr + len; 262229e83d4bSgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len); 262329e83d4bSgd78059 262429e83d4bSgd78059 mxfep->mxfe_ipackets++; 262529e83d4bSgd78059 mxfep->mxfe_rbytes += len; 262629e83d4bSgd78059 if (status & RXSTAT_GROUP) { 262729e83d4bSgd78059 if (bcmp(mp->b_rptr, mxfe_broadcast, 262829e83d4bSgd78059 ETHERADDRL) == 0) 262929e83d4bSgd78059 mxfep->mxfe_brdcstrcv++; 263029e83d4bSgd78059 else 263129e83d4bSgd78059 mxfep->mxfe_multircv++; 263229e83d4bSgd78059 } 263329e83d4bSgd78059 *mpp = mp; 263429e83d4bSgd78059 mpp = &mp->b_next; 263529e83d4bSgd78059 } 263629e83d4bSgd78059 263729e83d4bSgd78059 skip: 263829e83d4bSgd78059 /* return ring entry to the hardware */ 263929e83d4bSgd78059 PUTRXDESC(mxfep, rmd->desc_status, RXSTAT_OWN); 264029e83d4bSgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORDEV); 264129e83d4bSgd78059 264229e83d4bSgd78059 /* advance to next RMD */ 264329e83d4bSgd78059 head = (head + 1) % MXFE_RXRING; 264429e83d4bSgd78059 } 264529e83d4bSgd78059 264629e83d4bSgd78059 mxfep->mxfe_rxhead = head; 264729e83d4bSgd78059 264877860f66SGarrett D'Amore *rxchain = mpchain; 264977860f66SGarrett D'Amore return (error); 265029e83d4bSgd78059 } 265129e83d4bSgd78059 265229e83d4bSgd78059 int 265329e83d4bSgd78059 mxfe_m_stat(void *arg, uint_t stat, uint64_t *val) 265429e83d4bSgd78059 { 265529e83d4bSgd78059 mxfe_t *mxfep = arg; 265629e83d4bSgd78059 265729e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 265829e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == MXFE_RUNNING) 265929e83d4bSgd78059 mxfe_reclaim(mxfep); 266029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 266129e83d4bSgd78059 266229e83d4bSgd78059 switch (stat) { 266329e83d4bSgd78059 case MAC_STAT_IFSPEED: 266429e83d4bSgd78059 *val = mxfep->mxfe_ifspeed; 266529e83d4bSgd78059 break; 266629e83d4bSgd78059 266729e83d4bSgd78059 case MAC_STAT_MULTIRCV: 266829e83d4bSgd78059 *val = mxfep->mxfe_multircv; 266929e83d4bSgd78059 break; 267029e83d4bSgd78059 267129e83d4bSgd78059 case MAC_STAT_BRDCSTRCV: 267229e83d4bSgd78059 *val = mxfep->mxfe_brdcstrcv; 267329e83d4bSgd78059 break; 267429e83d4bSgd78059 267529e83d4bSgd78059 case MAC_STAT_MULTIXMT: 267629e83d4bSgd78059 *val = mxfep->mxfe_multixmt; 267729e83d4bSgd78059 break; 267829e83d4bSgd78059 267929e83d4bSgd78059 case MAC_STAT_BRDCSTXMT: 268029e83d4bSgd78059 *val = mxfep->mxfe_brdcstxmt; 268129e83d4bSgd78059 break; 268229e83d4bSgd78059 268329e83d4bSgd78059 case MAC_STAT_IPACKETS: 268429e83d4bSgd78059 *val = mxfep->mxfe_ipackets; 268529e83d4bSgd78059 break; 268629e83d4bSgd78059 268729e83d4bSgd78059 case MAC_STAT_RBYTES: 268829e83d4bSgd78059 *val = mxfep->mxfe_rbytes; 268929e83d4bSgd78059 break; 269029e83d4bSgd78059 269129e83d4bSgd78059 case MAC_STAT_OPACKETS: 269229e83d4bSgd78059 *val = mxfep->mxfe_opackets; 269329e83d4bSgd78059 break; 269429e83d4bSgd78059 269529e83d4bSgd78059 case MAC_STAT_OBYTES: 269629e83d4bSgd78059 *val = mxfep->mxfe_obytes; 269729e83d4bSgd78059 break; 269829e83d4bSgd78059 269929e83d4bSgd78059 case MAC_STAT_NORCVBUF: 270029e83d4bSgd78059 *val = mxfep->mxfe_norcvbuf; 270129e83d4bSgd78059 break; 270229e83d4bSgd78059 270329e83d4bSgd78059 case MAC_STAT_NOXMTBUF: 270429e83d4bSgd78059 *val = mxfep->mxfe_noxmtbuf; 270529e83d4bSgd78059 break; 270629e83d4bSgd78059 270729e83d4bSgd78059 case MAC_STAT_COLLISIONS: 270829e83d4bSgd78059 *val = mxfep->mxfe_collisions; 270929e83d4bSgd78059 break; 271029e83d4bSgd78059 271129e83d4bSgd78059 case MAC_STAT_IERRORS: 271229e83d4bSgd78059 *val = mxfep->mxfe_errrcv; 271329e83d4bSgd78059 break; 271429e83d4bSgd78059 271529e83d4bSgd78059 case MAC_STAT_OERRORS: 271629e83d4bSgd78059 *val = mxfep->mxfe_errxmt; 271729e83d4bSgd78059 break; 271829e83d4bSgd78059 271929e83d4bSgd78059 case ETHER_STAT_LINK_DUPLEX: 272029e83d4bSgd78059 *val = mxfep->mxfe_duplex; 272129e83d4bSgd78059 break; 272229e83d4bSgd78059 272329e83d4bSgd78059 case ETHER_STAT_ALIGN_ERRORS: 272429e83d4bSgd78059 *val = mxfep->mxfe_align_errors; 272529e83d4bSgd78059 break; 272629e83d4bSgd78059 272729e83d4bSgd78059 case ETHER_STAT_FCS_ERRORS: 272829e83d4bSgd78059 *val = mxfep->mxfe_fcs_errors; 272929e83d4bSgd78059 break; 273029e83d4bSgd78059 273129e83d4bSgd78059 case ETHER_STAT_SQE_ERRORS: 273229e83d4bSgd78059 *val = mxfep->mxfe_sqe_errors; 273329e83d4bSgd78059 break; 273429e83d4bSgd78059 273529e83d4bSgd78059 case ETHER_STAT_DEFER_XMTS: 273629e83d4bSgd78059 *val = mxfep->mxfe_defer_xmts; 273729e83d4bSgd78059 break; 273829e83d4bSgd78059 273929e83d4bSgd78059 case ETHER_STAT_FIRST_COLLISIONS: 274029e83d4bSgd78059 *val = mxfep->mxfe_first_collisions; 274129e83d4bSgd78059 break; 274229e83d4bSgd78059 274329e83d4bSgd78059 case ETHER_STAT_MULTI_COLLISIONS: 274429e83d4bSgd78059 *val = mxfep->mxfe_multi_collisions; 274529e83d4bSgd78059 break; 274629e83d4bSgd78059 274729e83d4bSgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 274829e83d4bSgd78059 *val = mxfep->mxfe_tx_late_collisions; 274929e83d4bSgd78059 break; 275029e83d4bSgd78059 275129e83d4bSgd78059 case ETHER_STAT_EX_COLLISIONS: 275229e83d4bSgd78059 *val = mxfep->mxfe_ex_collisions; 275329e83d4bSgd78059 break; 275429e83d4bSgd78059 275529e83d4bSgd78059 case ETHER_STAT_MACXMT_ERRORS: 275629e83d4bSgd78059 *val = mxfep->mxfe_macxmt_errors; 275729e83d4bSgd78059 break; 275829e83d4bSgd78059 275929e83d4bSgd78059 case ETHER_STAT_CARRIER_ERRORS: 276029e83d4bSgd78059 *val = mxfep->mxfe_carrier_errors; 276129e83d4bSgd78059 break; 276229e83d4bSgd78059 276329e83d4bSgd78059 case ETHER_STAT_TOOLONG_ERRORS: 276429e83d4bSgd78059 *val = mxfep->mxfe_toolong_errors; 276529e83d4bSgd78059 break; 276629e83d4bSgd78059 276729e83d4bSgd78059 case ETHER_STAT_MACRCV_ERRORS: 276829e83d4bSgd78059 *val = mxfep->mxfe_macrcv_errors; 276929e83d4bSgd78059 break; 277029e83d4bSgd78059 277129e83d4bSgd78059 case MAC_STAT_OVERFLOWS: 277229e83d4bSgd78059 *val = mxfep->mxfe_overflow; 277329e83d4bSgd78059 break; 277429e83d4bSgd78059 277529e83d4bSgd78059 case MAC_STAT_UNDERFLOWS: 277629e83d4bSgd78059 *val = mxfep->mxfe_underflow; 277729e83d4bSgd78059 break; 277829e83d4bSgd78059 277929e83d4bSgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 278029e83d4bSgd78059 *val = mxfep->mxfe_runt; 278129e83d4bSgd78059 break; 278229e83d4bSgd78059 278329e83d4bSgd78059 case ETHER_STAT_JABBER_ERRORS: 278429e83d4bSgd78059 *val = mxfep->mxfe_jabber; 278529e83d4bSgd78059 break; 278629e83d4bSgd78059 278729e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100T4: 278829e83d4bSgd78059 *val = mxfep->mxfe_adv_100T4; 278929e83d4bSgd78059 break; 279029e83d4bSgd78059 279129e83d4bSgd78059 case ETHER_STAT_LP_CAP_100T4: 279229e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_T4) ? 1 : 0; 279329e83d4bSgd78059 break; 279429e83d4bSgd78059 279596fb08b9Sgd78059 case ETHER_STAT_CAP_100T4: 279696fb08b9Sgd78059 *val = mxfep->mxfe_cap_100T4; 279796fb08b9Sgd78059 break; 279896fb08b9Sgd78059 279929e83d4bSgd78059 case ETHER_STAT_CAP_100FDX: 280096fb08b9Sgd78059 *val = mxfep->mxfe_cap_100fdx; 280129e83d4bSgd78059 break; 280229e83d4bSgd78059 280329e83d4bSgd78059 case ETHER_STAT_CAP_100HDX: 280496fb08b9Sgd78059 *val = mxfep->mxfe_cap_100hdx; 280529e83d4bSgd78059 break; 280629e83d4bSgd78059 280729e83d4bSgd78059 case ETHER_STAT_CAP_10FDX: 280896fb08b9Sgd78059 *val = mxfep->mxfe_cap_10fdx; 280929e83d4bSgd78059 break; 281029e83d4bSgd78059 281129e83d4bSgd78059 case ETHER_STAT_CAP_10HDX: 281296fb08b9Sgd78059 *val = mxfep->mxfe_cap_10hdx; 281329e83d4bSgd78059 break; 281429e83d4bSgd78059 281529e83d4bSgd78059 case ETHER_STAT_CAP_AUTONEG: 281696fb08b9Sgd78059 *val = mxfep->mxfe_cap_aneg; 281729e83d4bSgd78059 break; 281829e83d4bSgd78059 281929e83d4bSgd78059 case ETHER_STAT_LINK_AUTONEG: 282029e83d4bSgd78059 *val = ((mxfep->mxfe_adv_aneg != 0) && 282129e83d4bSgd78059 ((mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) != 0)); 282229e83d4bSgd78059 break; 282329e83d4bSgd78059 282429e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100FDX: 282529e83d4bSgd78059 *val = mxfep->mxfe_adv_100fdx; 282629e83d4bSgd78059 break; 282729e83d4bSgd78059 282829e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100HDX: 282929e83d4bSgd78059 *val = mxfep->mxfe_adv_100hdx; 283029e83d4bSgd78059 break; 283129e83d4bSgd78059 283229e83d4bSgd78059 case ETHER_STAT_ADV_CAP_10FDX: 283329e83d4bSgd78059 *val = mxfep->mxfe_adv_10fdx; 283429e83d4bSgd78059 break; 283529e83d4bSgd78059 283629e83d4bSgd78059 case ETHER_STAT_ADV_CAP_10HDX: 283729e83d4bSgd78059 *val = mxfep->mxfe_adv_10hdx; 283829e83d4bSgd78059 break; 283929e83d4bSgd78059 284029e83d4bSgd78059 case ETHER_STAT_ADV_CAP_AUTONEG: 284129e83d4bSgd78059 *val = mxfep->mxfe_adv_aneg; 284229e83d4bSgd78059 break; 284329e83d4bSgd78059 284429e83d4bSgd78059 case ETHER_STAT_LP_CAP_100FDX: 284529e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX_FD) ? 1 : 0; 284629e83d4bSgd78059 break; 284729e83d4bSgd78059 284829e83d4bSgd78059 case ETHER_STAT_LP_CAP_100HDX: 284929e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX) ? 1 : 0; 285029e83d4bSgd78059 break; 285129e83d4bSgd78059 285229e83d4bSgd78059 case ETHER_STAT_LP_CAP_10FDX: 285329e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T_FD) ? 1 : 0; 285429e83d4bSgd78059 break; 285529e83d4bSgd78059 285629e83d4bSgd78059 case ETHER_STAT_LP_CAP_10HDX: 285729e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T) ? 1 : 0; 285829e83d4bSgd78059 break; 285929e83d4bSgd78059 286029e83d4bSgd78059 case ETHER_STAT_LP_CAP_AUTONEG: 286129e83d4bSgd78059 *val = (mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) ? 1 : 0; 286229e83d4bSgd78059 break; 286329e83d4bSgd78059 286429e83d4bSgd78059 case ETHER_STAT_XCVR_ADDR: 286529e83d4bSgd78059 *val = mxfep->mxfe_phyaddr; 286629e83d4bSgd78059 break; 286729e83d4bSgd78059 286829e83d4bSgd78059 case ETHER_STAT_XCVR_ID: 286929e83d4bSgd78059 *val = mxfep->mxfe_phyid; 287029e83d4bSgd78059 break; 287129e83d4bSgd78059 287229e83d4bSgd78059 case ETHER_STAT_XCVR_INUSE: 287329e83d4bSgd78059 *val = mxfep->mxfe_phyinuse; 287429e83d4bSgd78059 break; 287529e83d4bSgd78059 287629e83d4bSgd78059 default: 287729e83d4bSgd78059 return (ENOTSUP); 287829e83d4bSgd78059 } 287929e83d4bSgd78059 return (0); 288029e83d4bSgd78059 } 288129e83d4bSgd78059 288296fb08b9Sgd78059 /*ARGSUSED*/ 288396fb08b9Sgd78059 int 2884*0dc2366fSVenugopal Iyer mxfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 2885*0dc2366fSVenugopal Iyer void *val) 288629e83d4bSgd78059 { 288796fb08b9Sgd78059 mxfe_t *mxfep = arg; 288896fb08b9Sgd78059 int err = 0; 288929e83d4bSgd78059 289096fb08b9Sgd78059 switch (num) { 28913fd94f8cSam223141 case MAC_PROP_DUPLEX: 2892*0dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (link_duplex_t)); 2893*0dc2366fSVenugopal Iyer bcopy(&mxfep->mxfe_duplex, val, sizeof (link_duplex_t)); 289429e83d4bSgd78059 break; 289529e83d4bSgd78059 28963fd94f8cSam223141 case MAC_PROP_SPEED: 2897*0dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (uint64_t)); 289896fb08b9Sgd78059 bcopy(&mxfep->mxfe_ifspeed, val, sizeof (uint64_t)); 289929e83d4bSgd78059 break; 290096fb08b9Sgd78059 29013fd94f8cSam223141 case MAC_PROP_AUTONEG: 2902*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_aneg; 290396fb08b9Sgd78059 break; 290496fb08b9Sgd78059 29053fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 29063fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 2907*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100fdx; 290896fb08b9Sgd78059 break; 290996fb08b9Sgd78059 29103fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 29113fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 2912*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100hdx; 291396fb08b9Sgd78059 break; 291496fb08b9Sgd78059 29153fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 29163fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 2917*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_10fdx; 291896fb08b9Sgd78059 break; 291996fb08b9Sgd78059 29203fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 29213fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 2922*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_10hdx; 292396fb08b9Sgd78059 break; 292496fb08b9Sgd78059 29253fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP: 29263fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP: 2927*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100T4; 292896fb08b9Sgd78059 break; 292996fb08b9Sgd78059 293096fb08b9Sgd78059 default: 293196fb08b9Sgd78059 err = ENOTSUP; 293229e83d4bSgd78059 } 293329e83d4bSgd78059 293496fb08b9Sgd78059 return (err); 293529e83d4bSgd78059 } 293629e83d4bSgd78059 293729e83d4bSgd78059 /*ARGSUSED*/ 293829e83d4bSgd78059 int 293996fb08b9Sgd78059 mxfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 294096fb08b9Sgd78059 const void *val) 294129e83d4bSgd78059 { 294296fb08b9Sgd78059 mxfe_t *mxfep = arg; 294396fb08b9Sgd78059 uint8_t *advp; 294496fb08b9Sgd78059 uint8_t *capp; 294529e83d4bSgd78059 294696fb08b9Sgd78059 switch (num) { 29473fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 294896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100fdx; 294996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100fdx; 295096fb08b9Sgd78059 break; 295129e83d4bSgd78059 29523fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 295396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100hdx; 295496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100hdx; 295596fb08b9Sgd78059 break; 295696fb08b9Sgd78059 29573fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 295896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_10fdx; 295996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_10fdx; 296096fb08b9Sgd78059 break; 296196fb08b9Sgd78059 29623fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 296396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_10hdx; 296496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_10hdx; 296596fb08b9Sgd78059 break; 296696fb08b9Sgd78059 29673fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP: 296896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100T4; 296996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100T4; 297096fb08b9Sgd78059 break; 297196fb08b9Sgd78059 29723fd94f8cSam223141 case MAC_PROP_AUTONEG: 297396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_aneg; 297496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_aneg; 297596fb08b9Sgd78059 break; 297696fb08b9Sgd78059 297796fb08b9Sgd78059 default: 297896fb08b9Sgd78059 return (ENOTSUP); 297929e83d4bSgd78059 } 298029e83d4bSgd78059 298196fb08b9Sgd78059 if (*capp == 0) /* ensure phy can support value */ 298296fb08b9Sgd78059 return (ENOTSUP); 298329e83d4bSgd78059 298429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock); 298529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 298629e83d4bSgd78059 298796fb08b9Sgd78059 if (*advp != *(const uint8_t *)val) { 298896fb08b9Sgd78059 *advp = *(const uint8_t *)val; 298996fb08b9Sgd78059 299029e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == 299129e83d4bSgd78059 MXFE_RUNNING) { 299229e83d4bSgd78059 /* 299329e83d4bSgd78059 * This re-initializes the phy, but it also 299429e83d4bSgd78059 * restarts transmit and receive rings. 299529e83d4bSgd78059 * Needless to say, changing the link 299629e83d4bSgd78059 * parameters is destructive to traffic in 299729e83d4bSgd78059 * progress. 299829e83d4bSgd78059 */ 299929e83d4bSgd78059 mxfe_resetall(mxfep); 300029e83d4bSgd78059 } 300129e83d4bSgd78059 } 300229e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 300329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock); 300429e83d4bSgd78059 300529e83d4bSgd78059 return (0); 300629e83d4bSgd78059 } 300729e83d4bSgd78059 3008*0dc2366fSVenugopal Iyer static void 3009*0dc2366fSVenugopal Iyer mxfe_m_propinfo(void *arg, const char *name, mac_prop_id_t num, 3010*0dc2366fSVenugopal Iyer mac_prop_info_handle_t mph) 3011*0dc2366fSVenugopal Iyer { 3012*0dc2366fSVenugopal Iyer mxfe_t *mxfep = arg; 3013*0dc2366fSVenugopal Iyer 3014*0dc2366fSVenugopal Iyer _NOTE(ARGUNUSED(name)); 3015*0dc2366fSVenugopal Iyer 3016*0dc2366fSVenugopal Iyer switch (num) { 3017*0dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX: 3018*0dc2366fSVenugopal Iyer case MAC_PROP_SPEED: 3019*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP: 3020*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP: 3021*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP: 3022*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP: 3023*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP: 3024*0dc2366fSVenugopal Iyer mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ); 3025*0dc2366fSVenugopal Iyer break; 3026*0dc2366fSVenugopal Iyer 3027*0dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG: 3028*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_aneg); 3029*0dc2366fSVenugopal Iyer break; 3030*0dc2366fSVenugopal Iyer 3031*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP: 3032*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100fdx); 3033*0dc2366fSVenugopal Iyer break; 3034*0dc2366fSVenugopal Iyer 3035*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP: 3036*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100hdx); 3037*0dc2366fSVenugopal Iyer break; 3038*0dc2366fSVenugopal Iyer 3039*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP: 3040*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10fdx); 3041*0dc2366fSVenugopal Iyer break; 3042*0dc2366fSVenugopal Iyer 3043*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP: 3044*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10hdx); 3045*0dc2366fSVenugopal Iyer break; 3046*0dc2366fSVenugopal Iyer 3047*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP: 3048*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100T4); 3049*0dc2366fSVenugopal Iyer break; 3050*0dc2366fSVenugopal Iyer } 3051*0dc2366fSVenugopal Iyer } 3052*0dc2366fSVenugopal Iyer 305329e83d4bSgd78059 /* 305429e83d4bSgd78059 * Debugging and error reporting. 305529e83d4bSgd78059 */ 305629e83d4bSgd78059 void 305729e83d4bSgd78059 mxfe_error(dev_info_t *dip, char *fmt, ...) 305829e83d4bSgd78059 { 305929e83d4bSgd78059 va_list ap; 306029e83d4bSgd78059 char buf[256]; 306129e83d4bSgd78059 306229e83d4bSgd78059 va_start(ap, fmt); 306329e83d4bSgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 306429e83d4bSgd78059 va_end(ap); 306529e83d4bSgd78059 306629e83d4bSgd78059 if (dip) { 306729e83d4bSgd78059 cmn_err(CE_WARN, "%s%d: %s", 306829e83d4bSgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf); 306929e83d4bSgd78059 } else { 307029e83d4bSgd78059 cmn_err(CE_WARN, "mxfe: %s", buf); 307129e83d4bSgd78059 } 307229e83d4bSgd78059 } 307329e83d4bSgd78059 307429e83d4bSgd78059 #ifdef DEBUG 307529e83d4bSgd78059 307629e83d4bSgd78059 void 307729e83d4bSgd78059 mxfe_dprintf(mxfe_t *mxfep, const char *func, int level, char *fmt, ...) 307829e83d4bSgd78059 { 307929e83d4bSgd78059 va_list ap; 308029e83d4bSgd78059 308129e83d4bSgd78059 va_start(ap, fmt); 308229e83d4bSgd78059 if (mxfe_debug & level) { 308329e83d4bSgd78059 char tag[64]; 308429e83d4bSgd78059 char buf[256]; 308529e83d4bSgd78059 308629e83d4bSgd78059 if (mxfep && mxfep->mxfe_dip) { 308729e83d4bSgd78059 (void) snprintf(tag, sizeof (tag), 308829e83d4bSgd78059 "%s%d", ddi_driver_name(mxfep->mxfe_dip), 308929e83d4bSgd78059 ddi_get_instance(mxfep->mxfe_dip)); 309029e83d4bSgd78059 } else { 309129e83d4bSgd78059 (void) snprintf(tag, sizeof (tag), "mxfe"); 309229e83d4bSgd78059 } 309329e83d4bSgd78059 309429e83d4bSgd78059 (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", tag, 309529e83d4bSgd78059 func, fmt); 309629e83d4bSgd78059 309729e83d4bSgd78059 vcmn_err(CE_CONT, buf, ap); 309829e83d4bSgd78059 } 309929e83d4bSgd78059 va_end(ap); 310029e83d4bSgd78059 } 310129e83d4bSgd78059 310229e83d4bSgd78059 #endif 3103