1*1959748cSgd78059 /* 2*1959748cSgd78059 * Solaris driver for ethernet cards based on the ADMtek Centaur 3*1959748cSgd78059 * 4*1959748cSgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>. 5*1959748cSgd78059 * All rights reserved. 6*1959748cSgd78059 * 7*1959748cSgd78059 * Redistribution and use in source and binary forms, with or without 8*1959748cSgd78059 * modification, are permitted provided that the following conditions 9*1959748cSgd78059 * are met: 10*1959748cSgd78059 * 1. Redistributions of source code must retain the above copyright 11*1959748cSgd78059 * notice, this list of conditions and the following disclaimer. 12*1959748cSgd78059 * 2. Redistributions in binary form must reproduce the above copyright 13*1959748cSgd78059 * notice, this list of conditions and the following disclaimer in the 14*1959748cSgd78059 * documentation and/or other materials provided with the distribution. 15*1959748cSgd78059 * 3. Neither the name of the author nor the names of any co-contributors 16*1959748cSgd78059 * may be used to endorse or promote products derived from this software 17*1959748cSgd78059 * without specific prior written permission. 18*1959748cSgd78059 * 19*1959748cSgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' 20*1959748cSgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*1959748cSgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*1959748cSgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23*1959748cSgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*1959748cSgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*1959748cSgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*1959748cSgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*1959748cSgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*1959748cSgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*1959748cSgd78059 * POSSIBILITY OF SUCH DAMAGE. 30*1959748cSgd78059 */ 31*1959748cSgd78059 32*1959748cSgd78059 #pragma ident "%Z%%M% %I% %E% SMI" 33*1959748cSgd78059 34*1959748cSgd78059 #include <sys/varargs.h> 35*1959748cSgd78059 #include <sys/types.h> 36*1959748cSgd78059 #include <sys/modctl.h> 37*1959748cSgd78059 #include <sys/conf.h> 38*1959748cSgd78059 #include <sys/devops.h> 39*1959748cSgd78059 #include <sys/stream.h> 40*1959748cSgd78059 #include <sys/strsun.h> 41*1959748cSgd78059 #include <sys/priv.h> 42*1959748cSgd78059 #include <sys/policy.h> 43*1959748cSgd78059 #include <sys/cred.h> 44*1959748cSgd78059 #include <sys/cmn_err.h> 45*1959748cSgd78059 #include <sys/dlpi.h> 46*1959748cSgd78059 #include <sys/ethernet.h> 47*1959748cSgd78059 #include <sys/kmem.h> 48*1959748cSgd78059 #include <sys/time.h> 49*1959748cSgd78059 #include <sys/crc32.h> 50*1959748cSgd78059 #include <sys/miiregs.h> 51*1959748cSgd78059 #include <sys/mac.h> 52*1959748cSgd78059 #include <sys/mac_ether.h> 53*1959748cSgd78059 #include <sys/ddi.h> 54*1959748cSgd78059 #include <sys/sunddi.h> 55*1959748cSgd78059 56*1959748cSgd78059 #include "afe.h" 57*1959748cSgd78059 #include "afeimpl.h" 58*1959748cSgd78059 59*1959748cSgd78059 /* 60*1959748cSgd78059 * Driver globals. 61*1959748cSgd78059 */ 62*1959748cSgd78059 63*1959748cSgd78059 /* patchable debug flag ... must not be static! */ 64*1959748cSgd78059 #ifdef DEBUG 65*1959748cSgd78059 unsigned afe_debug = DWARN; 66*1959748cSgd78059 #endif 67*1959748cSgd78059 68*1959748cSgd78059 /* table of supported devices */ 69*1959748cSgd78059 static afe_card_t afe_cards[] = { 70*1959748cSgd78059 71*1959748cSgd78059 /* 72*1959748cSgd78059 * ADMtek Centaur and Comet 73*1959748cSgd78059 */ 74*1959748cSgd78059 { 0x1317, 0x0981, "ADMtek AL981", MODEL_COMET }, 75*1959748cSgd78059 { 0x1317, 0x0985, "ADMtek AN983", MODEL_CENTAUR }, 76*1959748cSgd78059 { 0x1317, 0x1985, "ADMtek AN985", MODEL_CENTAUR }, 77*1959748cSgd78059 { 0x1317, 0x9511, "ADMtek ADM9511", MODEL_CENTAUR }, 78*1959748cSgd78059 { 0x1317, 0x9513, "ADMtek ADM9513", MODEL_CENTAUR }, 79*1959748cSgd78059 /* 80*1959748cSgd78059 * Accton just relabels other companies' controllers 81*1959748cSgd78059 */ 82*1959748cSgd78059 { 0x1113, 0x1216, "Accton EN5251", MODEL_CENTAUR }, 83*1959748cSgd78059 /* 84*1959748cSgd78059 * Models listed here. 85*1959748cSgd78059 */ 86*1959748cSgd78059 { 0x10b7, 0x9300, "3Com 3CSOHO100B-TX", MODEL_CENTAUR }, 87*1959748cSgd78059 { 0x1113, 0xec02, "SMC SMC1244TX", MODEL_CENTAUR }, 88*1959748cSgd78059 { 0x10b8, 0x1255, "SMC SMC1255TX", MODEL_CENTAUR }, 89*1959748cSgd78059 { 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR }, 90*1959748cSgd78059 { 0x1113, 0x1207, "Accton EN1207F", MODEL_CENTAUR }, 91*1959748cSgd78059 { 0x1113, 0x2242, "Accton EN2242", MODEL_CENTAUR }, 92*1959748cSgd78059 { 0x1113, 0x2220, "Accton EN2220", MODEL_CENTAUR }, 93*1959748cSgd78059 { 0x1113, 0x9216, "3M VOL-N100VF+TX", MODEL_CENTAUR }, 94*1959748cSgd78059 { 0x1317, 0x0574, "Linksys LNE100TX", MODEL_CENTAUR }, 95*1959748cSgd78059 { 0x1317, 0x0570, "Linksys NC100", MODEL_CENTAUR }, 96*1959748cSgd78059 { 0x1385, 0x511a, "Netgear FA511", MODEL_CENTAUR }, 97*1959748cSgd78059 { 0x13d1, 0xab02, "AboCom FE2500", MODEL_CENTAUR }, 98*1959748cSgd78059 { 0x13d1, 0xab03, "AboCom PCM200", MODEL_CENTAUR }, 99*1959748cSgd78059 { 0x13d1, 0xab08, "AboCom FE2500MX", MODEL_CENTAUR }, 100*1959748cSgd78059 { 0x1414, 0x0001, "Microsoft MN-120", MODEL_CENTAUR }, 101*1959748cSgd78059 { 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR }, 102*1959748cSgd78059 { 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR }, 103*1959748cSgd78059 { 0x1737, 0xab08, "Linksys PCMPC200", MODEL_CENTAUR }, 104*1959748cSgd78059 { 0x1737, 0xab09, "Linksys PCM200", MODEL_CENTAUR }, 105*1959748cSgd78059 { 0x17b3, 0xab08, "Hawking PN672TX", MODEL_CENTAUR }, 106*1959748cSgd78059 }; 107*1959748cSgd78059 108*1959748cSgd78059 #define ETHERVLANMTU (ETHERMAX + 4) 109*1959748cSgd78059 110*1959748cSgd78059 /* 111*1959748cSgd78059 * Function prototypes 112*1959748cSgd78059 */ 113*1959748cSgd78059 static int afe_attach(dev_info_t *, ddi_attach_cmd_t); 114*1959748cSgd78059 static int afe_detach(dev_info_t *, ddi_detach_cmd_t); 115*1959748cSgd78059 static int afe_resume(dev_info_t *); 116*1959748cSgd78059 static int afe_m_unicst(void *, const uint8_t *); 117*1959748cSgd78059 static int afe_m_multicst(void *, boolean_t, const uint8_t *); 118*1959748cSgd78059 static int afe_m_promisc(void *, boolean_t); 119*1959748cSgd78059 static mblk_t *afe_m_tx(void *, mblk_t *); 120*1959748cSgd78059 static int afe_m_stat(void *, uint_t, uint64_t *); 121*1959748cSgd78059 static int afe_m_start(void *); 122*1959748cSgd78059 static void afe_m_stop(void *); 123*1959748cSgd78059 static void afe_m_ioctl(void *, queue_t *, mblk_t *); 124*1959748cSgd78059 static unsigned afe_intr(caddr_t); 125*1959748cSgd78059 static void afe_startmac(afe_t *); 126*1959748cSgd78059 static void afe_stopmac(afe_t *); 127*1959748cSgd78059 static void afe_resetrings(afe_t *); 128*1959748cSgd78059 static boolean_t afe_initialize(afe_t *); 129*1959748cSgd78059 static void afe_startall(afe_t *); 130*1959748cSgd78059 static void afe_stopall(afe_t *); 131*1959748cSgd78059 static void afe_resetall(afe_t *); 132*1959748cSgd78059 static afe_txbuf_t *afe_alloctxbuf(afe_t *); 133*1959748cSgd78059 static void afe_destroytxbuf(afe_txbuf_t *); 134*1959748cSgd78059 static afe_rxbuf_t *afe_allocrxbuf(afe_t *); 135*1959748cSgd78059 static void afe_destroyrxbuf(afe_rxbuf_t *); 136*1959748cSgd78059 static boolean_t afe_send(afe_t *, mblk_t *); 137*1959748cSgd78059 static int afe_allocrxring(afe_t *); 138*1959748cSgd78059 static void afe_freerxring(afe_t *); 139*1959748cSgd78059 static int afe_alloctxring(afe_t *); 140*1959748cSgd78059 static void afe_freetxring(afe_t *); 141*1959748cSgd78059 static void afe_error(dev_info_t *, char *, ...); 142*1959748cSgd78059 static void afe_setrxfilt(afe_t *); 143*1959748cSgd78059 static uint8_t afe_sromwidth(afe_t *); 144*1959748cSgd78059 static uint16_t afe_readsromword(afe_t *, unsigned); 145*1959748cSgd78059 static void afe_readsrom(afe_t *, unsigned, unsigned, char *); 146*1959748cSgd78059 static void afe_getfactaddr(afe_t *, uchar_t *); 147*1959748cSgd78059 static int afe_miireadbit(afe_t *); 148*1959748cSgd78059 static void afe_miiwritebit(afe_t *, int); 149*1959748cSgd78059 static void afe_miitristate(afe_t *); 150*1959748cSgd78059 static unsigned afe_miiread(afe_t *, int, int); 151*1959748cSgd78059 static void afe_miiwrite(afe_t *, int, int, uint16_t); 152*1959748cSgd78059 static unsigned afe_miireadgeneral(afe_t *, int, int); 153*1959748cSgd78059 static void afe_miiwritegeneral(afe_t *, int, int, uint16_t); 154*1959748cSgd78059 static unsigned afe_miireadcomet(afe_t *, int, int); 155*1959748cSgd78059 static void afe_miiwritecomet(afe_t *, int, int, uint16_t); 156*1959748cSgd78059 static int afe_getmiibit(afe_t *, uint16_t, uint16_t); 157*1959748cSgd78059 static void afe_startphy(afe_t *); 158*1959748cSgd78059 static void afe_stopphy(afe_t *); 159*1959748cSgd78059 static void afe_reportlink(afe_t *); 160*1959748cSgd78059 static void afe_checklink(afe_t *); 161*1959748cSgd78059 static void afe_checklinkcomet(afe_t *); 162*1959748cSgd78059 static void afe_checklinkcentaur(afe_t *); 163*1959748cSgd78059 static void afe_checklinkmii(afe_t *); 164*1959748cSgd78059 static void afe_disableinterrupts(afe_t *); 165*1959748cSgd78059 static void afe_enableinterrupts(afe_t *); 166*1959748cSgd78059 static void afe_reclaim(afe_t *); 167*1959748cSgd78059 static mblk_t *afe_receive(afe_t *); 168*1959748cSgd78059 static int afe_ndaddbytes(mblk_t *, char *, int); 169*1959748cSgd78059 static int afe_ndaddstr(mblk_t *, char *, int); 170*1959748cSgd78059 static void afe_ndparsestring(mblk_t *, char *, int); 171*1959748cSgd78059 static int afe_ndparselen(mblk_t *); 172*1959748cSgd78059 static int afe_ndparseint(mblk_t *); 173*1959748cSgd78059 static void afe_ndget(afe_t *, queue_t *, mblk_t *); 174*1959748cSgd78059 static void afe_ndset(afe_t *, queue_t *, mblk_t *); 175*1959748cSgd78059 static void afe_ndfini(afe_t *); 176*1959748cSgd78059 static void afe_ndinit(afe_t *); 177*1959748cSgd78059 static int afe_ndquestion(afe_t *, mblk_t *, afe_nd_t *); 178*1959748cSgd78059 static int afe_ndgetint(afe_t *, mblk_t *, afe_nd_t *); 179*1959748cSgd78059 static int afe_ndgetmiibit(afe_t *, mblk_t *, afe_nd_t *); 180*1959748cSgd78059 static int afe_ndsetadv(afe_t *, mblk_t *, afe_nd_t *); 181*1959748cSgd78059 static afe_nd_t *afe_ndfind(afe_t *, char *); 182*1959748cSgd78059 static void afe_ndempty(mblk_t *); 183*1959748cSgd78059 static void afe_ndadd(afe_t *, char *, afe_nd_pf_t, afe_nd_pf_t, 184*1959748cSgd78059 intptr_t, intptr_t); 185*1959748cSgd78059 186*1959748cSgd78059 #ifdef DEBUG 187*1959748cSgd78059 static void afe_dprintf(afe_t *, const char *, int, char *, ...); 188*1959748cSgd78059 #endif 189*1959748cSgd78059 190*1959748cSgd78059 #define KIOIP KSTAT_INTR_PTR(afep->afe_intrstat) 191*1959748cSgd78059 192*1959748cSgd78059 static mac_callbacks_t afe_m_callbacks = { 193*1959748cSgd78059 MC_IOCTL, 194*1959748cSgd78059 afe_m_stat, 195*1959748cSgd78059 afe_m_start, 196*1959748cSgd78059 afe_m_stop, 197*1959748cSgd78059 afe_m_promisc, 198*1959748cSgd78059 afe_m_multicst, 199*1959748cSgd78059 afe_m_unicst, 200*1959748cSgd78059 afe_m_tx, 201*1959748cSgd78059 NULL, 202*1959748cSgd78059 afe_m_ioctl, 203*1959748cSgd78059 NULL, /* m_getcapab */ 204*1959748cSgd78059 }; 205*1959748cSgd78059 206*1959748cSgd78059 207*1959748cSgd78059 /* 208*1959748cSgd78059 * Stream information 209*1959748cSgd78059 */ 210*1959748cSgd78059 DDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach, 211*1959748cSgd78059 nodev, NULL, D_MP, NULL); 212*1959748cSgd78059 213*1959748cSgd78059 /* 214*1959748cSgd78059 * Module linkage information. 215*1959748cSgd78059 */ 216*1959748cSgd78059 217*1959748cSgd78059 static struct modldrv afe_modldrv = { 218*1959748cSgd78059 &mod_driverops, /* drv_modops */ 219*1959748cSgd78059 "ADMtek Fast Ethernet", /* drv_linkinfo */ 220*1959748cSgd78059 &afe_devops /* drv_dev_ops */ 221*1959748cSgd78059 }; 222*1959748cSgd78059 223*1959748cSgd78059 static struct modlinkage afe_modlinkage = { 224*1959748cSgd78059 MODREV_1, /* ml_rev */ 225*1959748cSgd78059 { &afe_modldrv, NULL } /* ml_linkage */ 226*1959748cSgd78059 }; 227*1959748cSgd78059 228*1959748cSgd78059 /* 229*1959748cSgd78059 * Device attributes. 230*1959748cSgd78059 */ 231*1959748cSgd78059 static ddi_device_acc_attr_t afe_devattr = { 232*1959748cSgd78059 DDI_DEVICE_ATTR_V0, 233*1959748cSgd78059 DDI_STRUCTURE_LE_ACC, 234*1959748cSgd78059 DDI_STRICTORDER_ACC 235*1959748cSgd78059 }; 236*1959748cSgd78059 237*1959748cSgd78059 static ddi_device_acc_attr_t afe_bufattr = { 238*1959748cSgd78059 DDI_DEVICE_ATTR_V0, 239*1959748cSgd78059 DDI_NEVERSWAP_ACC, 240*1959748cSgd78059 DDI_STRICTORDER_ACC 241*1959748cSgd78059 }; 242*1959748cSgd78059 243*1959748cSgd78059 static ddi_dma_attr_t afe_dma_attr = { 244*1959748cSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 245*1959748cSgd78059 0, /* dma_attr_addr_lo */ 246*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 247*1959748cSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 248*1959748cSgd78059 4, /* dma_attr_align */ 249*1959748cSgd78059 0x3F, /* dma_attr_burstsizes */ 250*1959748cSgd78059 1, /* dma_attr_minxfer */ 251*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 252*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 253*1959748cSgd78059 1, /* dma_attr_sgllen */ 254*1959748cSgd78059 1, /* dma_attr_granular */ 255*1959748cSgd78059 0 /* dma_attr_flags */ 256*1959748cSgd78059 }; 257*1959748cSgd78059 258*1959748cSgd78059 /* 259*1959748cSgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can 260*1959748cSgd78059 * cross a page boundary, so we use the two buffer addresses of the 261*1959748cSgd78059 * chip to provide a two-entry scatter-gather list. 262*1959748cSgd78059 */ 263*1959748cSgd78059 static ddi_dma_attr_t afe_dma_txattr = { 264*1959748cSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 265*1959748cSgd78059 0, /* dma_attr_addr_lo */ 266*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 267*1959748cSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 268*1959748cSgd78059 1, /* dma_attr_align */ 269*1959748cSgd78059 0x3F, /* dma_attr_burstsizes */ 270*1959748cSgd78059 1, /* dma_attr_minxfer */ 271*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 272*1959748cSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 273*1959748cSgd78059 2, /* dma_attr_sgllen */ 274*1959748cSgd78059 1, /* dma_attr_granular */ 275*1959748cSgd78059 0 /* dma_attr_flags */ 276*1959748cSgd78059 }; 277*1959748cSgd78059 278*1959748cSgd78059 /* 279*1959748cSgd78059 * Ethernet addresses. 280*1959748cSgd78059 */ 281*1959748cSgd78059 static uchar_t afe_broadcast[ETHERADDRL] = { 282*1959748cSgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 283*1959748cSgd78059 }; 284*1959748cSgd78059 285*1959748cSgd78059 /* 286*1959748cSgd78059 * DDI entry points. 287*1959748cSgd78059 */ 288*1959748cSgd78059 int 289*1959748cSgd78059 _init(void) 290*1959748cSgd78059 { 291*1959748cSgd78059 int rv; 292*1959748cSgd78059 mac_init_ops(&afe_devops, "afe"); 293*1959748cSgd78059 if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) { 294*1959748cSgd78059 mac_fini_ops(&afe_devops); 295*1959748cSgd78059 } 296*1959748cSgd78059 return (rv); 297*1959748cSgd78059 } 298*1959748cSgd78059 299*1959748cSgd78059 int 300*1959748cSgd78059 _fini(void) 301*1959748cSgd78059 { 302*1959748cSgd78059 int rv; 303*1959748cSgd78059 if ((rv = mod_remove(&afe_modlinkage)) == DDI_SUCCESS) { 304*1959748cSgd78059 mac_fini_ops(&afe_devops); 305*1959748cSgd78059 } 306*1959748cSgd78059 return (rv); 307*1959748cSgd78059 } 308*1959748cSgd78059 309*1959748cSgd78059 int 310*1959748cSgd78059 _info(struct modinfo *modinfop) 311*1959748cSgd78059 { 312*1959748cSgd78059 return (mod_info(&afe_modlinkage, modinfop)); 313*1959748cSgd78059 } 314*1959748cSgd78059 315*1959748cSgd78059 int 316*1959748cSgd78059 afe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 317*1959748cSgd78059 { 318*1959748cSgd78059 afe_t *afep; 319*1959748cSgd78059 mac_register_t *macp; 320*1959748cSgd78059 int inst = ddi_get_instance(dip); 321*1959748cSgd78059 ddi_acc_handle_t pci; 322*1959748cSgd78059 uint16_t venid; 323*1959748cSgd78059 uint16_t devid; 324*1959748cSgd78059 uint16_t svid; 325*1959748cSgd78059 uint16_t ssid; 326*1959748cSgd78059 uint16_t cachesize; 327*1959748cSgd78059 afe_card_t *cardp; 328*1959748cSgd78059 int i; 329*1959748cSgd78059 330*1959748cSgd78059 switch (cmd) { 331*1959748cSgd78059 case DDI_RESUME: 332*1959748cSgd78059 return (afe_resume(dip)); 333*1959748cSgd78059 334*1959748cSgd78059 case DDI_ATTACH: 335*1959748cSgd78059 break; 336*1959748cSgd78059 337*1959748cSgd78059 default: 338*1959748cSgd78059 return (DDI_FAILURE); 339*1959748cSgd78059 } 340*1959748cSgd78059 341*1959748cSgd78059 /* this card is a bus master, reject any slave-only slot */ 342*1959748cSgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) { 343*1959748cSgd78059 afe_error(dip, "slot does not support PCI bus-master"); 344*1959748cSgd78059 return (DDI_FAILURE); 345*1959748cSgd78059 } 346*1959748cSgd78059 /* PCI devices shouldn't generate hilevel interrupts */ 347*1959748cSgd78059 if (ddi_intr_hilevel(dip, 0) != 0) { 348*1959748cSgd78059 afe_error(dip, "hilevel interrupts not supported"); 349*1959748cSgd78059 return (DDI_FAILURE); 350*1959748cSgd78059 } 351*1959748cSgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 352*1959748cSgd78059 afe_error(dip, "unable to setup PCI config handle"); 353*1959748cSgd78059 return (DDI_FAILURE); 354*1959748cSgd78059 } 355*1959748cSgd78059 356*1959748cSgd78059 venid = pci_config_get16(pci, PCI_VID); 357*1959748cSgd78059 devid = pci_config_get16(pci, PCI_DID); 358*1959748cSgd78059 svid = pci_config_get16(pci, PCI_SVID); 359*1959748cSgd78059 ssid = pci_config_get16(pci, PCI_SSID); 360*1959748cSgd78059 361*1959748cSgd78059 /* 362*1959748cSgd78059 * Note: ADMtek boards seem to misprogram themselves with bogus 363*1959748cSgd78059 * timings, which do not seem to work properly on SPARC. We 364*1959748cSgd78059 * reprogram them zero (but only if they appear to be broken), 365*1959748cSgd78059 * which seems to at least work. Its unclear that this is a 366*1959748cSgd78059 * legal or wise practice to me, but it certainly works better 367*1959748cSgd78059 * than the original values. (I would love to hear 368*1959748cSgd78059 * suggestions for better values, or a better strategy.) 369*1959748cSgd78059 */ 370*1959748cSgd78059 if ((pci_config_get8(pci, PCI_MINGNT) == 0xff) && 371*1959748cSgd78059 (pci_config_get8(pci, PCI_MAXLAT) == 0xff)) { 372*1959748cSgd78059 pci_config_put8(pci, PCI_MINGNT, 0); 373*1959748cSgd78059 pci_config_put8(pci, PCI_MAXLAT, 0); 374*1959748cSgd78059 } 375*1959748cSgd78059 376*1959748cSgd78059 /* 377*1959748cSgd78059 * the last entry in the card table matches every possible 378*1959748cSgd78059 * card, so the for-loop always terminates properly. 379*1959748cSgd78059 */ 380*1959748cSgd78059 cardp = NULL; 381*1959748cSgd78059 for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) { 382*1959748cSgd78059 if ((venid == afe_cards[i].card_venid) && 383*1959748cSgd78059 (devid == afe_cards[i].card_devid)) { 384*1959748cSgd78059 cardp = &afe_cards[i]; 385*1959748cSgd78059 } 386*1959748cSgd78059 if ((svid == afe_cards[i].card_venid) && 387*1959748cSgd78059 (ssid == afe_cards[i].card_devid)) { 388*1959748cSgd78059 cardp = &afe_cards[i]; 389*1959748cSgd78059 break; 390*1959748cSgd78059 } 391*1959748cSgd78059 } 392*1959748cSgd78059 393*1959748cSgd78059 if (cardp == NULL) { 394*1959748cSgd78059 pci_config_teardown(&pci); 395*1959748cSgd78059 afe_error(dip, "Unable to identify PCI card"); 396*1959748cSgd78059 return (DDI_FAILURE); 397*1959748cSgd78059 } 398*1959748cSgd78059 399*1959748cSgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model", 400*1959748cSgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) { 401*1959748cSgd78059 pci_config_teardown(&pci); 402*1959748cSgd78059 afe_error(dip, "Unable to create model property"); 403*1959748cSgd78059 return (DDI_FAILURE); 404*1959748cSgd78059 } 405*1959748cSgd78059 406*1959748cSgd78059 /* 407*1959748cSgd78059 * Grab the PCI cachesize -- we use this to program the 408*1959748cSgd78059 * cache-optimization bus access bits. 409*1959748cSgd78059 */ 410*1959748cSgd78059 cachesize = pci_config_get8(pci, PCI_CLS); 411*1959748cSgd78059 412*1959748cSgd78059 /* this cannot fail */ 413*1959748cSgd78059 afep = kmem_zalloc(sizeof (afe_t), KM_SLEEP); 414*1959748cSgd78059 ddi_set_driver_private(dip, afep); 415*1959748cSgd78059 416*1959748cSgd78059 /* get the interrupt block cookie */ 417*1959748cSgd78059 if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) { 418*1959748cSgd78059 afe_error(dip, "ddi_get_iblock_cookie failed"); 419*1959748cSgd78059 pci_config_teardown(&pci); 420*1959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 421*1959748cSgd78059 return (DDI_FAILURE); 422*1959748cSgd78059 } 423*1959748cSgd78059 424*1959748cSgd78059 afep->afe_dip = dip; 425*1959748cSgd78059 afep->afe_cardp = cardp; 426*1959748cSgd78059 afep->afe_phyaddr = -1; 427*1959748cSgd78059 afep->afe_cachesize = cachesize; 428*1959748cSgd78059 429*1959748cSgd78059 /* default properties */ 430*1959748cSgd78059 afep->afe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 431*1959748cSgd78059 "adv_autoneg_cap", 1); 432*1959748cSgd78059 afep->afe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 433*1959748cSgd78059 "adv_100T4_cap", 1); 434*1959748cSgd78059 afep->afe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 435*1959748cSgd78059 "adv_100fdx_cap", 1); 436*1959748cSgd78059 afep->afe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 437*1959748cSgd78059 "adv_100hdx_cap", 1); 438*1959748cSgd78059 afep->afe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 439*1959748cSgd78059 "adv_10fdx_cap", 1); 440*1959748cSgd78059 afep->afe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 441*1959748cSgd78059 "adv_10hdx_cap", 1); 442*1959748cSgd78059 443*1959748cSgd78059 afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 444*1959748cSgd78059 "fiber", 0); 445*1959748cSgd78059 446*1959748cSgd78059 DBG(DPCI, "PCI vendor id = %x", venid); 447*1959748cSgd78059 DBG(DPCI, "PCI device id = %x", devid); 448*1959748cSgd78059 DBG(DPCI, "PCI cachesize = %d", cachesize); 449*1959748cSgd78059 DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD)); 450*1959748cSgd78059 DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT)); 451*1959748cSgd78059 452*1959748cSgd78059 mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie); 453*1959748cSgd78059 mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie); 454*1959748cSgd78059 455*1959748cSgd78059 afe_ndinit(afep); 456*1959748cSgd78059 457*1959748cSgd78059 /* 458*1959748cSgd78059 * Enable bus master, IO space, and memory space accesses. 459*1959748cSgd78059 */ 460*1959748cSgd78059 pci_config_put16(pci, PCI_CMD, 461*1959748cSgd78059 pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE); 462*1959748cSgd78059 463*1959748cSgd78059 /* we're done with this now, drop it */ 464*1959748cSgd78059 pci_config_teardown(&pci); 465*1959748cSgd78059 466*1959748cSgd78059 /* 467*1959748cSgd78059 * Initialize interrupt kstat. This should not normally fail, since 468*1959748cSgd78059 * we don't use a persistent stat. We do it this way to avoid having 469*1959748cSgd78059 * to test for it at run time on the hot path. 470*1959748cSgd78059 */ 471*1959748cSgd78059 afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller", 472*1959748cSgd78059 KSTAT_TYPE_INTR, 1, 0); 473*1959748cSgd78059 if (afep->afe_intrstat == NULL) { 474*1959748cSgd78059 afe_error(dip, "kstat_create failed"); 475*1959748cSgd78059 goto failed; 476*1959748cSgd78059 } 477*1959748cSgd78059 kstat_install(afep->afe_intrstat); 478*1959748cSgd78059 479*1959748cSgd78059 /* 480*1959748cSgd78059 * Map in the device registers. 481*1959748cSgd78059 */ 482*1959748cSgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs, 483*1959748cSgd78059 0, 0, &afe_devattr, &afep->afe_regshandle)) { 484*1959748cSgd78059 afe_error(dip, "ddi_regs_map_setup failed"); 485*1959748cSgd78059 goto failed; 486*1959748cSgd78059 } 487*1959748cSgd78059 488*1959748cSgd78059 /* 489*1959748cSgd78059 * Allocate DMA resources (descriptor rings and buffers). 490*1959748cSgd78059 */ 491*1959748cSgd78059 if ((afe_allocrxring(afep) != DDI_SUCCESS) || 492*1959748cSgd78059 (afe_alloctxring(afep) != DDI_SUCCESS)) { 493*1959748cSgd78059 afe_error(dip, "unable to allocate DMA resources"); 494*1959748cSgd78059 goto failed; 495*1959748cSgd78059 } 496*1959748cSgd78059 497*1959748cSgd78059 /* Initialize the chip. */ 498*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 499*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 500*1959748cSgd78059 if (!afe_initialize(afep)) { 501*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 502*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 503*1959748cSgd78059 goto failed; 504*1959748cSgd78059 } 505*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 506*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 507*1959748cSgd78059 508*1959748cSgd78059 /* Determine the number of address bits to our EEPROM. */ 509*1959748cSgd78059 afep->afe_sromwidth = afe_sromwidth(afep); 510*1959748cSgd78059 511*1959748cSgd78059 /* 512*1959748cSgd78059 * Get the factory ethernet address. This becomes the current 513*1959748cSgd78059 * ethernet address (it can be overridden later via ifconfig). 514*1959748cSgd78059 */ 515*1959748cSgd78059 afe_getfactaddr(afep, afep->afe_curraddr); 516*1959748cSgd78059 afep->afe_promisc = B_FALSE; 517*1959748cSgd78059 518*1959748cSgd78059 /* make sure we add configure the initial filter */ 519*1959748cSgd78059 (void) afe_m_unicst(afep, afep->afe_curraddr); 520*1959748cSgd78059 (void) afe_m_multicst(afep, B_TRUE, afe_broadcast); 521*1959748cSgd78059 522*1959748cSgd78059 /* 523*1959748cSgd78059 * Establish interrupt handler. 524*1959748cSgd78059 */ 525*1959748cSgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) != 526*1959748cSgd78059 DDI_SUCCESS) { 527*1959748cSgd78059 afe_error(dip, "unable to add interrupt"); 528*1959748cSgd78059 goto failed; 529*1959748cSgd78059 } 530*1959748cSgd78059 531*1959748cSgd78059 /* TODO: do the power management stuff */ 532*1959748cSgd78059 533*1959748cSgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 534*1959748cSgd78059 afe_error(dip, "mac_alloc failed"); 535*1959748cSgd78059 goto failed; 536*1959748cSgd78059 } 537*1959748cSgd78059 538*1959748cSgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 539*1959748cSgd78059 macp->m_driver = afep; 540*1959748cSgd78059 macp->m_dip = dip; 541*1959748cSgd78059 macp->m_src_addr = afep->afe_curraddr; 542*1959748cSgd78059 macp->m_callbacks = &afe_m_callbacks; 543*1959748cSgd78059 macp->m_min_sdu = 0; 544*1959748cSgd78059 macp->m_max_sdu = ETHERMTU; 545*1959748cSgd78059 546*1959748cSgd78059 if (mac_register(macp, &afep->afe_mh) == DDI_SUCCESS) { 547*1959748cSgd78059 mac_free(macp); 548*1959748cSgd78059 return (DDI_SUCCESS); 549*1959748cSgd78059 } 550*1959748cSgd78059 551*1959748cSgd78059 /* failed to register with MAC */ 552*1959748cSgd78059 mac_free(macp); 553*1959748cSgd78059 failed: 554*1959748cSgd78059 if (afep->afe_icookie != NULL) { 555*1959748cSgd78059 ddi_remove_intr(dip, 0, afep->afe_icookie); 556*1959748cSgd78059 } 557*1959748cSgd78059 if (afep->afe_intrstat) { 558*1959748cSgd78059 kstat_delete(afep->afe_intrstat); 559*1959748cSgd78059 } 560*1959748cSgd78059 afe_ndfini(afep); 561*1959748cSgd78059 mutex_destroy(&afep->afe_intrlock); 562*1959748cSgd78059 mutex_destroy(&afep->afe_xmtlock); 563*1959748cSgd78059 564*1959748cSgd78059 afe_freerxring(afep); 565*1959748cSgd78059 afe_freetxring(afep); 566*1959748cSgd78059 567*1959748cSgd78059 if (afep->afe_regshandle != NULL) { 568*1959748cSgd78059 ddi_regs_map_free(&afep->afe_regshandle); 569*1959748cSgd78059 } 570*1959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 571*1959748cSgd78059 return (DDI_FAILURE); 572*1959748cSgd78059 } 573*1959748cSgd78059 574*1959748cSgd78059 int 575*1959748cSgd78059 afe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 576*1959748cSgd78059 { 577*1959748cSgd78059 afe_t *afep; 578*1959748cSgd78059 579*1959748cSgd78059 afep = ddi_get_driver_private(dip); 580*1959748cSgd78059 if (afep == NULL) { 581*1959748cSgd78059 afe_error(dip, "no soft state in detach!"); 582*1959748cSgd78059 return (DDI_FAILURE); 583*1959748cSgd78059 } 584*1959748cSgd78059 585*1959748cSgd78059 switch (cmd) { 586*1959748cSgd78059 case DDI_DETACH: 587*1959748cSgd78059 588*1959748cSgd78059 if (mac_unregister(afep->afe_mh) != 0) { 589*1959748cSgd78059 return (DDI_FAILURE); 590*1959748cSgd78059 } 591*1959748cSgd78059 592*1959748cSgd78059 /* make sure hardware is quiesced */ 593*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 594*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 595*1959748cSgd78059 afep->afe_flags &= ~AFE_RUNNING; 596*1959748cSgd78059 afe_stopall(afep); 597*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 598*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 599*1959748cSgd78059 600*1959748cSgd78059 /* clean up and shut down device */ 601*1959748cSgd78059 ddi_remove_intr(dip, 0, afep->afe_icookie); 602*1959748cSgd78059 603*1959748cSgd78059 /* clean up kstats */ 604*1959748cSgd78059 kstat_delete(afep->afe_intrstat); 605*1959748cSgd78059 606*1959748cSgd78059 ddi_prop_remove_all(dip); 607*1959748cSgd78059 608*1959748cSgd78059 /* free up any left over buffers or DMA resources */ 609*1959748cSgd78059 afe_freerxring(afep); 610*1959748cSgd78059 afe_freetxring(afep); 611*1959748cSgd78059 612*1959748cSgd78059 afe_ndfini(afep); 613*1959748cSgd78059 ddi_regs_map_free(&afep->afe_regshandle); 614*1959748cSgd78059 mutex_destroy(&afep->afe_intrlock); 615*1959748cSgd78059 mutex_destroy(&afep->afe_xmtlock); 616*1959748cSgd78059 617*1959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 618*1959748cSgd78059 return (DDI_SUCCESS); 619*1959748cSgd78059 620*1959748cSgd78059 case DDI_SUSPEND: 621*1959748cSgd78059 /* quiesce the hardware */ 622*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 623*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 624*1959748cSgd78059 afep->afe_flags |= AFE_SUSPENDED; 625*1959748cSgd78059 afe_stopall(afep); 626*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 627*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 628*1959748cSgd78059 return (DDI_SUCCESS); 629*1959748cSgd78059 default: 630*1959748cSgd78059 return (DDI_FAILURE); 631*1959748cSgd78059 } 632*1959748cSgd78059 } 633*1959748cSgd78059 634*1959748cSgd78059 int 635*1959748cSgd78059 afe_resume(dev_info_t *dip) 636*1959748cSgd78059 { 637*1959748cSgd78059 afe_t *afep; 638*1959748cSgd78059 639*1959748cSgd78059 if ((afep = ddi_get_driver_private(dip)) == NULL) { 640*1959748cSgd78059 return (DDI_FAILURE); 641*1959748cSgd78059 } 642*1959748cSgd78059 643*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 644*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 645*1959748cSgd78059 646*1959748cSgd78059 afep->afe_flags &= ~AFE_SUSPENDED; 647*1959748cSgd78059 648*1959748cSgd78059 /* re-initialize chip */ 649*1959748cSgd78059 if (!afe_initialize(afep)) { 650*1959748cSgd78059 afe_error(afep->afe_dip, "unable to resume chip!"); 651*1959748cSgd78059 afep->afe_flags |= AFE_SUSPENDED; 652*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 653*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 654*1959748cSgd78059 return (DDI_SUCCESS); 655*1959748cSgd78059 } 656*1959748cSgd78059 657*1959748cSgd78059 /* start the chip */ 658*1959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) { 659*1959748cSgd78059 afe_startall(afep); 660*1959748cSgd78059 } 661*1959748cSgd78059 662*1959748cSgd78059 /* drop locks */ 663*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 664*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 665*1959748cSgd78059 666*1959748cSgd78059 return (DDI_SUCCESS); 667*1959748cSgd78059 } 668*1959748cSgd78059 669*1959748cSgd78059 void 670*1959748cSgd78059 afe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 671*1959748cSgd78059 { 672*1959748cSgd78059 afe_t *afep = arg; 673*1959748cSgd78059 674*1959748cSgd78059 switch (*(int *)(void *)(mp->b_rptr)) { 675*1959748cSgd78059 676*1959748cSgd78059 case NDIOC_GET: 677*1959748cSgd78059 afe_ndget(afep, wq, mp); 678*1959748cSgd78059 break; 679*1959748cSgd78059 680*1959748cSgd78059 case NDIOC_SET: 681*1959748cSgd78059 afe_ndset(afep, wq, mp); 682*1959748cSgd78059 break; 683*1959748cSgd78059 684*1959748cSgd78059 default: 685*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 686*1959748cSgd78059 break; 687*1959748cSgd78059 } 688*1959748cSgd78059 } 689*1959748cSgd78059 690*1959748cSgd78059 void 691*1959748cSgd78059 afe_setrxfilt(afe_t *afep) 692*1959748cSgd78059 { 693*1959748cSgd78059 unsigned rxen, pa0, pa1; 694*1959748cSgd78059 695*1959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 696*1959748cSgd78059 /* don't touch a suspended interface */ 697*1959748cSgd78059 return; 698*1959748cSgd78059 } 699*1959748cSgd78059 700*1959748cSgd78059 rxen = GETCSR(afep, CSR_NAR) & NAR_RX_ENABLE; 701*1959748cSgd78059 702*1959748cSgd78059 /* stop receiver */ 703*1959748cSgd78059 if (rxen) { 704*1959748cSgd78059 afe_stopmac(afep); 705*1959748cSgd78059 } 706*1959748cSgd78059 707*1959748cSgd78059 /* program promiscuous mode */ 708*1959748cSgd78059 if (afep->afe_promisc) 709*1959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_RX_PROMISC); 710*1959748cSgd78059 else 711*1959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_PROMISC); 712*1959748cSgd78059 713*1959748cSgd78059 /* program mac address */ 714*1959748cSgd78059 pa0 = (afep->afe_curraddr[3] << 24) | (afep->afe_curraddr[2] << 16) | 715*1959748cSgd78059 (afep->afe_curraddr[1] << 8) | afep->afe_curraddr[0]; 716*1959748cSgd78059 pa1 = (afep->afe_curraddr[5] << 8) | afep->afe_curraddr[4]; 717*1959748cSgd78059 718*1959748cSgd78059 DBG(DMACID, "programming PAR0 with %x", pa0); 719*1959748cSgd78059 DBG(DMACID, "programming PAR1 with %x", pa1); 720*1959748cSgd78059 PUTCSR(afep, CSR_PAR0, pa0); 721*1959748cSgd78059 PUTCSR(afep, CSR_PAR1, pa1); 722*1959748cSgd78059 if (rxen) { 723*1959748cSgd78059 SETBIT(afep, CSR_NAR, rxen); 724*1959748cSgd78059 } 725*1959748cSgd78059 726*1959748cSgd78059 DBG(DMACID, "programming MAR0 = %x", afep->afe_mctab[0]); 727*1959748cSgd78059 DBG(DMACID, "programming MAR1 = %x", afep->afe_mctab[1]); 728*1959748cSgd78059 729*1959748cSgd78059 /* program multicast filter */ 730*1959748cSgd78059 if (AFE_MODEL(afep) == MODEL_COMET) { 731*1959748cSgd78059 if (afep->afe_mctab[0] || afep->afe_mctab[1]) { 732*1959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_RX_MULTI); 733*1959748cSgd78059 } else { 734*1959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_MULTI); 735*1959748cSgd78059 } 736*1959748cSgd78059 } else { 737*1959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_MULTI); 738*1959748cSgd78059 PUTCSR(afep, CSR_MAR0, afep->afe_mctab[0]); 739*1959748cSgd78059 PUTCSR(afep, CSR_MAR1, afep->afe_mctab[1]); 740*1959748cSgd78059 } 741*1959748cSgd78059 742*1959748cSgd78059 /* restart receiver */ 743*1959748cSgd78059 if (rxen) { 744*1959748cSgd78059 afe_startmac(afep); 745*1959748cSgd78059 } 746*1959748cSgd78059 } 747*1959748cSgd78059 748*1959748cSgd78059 int 749*1959748cSgd78059 afe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 750*1959748cSgd78059 { 751*1959748cSgd78059 afe_t *afep = arg; 752*1959748cSgd78059 int index; 753*1959748cSgd78059 uint32_t crc; 754*1959748cSgd78059 uint32_t bit; 755*1959748cSgd78059 uint32_t newval, oldval; 756*1959748cSgd78059 757*1959748cSgd78059 CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table); 758*1959748cSgd78059 crc %= AFE_MCHASH; 759*1959748cSgd78059 760*1959748cSgd78059 /* bit within a 32-bit word */ 761*1959748cSgd78059 index = crc / 32; 762*1959748cSgd78059 bit = (1 << (crc % 32)); 763*1959748cSgd78059 764*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 765*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 766*1959748cSgd78059 newval = oldval = afep->afe_mctab[index]; 767*1959748cSgd78059 768*1959748cSgd78059 if (add) { 769*1959748cSgd78059 afep->afe_mccount[crc]++; 770*1959748cSgd78059 if (afep->afe_mccount[crc] == 1) 771*1959748cSgd78059 newval |= bit; 772*1959748cSgd78059 } else { 773*1959748cSgd78059 afep->afe_mccount[crc]--; 774*1959748cSgd78059 if (afep->afe_mccount[crc] == 0) 775*1959748cSgd78059 newval &= ~bit; 776*1959748cSgd78059 } 777*1959748cSgd78059 if (newval != oldval) { 778*1959748cSgd78059 afep->afe_mctab[index] = newval; 779*1959748cSgd78059 afe_setrxfilt(afep); 780*1959748cSgd78059 } 781*1959748cSgd78059 782*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 783*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 784*1959748cSgd78059 785*1959748cSgd78059 return (0); 786*1959748cSgd78059 } 787*1959748cSgd78059 788*1959748cSgd78059 int 789*1959748cSgd78059 afe_m_promisc(void *arg, boolean_t on) 790*1959748cSgd78059 { 791*1959748cSgd78059 afe_t *afep = arg; 792*1959748cSgd78059 793*1959748cSgd78059 /* exclusive access to the card while we reprogram it */ 794*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 795*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 796*1959748cSgd78059 /* save current promiscuous mode state for replay in resume */ 797*1959748cSgd78059 afep->afe_promisc = on; 798*1959748cSgd78059 799*1959748cSgd78059 afe_setrxfilt(afep); 800*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 801*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 802*1959748cSgd78059 803*1959748cSgd78059 return (0); 804*1959748cSgd78059 } 805*1959748cSgd78059 806*1959748cSgd78059 int 807*1959748cSgd78059 afe_m_unicst(void *arg, const uint8_t *macaddr) 808*1959748cSgd78059 { 809*1959748cSgd78059 afe_t *afep = arg; 810*1959748cSgd78059 811*1959748cSgd78059 /* exclusive access to the card while we reprogram it */ 812*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 813*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 814*1959748cSgd78059 815*1959748cSgd78059 bcopy(macaddr, afep->afe_curraddr, ETHERADDRL); 816*1959748cSgd78059 afe_setrxfilt(afep); 817*1959748cSgd78059 818*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 819*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 820*1959748cSgd78059 821*1959748cSgd78059 return (0); 822*1959748cSgd78059 } 823*1959748cSgd78059 824*1959748cSgd78059 mblk_t * 825*1959748cSgd78059 afe_m_tx(void *arg, mblk_t *mp) 826*1959748cSgd78059 { 827*1959748cSgd78059 afe_t *afep = arg; 828*1959748cSgd78059 mblk_t *nmp; 829*1959748cSgd78059 830*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 831*1959748cSgd78059 832*1959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 833*1959748cSgd78059 while ((nmp = mp) != NULL) { 834*1959748cSgd78059 afep->afe_carrier_errors++; 835*1959748cSgd78059 mp = mp->b_next; 836*1959748cSgd78059 freemsg(nmp); 837*1959748cSgd78059 } 838*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 839*1959748cSgd78059 return (NULL); 840*1959748cSgd78059 } 841*1959748cSgd78059 842*1959748cSgd78059 while (mp != NULL) { 843*1959748cSgd78059 nmp = mp->b_next; 844*1959748cSgd78059 mp->b_next = NULL; 845*1959748cSgd78059 846*1959748cSgd78059 if (!afe_send(afep, mp)) { 847*1959748cSgd78059 mp->b_next = nmp; 848*1959748cSgd78059 break; 849*1959748cSgd78059 } 850*1959748cSgd78059 mp = nmp; 851*1959748cSgd78059 } 852*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 853*1959748cSgd78059 854*1959748cSgd78059 return (mp); 855*1959748cSgd78059 } 856*1959748cSgd78059 857*1959748cSgd78059 /* 858*1959748cSgd78059 * Hardware management. 859*1959748cSgd78059 */ 860*1959748cSgd78059 static boolean_t 861*1959748cSgd78059 afe_initialize(afe_t *afep) 862*1959748cSgd78059 { 863*1959748cSgd78059 int i; 864*1959748cSgd78059 unsigned val; 865*1959748cSgd78059 uint32_t par, nar; 866*1959748cSgd78059 867*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 868*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 869*1959748cSgd78059 870*1959748cSgd78059 DBG(DCHATTY, "resetting!"); 871*1959748cSgd78059 SETBIT(afep, CSR_PAR, PAR_RESET); 872*1959748cSgd78059 for (i = 1; i < 10; i++) { 873*1959748cSgd78059 drv_usecwait(5); 874*1959748cSgd78059 val = GETCSR(afep, CSR_PAR); 875*1959748cSgd78059 if (!(val & PAR_RESET)) { 876*1959748cSgd78059 break; 877*1959748cSgd78059 } 878*1959748cSgd78059 } 879*1959748cSgd78059 if (i == 10) { 880*1959748cSgd78059 afe_error(afep->afe_dip, "timed out waiting for reset!"); 881*1959748cSgd78059 return (B_FALSE); 882*1959748cSgd78059 } 883*1959748cSgd78059 884*1959748cSgd78059 /* 885*1959748cSgd78059 * Updated Centaur data sheets show that the Comet and Centaur are 886*1959748cSgd78059 * alike here (contrary to earlier versions of the data sheet). 887*1959748cSgd78059 */ 888*1959748cSgd78059 /* XXX:? chip problems */ 889*1959748cSgd78059 /* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */ 890*1959748cSgd78059 par = 0; 891*1959748cSgd78059 switch (afep->afe_cachesize) { 892*1959748cSgd78059 case 8: 893*1959748cSgd78059 par |= PAR_CALIGN_8 | PAR_BURST_8; 894*1959748cSgd78059 break; 895*1959748cSgd78059 case 16: 896*1959748cSgd78059 par |= PAR_CALIGN_16 | PAR_BURST_16; 897*1959748cSgd78059 break; 898*1959748cSgd78059 case 32: 899*1959748cSgd78059 par |= PAR_CALIGN_32 | PAR_BURST_32; 900*1959748cSgd78059 break; 901*1959748cSgd78059 default: 902*1959748cSgd78059 par |= PAR_BURST_32; 903*1959748cSgd78059 par &= ~(PAR_MWIE | PAR_MRLE | PAR_MRME); 904*1959748cSgd78059 break; 905*1959748cSgd78059 906*1959748cSgd78059 } 907*1959748cSgd78059 908*1959748cSgd78059 PUTCSR(afep, CSR_PAR, par); 909*1959748cSgd78059 910*1959748cSgd78059 /* enable transmit underrun auto-recovery */ 911*1959748cSgd78059 SETBIT(afep, CSR_CR, CR_TXURAUTOR); 912*1959748cSgd78059 913*1959748cSgd78059 afe_resetrings(afep); 914*1959748cSgd78059 915*1959748cSgd78059 /* clear the lost packet counter (cleared on read) */ 916*1959748cSgd78059 (void) GETCSR(afep, CSR_LPC); 917*1959748cSgd78059 918*1959748cSgd78059 nar = GETCSR(afep, CSR_NAR); 919*1959748cSgd78059 nar &= ~NAR_TR; /* clear tx threshold */ 920*1959748cSgd78059 nar |= NAR_SF; /* store-and-forward */ 921*1959748cSgd78059 nar |= NAR_HBD; /* disable SQE test */ 922*1959748cSgd78059 PUTCSR(afep, CSR_NAR, nar); 923*1959748cSgd78059 924*1959748cSgd78059 afe_setrxfilt(afep); 925*1959748cSgd78059 926*1959748cSgd78059 return (B_TRUE); 927*1959748cSgd78059 } 928*1959748cSgd78059 929*1959748cSgd78059 /* 930*1959748cSgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation. 931*1959748cSgd78059 */ 932*1959748cSgd78059 933*1959748cSgd78059 uint8_t 934*1959748cSgd78059 afe_sromwidth(afe_t *afep) 935*1959748cSgd78059 { 936*1959748cSgd78059 int i; 937*1959748cSgd78059 uint32_t eeread; 938*1959748cSgd78059 uint8_t addrlen = 8; 939*1959748cSgd78059 940*1959748cSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 941*1959748cSgd78059 942*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 943*1959748cSgd78059 drv_usecwait(1); 944*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 945*1959748cSgd78059 946*1959748cSgd78059 /* command bits first */ 947*1959748cSgd78059 for (i = 4; i != 0; i >>= 1) { 948*1959748cSgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0; 949*1959748cSgd78059 950*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val); 951*1959748cSgd78059 drv_usecwait(1); 952*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 953*1959748cSgd78059 drv_usecwait(1); 954*1959748cSgd78059 } 955*1959748cSgd78059 956*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 957*1959748cSgd78059 958*1959748cSgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) { 959*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK); 960*1959748cSgd78059 drv_usecwait(1); 961*1959748cSgd78059 if (!(GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT)) { 962*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 963*1959748cSgd78059 drv_usecwait(1); 964*1959748cSgd78059 break; 965*1959748cSgd78059 } 966*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 967*1959748cSgd78059 drv_usecwait(1); 968*1959748cSgd78059 } 969*1959748cSgd78059 970*1959748cSgd78059 /* turn off accesses to the EEPROM */ 971*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 972*1959748cSgd78059 973*1959748cSgd78059 DBG(DSROM, "detected srom width = %d bits", addrlen); 974*1959748cSgd78059 975*1959748cSgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen); 976*1959748cSgd78059 } 977*1959748cSgd78059 978*1959748cSgd78059 /* 979*1959748cSgd78059 * The words in EEPROM are stored in little endian order. We 980*1959748cSgd78059 * shift bits out in big endian order, though. This requires 981*1959748cSgd78059 * a byte swap on some platforms. 982*1959748cSgd78059 */ 983*1959748cSgd78059 uint16_t 984*1959748cSgd78059 afe_readsromword(afe_t *afep, unsigned romaddr) 985*1959748cSgd78059 { 986*1959748cSgd78059 int i; 987*1959748cSgd78059 uint16_t word = 0; 988*1959748cSgd78059 uint16_t retval; 989*1959748cSgd78059 int eeread; 990*1959748cSgd78059 uint8_t addrlen; 991*1959748cSgd78059 int readcmd; 992*1959748cSgd78059 uchar_t *ptr; 993*1959748cSgd78059 994*1959748cSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 995*1959748cSgd78059 addrlen = afep->afe_sromwidth; 996*1959748cSgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr; 997*1959748cSgd78059 998*1959748cSgd78059 if (romaddr >= (1 << addrlen)) { 999*1959748cSgd78059 /* too big to fit! */ 1000*1959748cSgd78059 return (0); 1001*1959748cSgd78059 } 1002*1959748cSgd78059 1003*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 1004*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 1005*1959748cSgd78059 1006*1959748cSgd78059 /* command and address bits */ 1007*1959748cSgd78059 for (i = 4 + addrlen; i >= 0; i--) { 1008*1959748cSgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0; 1009*1959748cSgd78059 1010*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val); 1011*1959748cSgd78059 drv_usecwait(1); 1012*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 1013*1959748cSgd78059 drv_usecwait(1); 1014*1959748cSgd78059 } 1015*1959748cSgd78059 1016*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 1017*1959748cSgd78059 1018*1959748cSgd78059 for (i = 0; i < 16; i++) { 1019*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK); 1020*1959748cSgd78059 drv_usecwait(1); 1021*1959748cSgd78059 word <<= 1; 1022*1959748cSgd78059 if (GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT) { 1023*1959748cSgd78059 word |= 1; 1024*1959748cSgd78059 } 1025*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 1026*1959748cSgd78059 drv_usecwait(1); 1027*1959748cSgd78059 } 1028*1959748cSgd78059 1029*1959748cSgd78059 /* turn off accesses to the EEPROM */ 1030*1959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 1031*1959748cSgd78059 1032*1959748cSgd78059 /* 1033*1959748cSgd78059 * Fix up the endianness thing. Note that the values 1034*1959748cSgd78059 * are stored in little endian format on the SROM. 1035*1959748cSgd78059 */ 1036*1959748cSgd78059 ptr = (uchar_t *)&word; 1037*1959748cSgd78059 retval = (ptr[1] << 8) | ptr[0]; 1038*1959748cSgd78059 return (retval); 1039*1959748cSgd78059 } 1040*1959748cSgd78059 1041*1959748cSgd78059 void 1042*1959748cSgd78059 afe_readsrom(afe_t *afep, unsigned romaddr, unsigned len, char *dest) 1043*1959748cSgd78059 { 1044*1959748cSgd78059 int i; 1045*1959748cSgd78059 uint16_t word; 1046*1959748cSgd78059 uint16_t *ptr = (uint16_t *)((void *)dest); 1047*1959748cSgd78059 for (i = 0; i < len; i++) { 1048*1959748cSgd78059 word = afe_readsromword(afep, romaddr + i); 1049*1959748cSgd78059 *ptr = word; 1050*1959748cSgd78059 ptr++; 1051*1959748cSgd78059 } 1052*1959748cSgd78059 } 1053*1959748cSgd78059 1054*1959748cSgd78059 void 1055*1959748cSgd78059 afe_getfactaddr(afe_t *afep, uchar_t *eaddr) 1056*1959748cSgd78059 { 1057*1959748cSgd78059 afe_readsrom(afep, SROM_ENADDR, ETHERADDRL / 2, (char *)eaddr); 1058*1959748cSgd78059 1059*1959748cSgd78059 DBG(DMACID, 1060*1959748cSgd78059 "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x", 1061*1959748cSgd78059 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 1062*1959748cSgd78059 } 1063*1959748cSgd78059 1064*1959748cSgd78059 /* 1065*1959748cSgd78059 * MII management. 1066*1959748cSgd78059 */ 1067*1959748cSgd78059 void 1068*1959748cSgd78059 afe_startphy(afe_t *afep) 1069*1959748cSgd78059 { 1070*1959748cSgd78059 unsigned phyaddr; 1071*1959748cSgd78059 unsigned bmcr; 1072*1959748cSgd78059 unsigned bmsr; 1073*1959748cSgd78059 unsigned anar; 1074*1959748cSgd78059 unsigned phyidr1; 1075*1959748cSgd78059 unsigned phyidr2; 1076*1959748cSgd78059 unsigned nosqe = 0; 1077*1959748cSgd78059 int retries; 1078*1959748cSgd78059 int force; 1079*1959748cSgd78059 int fiber; 1080*1959748cSgd78059 int cnt; 1081*1959748cSgd78059 1082*1959748cSgd78059 /* ADMtek devices just use the PHY at address 1 */ 1083*1959748cSgd78059 afep->afe_phyaddr = phyaddr = 1; 1084*1959748cSgd78059 1085*1959748cSgd78059 phyidr1 = afe_miiread(afep, phyaddr, MII_PHYIDH); 1086*1959748cSgd78059 phyidr2 = afe_miiread(afep, phyaddr, MII_PHYIDL); 1087*1959748cSgd78059 if ((phyidr1 == 0x0022) && 1088*1959748cSgd78059 ((phyidr2 & 0xfff0) == 0x5410)) { 1089*1959748cSgd78059 nosqe = 1; 1090*1959748cSgd78059 /* only 983B has fiber support */ 1091*1959748cSgd78059 afep->afe_flags |= AFE_HASFIBER; 1092*1959748cSgd78059 } 1093*1959748cSgd78059 afep->afe_phyid = (phyidr1 << 16) | phyidr2; 1094*1959748cSgd78059 1095*1959748cSgd78059 DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2); 1096*1959748cSgd78059 DBG(DPHY, "bmsr = %x", afe_miiread(afep, 1097*1959748cSgd78059 afep->afe_phyaddr, MII_STATUS)); 1098*1959748cSgd78059 DBG(DPHY, "anar = %x", afe_miiread(afep, 1099*1959748cSgd78059 afep->afe_phyaddr, MII_AN_ADVERT)); 1100*1959748cSgd78059 DBG(DPHY, "anlpar = %x", afe_miiread(afep, 1101*1959748cSgd78059 afep->afe_phyaddr, MII_AN_LPABLE)); 1102*1959748cSgd78059 DBG(DPHY, "aner = %x", afe_miiread(afep, 1103*1959748cSgd78059 afep->afe_phyaddr, MII_AN_EXPANSION)); 1104*1959748cSgd78059 1105*1959748cSgd78059 DBG(DPHY, "resetting phy"); 1106*1959748cSgd78059 1107*1959748cSgd78059 /* we reset the phy block */ 1108*1959748cSgd78059 afe_miiwrite(afep, phyaddr, MII_CONTROL, MII_CONTROL_RESET); 1109*1959748cSgd78059 /* 1110*1959748cSgd78059 * wait for it to complete -- 500usec is still to short to 1111*1959748cSgd78059 * bother getting the system clock involved. 1112*1959748cSgd78059 */ 1113*1959748cSgd78059 drv_usecwait(500); 1114*1959748cSgd78059 for (retries = 0; retries < 10; retries++) { 1115*1959748cSgd78059 if (afe_miiread(afep, phyaddr, MII_CONTROL) & 1116*1959748cSgd78059 MII_CONTROL_RESET) { 1117*1959748cSgd78059 drv_usecwait(500); 1118*1959748cSgd78059 continue; 1119*1959748cSgd78059 } 1120*1959748cSgd78059 break; 1121*1959748cSgd78059 } 1122*1959748cSgd78059 if (retries == 100) { 1123*1959748cSgd78059 afe_error(afep->afe_dip, "timeout waiting on phy to reset"); 1124*1959748cSgd78059 return; 1125*1959748cSgd78059 } 1126*1959748cSgd78059 1127*1959748cSgd78059 DBG(DPHY, "phy reset complete"); 1128*1959748cSgd78059 1129*1959748cSgd78059 bmsr = afe_miiread(afep, phyaddr, MII_STATUS); 1130*1959748cSgd78059 anar = afe_miiread(afep, phyaddr, MII_AN_ADVERT); 1131*1959748cSgd78059 1132*1959748cSgd78059 anar &= ~(MII_ABILITY_100BASE_T4 | 1133*1959748cSgd78059 MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX | 1134*1959748cSgd78059 MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T); 1135*1959748cSgd78059 1136*1959748cSgd78059 force = 0; 1137*1959748cSgd78059 fiber = 0; 1138*1959748cSgd78059 1139*1959748cSgd78059 /* if fiber is being forced, and device supports fiber... */ 1140*1959748cSgd78059 if (afep->afe_flags & AFE_HASFIBER) { 1141*1959748cSgd78059 1142*1959748cSgd78059 uint16_t mcr; 1143*1959748cSgd78059 1144*1959748cSgd78059 DBG(DPHY, "device supports 100BaseFX"); 1145*1959748cSgd78059 mcr = afe_miiread(afep, phyaddr, PHY_MCR); 1146*1959748cSgd78059 switch (afep->afe_forcefiber) { 1147*1959748cSgd78059 case 0: 1148*1959748cSgd78059 /* UTP Port */ 1149*1959748cSgd78059 DBG(DPHY, "forcing twpair"); 1150*1959748cSgd78059 mcr &= ~MCR_FIBER; 1151*1959748cSgd78059 fiber = 0; 1152*1959748cSgd78059 break; 1153*1959748cSgd78059 case 1: 1154*1959748cSgd78059 /* Fiber Port */ 1155*1959748cSgd78059 force = 1; 1156*1959748cSgd78059 DBG(DPHY, "forcing 100BaseFX"); 1157*1959748cSgd78059 mcr |= MCR_FIBER; 1158*1959748cSgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 1159*1959748cSgd78059 fiber = 1; 1160*1959748cSgd78059 break; 1161*1959748cSgd78059 default: 1162*1959748cSgd78059 DBG(DPHY, "checking for 100BaseFX link"); 1163*1959748cSgd78059 /* fiber is 100 Mb FDX */ 1164*1959748cSgd78059 afe_miiwrite(afep, phyaddr, MII_CONTROL, 1165*1959748cSgd78059 MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 1166*1959748cSgd78059 drv_usecwait(50); 1167*1959748cSgd78059 1168*1959748cSgd78059 mcr = afe_miiread(afep, phyaddr, PHY_MCR); 1169*1959748cSgd78059 mcr |= MCR_FIBER; 1170*1959748cSgd78059 afe_miiwrite(afep, phyaddr, PHY_MCR, mcr); 1171*1959748cSgd78059 drv_usecwait(500); 1172*1959748cSgd78059 1173*1959748cSgd78059 /* if fiber is active, use it */ 1174*1959748cSgd78059 if ((afe_miiread(afep, phyaddr, MII_STATUS) & 1175*1959748cSgd78059 MII_STATUS_LINKUP)) { 1176*1959748cSgd78059 bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX; 1177*1959748cSgd78059 fiber = 1; 1178*1959748cSgd78059 } else { 1179*1959748cSgd78059 mcr &= ~MCR_FIBER; 1180*1959748cSgd78059 fiber = 0; 1181*1959748cSgd78059 } 1182*1959748cSgd78059 break; 1183*1959748cSgd78059 } 1184*1959748cSgd78059 afe_miiwrite(afep, phyaddr, PHY_MCR, mcr); 1185*1959748cSgd78059 drv_usecwait(500); 1186*1959748cSgd78059 } 1187*1959748cSgd78059 1188*1959748cSgd78059 if (fiber) { 1189*1959748cSgd78059 /* fiber only supports 100FDX(?) */ 1190*1959748cSgd78059 bmsr &= ~(MII_STATUS_100_BASE_T4 | 1191*1959748cSgd78059 MII_STATUS_100_BASEX | MII_STATUS_10_FD | MII_STATUS_10); 1192*1959748cSgd78059 bmsr |= MII_STATUS_100_BASEX_FD; 1193*1959748cSgd78059 } 1194*1959748cSgd78059 1195*1959748cSgd78059 /* disable modes not supported in hardware */ 1196*1959748cSgd78059 if (!(bmsr & MII_STATUS_100_BASEX_FD)) { 1197*1959748cSgd78059 afep->afe_adv_100fdx = 0; 1198*1959748cSgd78059 } 1199*1959748cSgd78059 if (!(bmsr & MII_STATUS_100_BASE_T4)) { 1200*1959748cSgd78059 afep->afe_adv_100T4 = 0; 1201*1959748cSgd78059 } 1202*1959748cSgd78059 if (!(bmsr & MII_STATUS_100_BASEX)) { 1203*1959748cSgd78059 afep->afe_adv_100hdx = 0; 1204*1959748cSgd78059 } 1205*1959748cSgd78059 if (!(bmsr & MII_STATUS_10_FD)) { 1206*1959748cSgd78059 afep->afe_adv_10fdx = 0; 1207*1959748cSgd78059 } 1208*1959748cSgd78059 if (!(bmsr & MII_STATUS_10)) { 1209*1959748cSgd78059 afep->afe_adv_10hdx = 0; 1210*1959748cSgd78059 } 1211*1959748cSgd78059 if (!(bmsr & MII_STATUS_CANAUTONEG)) { 1212*1959748cSgd78059 afep->afe_adv_aneg = 0; 1213*1959748cSgd78059 force = 1; 1214*1959748cSgd78059 } 1215*1959748cSgd78059 1216*1959748cSgd78059 cnt = 0; 1217*1959748cSgd78059 if (afep->afe_adv_100fdx) { 1218*1959748cSgd78059 anar |= MII_ABILITY_100BASE_TX_FD; 1219*1959748cSgd78059 cnt++; 1220*1959748cSgd78059 } 1221*1959748cSgd78059 if (afep->afe_adv_100T4) { 1222*1959748cSgd78059 anar |= MII_ABILITY_100BASE_T4; 1223*1959748cSgd78059 cnt++; 1224*1959748cSgd78059 } 1225*1959748cSgd78059 if (afep->afe_adv_100hdx) { 1226*1959748cSgd78059 anar |= MII_ABILITY_100BASE_TX; 1227*1959748cSgd78059 cnt++; 1228*1959748cSgd78059 } 1229*1959748cSgd78059 if (afep->afe_adv_10fdx) { 1230*1959748cSgd78059 anar |= MII_ABILITY_10BASE_T_FD; 1231*1959748cSgd78059 cnt++; 1232*1959748cSgd78059 } 1233*1959748cSgd78059 if (afep->afe_adv_10hdx) { 1234*1959748cSgd78059 anar |= MII_ABILITY_10BASE_T; 1235*1959748cSgd78059 cnt++; 1236*1959748cSgd78059 } 1237*1959748cSgd78059 1238*1959748cSgd78059 /* 1239*1959748cSgd78059 * Make certain at least one valid link mode is selected. 1240*1959748cSgd78059 */ 1241*1959748cSgd78059 if (!cnt) { 1242*1959748cSgd78059 afe_error(afep->afe_dip, "No valid link mode selected."); 1243*1959748cSgd78059 afe_error(afep->afe_dip, "Powering down PHY."); 1244*1959748cSgd78059 afe_stopphy(afep); 1245*1959748cSgd78059 afep->afe_linkup = LINK_STATE_DOWN; 1246*1959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) 1247*1959748cSgd78059 afe_reportlink(afep); 1248*1959748cSgd78059 return; 1249*1959748cSgd78059 } 1250*1959748cSgd78059 1251*1959748cSgd78059 if (fiber) { 1252*1959748cSgd78059 bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX; 1253*1959748cSgd78059 } else if ((afep->afe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) { 1254*1959748cSgd78059 DBG(DPHY, "using autoneg mode"); 1255*1959748cSgd78059 bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN); 1256*1959748cSgd78059 } else { 1257*1959748cSgd78059 DBG(DPHY, "using forced mode"); 1258*1959748cSgd78059 force = 1; 1259*1959748cSgd78059 if (afep->afe_adv_100fdx) { 1260*1959748cSgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 1261*1959748cSgd78059 } else if (afep->afe_adv_100hdx) { 1262*1959748cSgd78059 bmcr = MII_CONTROL_100MB; 1263*1959748cSgd78059 } else if (afep->afe_adv_10fdx) { 1264*1959748cSgd78059 bmcr = MII_CONTROL_FDUPLEX; 1265*1959748cSgd78059 } else { 1266*1959748cSgd78059 /* 10HDX */ 1267*1959748cSgd78059 bmcr = 0; 1268*1959748cSgd78059 } 1269*1959748cSgd78059 } 1270*1959748cSgd78059 1271*1959748cSgd78059 afep->afe_forcephy = force; 1272*1959748cSgd78059 1273*1959748cSgd78059 DBG(DPHY, "programming anar to 0x%x", anar); 1274*1959748cSgd78059 afe_miiwrite(afep, phyaddr, MII_AN_ADVERT, anar); 1275*1959748cSgd78059 DBG(DPHY, "programming bmcr to 0x%x", bmcr); 1276*1959748cSgd78059 afe_miiwrite(afep, phyaddr, MII_CONTROL, bmcr); 1277*1959748cSgd78059 1278*1959748cSgd78059 if (nosqe) { 1279*1959748cSgd78059 uint16_t pilr; 1280*1959748cSgd78059 /* 1281*1959748cSgd78059 * work around for errata 983B_0416 -- duplex light flashes 1282*1959748cSgd78059 * in 10 HDX. we just disable SQE testing on the device. 1283*1959748cSgd78059 */ 1284*1959748cSgd78059 pilr = afe_miiread(afep, phyaddr, PHY_PILR); 1285*1959748cSgd78059 pilr |= PILR_NOSQE; 1286*1959748cSgd78059 afe_miiwrite(afep, phyaddr, PHY_PILR, pilr); 1287*1959748cSgd78059 } 1288*1959748cSgd78059 1289*1959748cSgd78059 /* 1290*1959748cSgd78059 * schedule a query of the link status 1291*1959748cSgd78059 */ 1292*1959748cSgd78059 PUTCSR(afep, CSR_TIMER, TIMER_LOOP | 1293*1959748cSgd78059 (AFE_LINKTIMER * 1000 / TIMER_USEC)); 1294*1959748cSgd78059 } 1295*1959748cSgd78059 1296*1959748cSgd78059 void 1297*1959748cSgd78059 afe_stopphy(afe_t *afep) 1298*1959748cSgd78059 { 1299*1959748cSgd78059 /* stop the phy timer */ 1300*1959748cSgd78059 PUTCSR(afep, CSR_TIMER, 0); 1301*1959748cSgd78059 1302*1959748cSgd78059 /* 1303*1959748cSgd78059 * phy in isolate & powerdown mode... 1304*1959748cSgd78059 */ 1305*1959748cSgd78059 afe_miiwrite(afep, afep->afe_phyaddr, MII_CONTROL, 1306*1959748cSgd78059 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE); 1307*1959748cSgd78059 1308*1959748cSgd78059 /* 1309*1959748cSgd78059 * mark the link state unknown 1310*1959748cSgd78059 */ 1311*1959748cSgd78059 if (!afep->afe_resetting) { 1312*1959748cSgd78059 afep->afe_linkup = LINK_STATE_UNKNOWN; 1313*1959748cSgd78059 afep->afe_ifspeed = 0; 1314*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1315*1959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) 1316*1959748cSgd78059 afe_reportlink(afep); 1317*1959748cSgd78059 } 1318*1959748cSgd78059 } 1319*1959748cSgd78059 1320*1959748cSgd78059 void 1321*1959748cSgd78059 afe_reportlink(afe_t *afep) 1322*1959748cSgd78059 { 1323*1959748cSgd78059 int changed = 0; 1324*1959748cSgd78059 1325*1959748cSgd78059 if (afep->afe_ifspeed != afep->afe_lastifspeed) { 1326*1959748cSgd78059 afep->afe_lastifspeed = afep->afe_ifspeed; 1327*1959748cSgd78059 changed++; 1328*1959748cSgd78059 } 1329*1959748cSgd78059 if (afep->afe_duplex != afep->afe_lastduplex) { 1330*1959748cSgd78059 afep->afe_lastduplex = afep->afe_duplex; 1331*1959748cSgd78059 changed++; 1332*1959748cSgd78059 } 1333*1959748cSgd78059 if (changed) 1334*1959748cSgd78059 mac_link_update(afep->afe_mh, afep->afe_linkup); 1335*1959748cSgd78059 } 1336*1959748cSgd78059 1337*1959748cSgd78059 void 1338*1959748cSgd78059 afe_checklink(afe_t *afep) 1339*1959748cSgd78059 { 1340*1959748cSgd78059 if ((afep->afe_flags & AFE_RUNNING) == 0) 1341*1959748cSgd78059 return; 1342*1959748cSgd78059 1343*1959748cSgd78059 if ((afep->afe_txstall_time != 0) && 1344*1959748cSgd78059 (gethrtime() > afep->afe_txstall_time) && 1345*1959748cSgd78059 (afep->afe_txavail != AFE_TXRING)) { 1346*1959748cSgd78059 afep->afe_txstall_time = 0; 1347*1959748cSgd78059 afe_error(afep->afe_dip, "TX stall detected!"); 1348*1959748cSgd78059 afe_resetall(afep); 1349*1959748cSgd78059 return; 1350*1959748cSgd78059 } 1351*1959748cSgd78059 1352*1959748cSgd78059 switch (AFE_MODEL(afep)) { 1353*1959748cSgd78059 case MODEL_COMET: 1354*1959748cSgd78059 afe_checklinkcomet(afep); 1355*1959748cSgd78059 break; 1356*1959748cSgd78059 case MODEL_CENTAUR: 1357*1959748cSgd78059 afe_checklinkcentaur(afep); 1358*1959748cSgd78059 break; 1359*1959748cSgd78059 } 1360*1959748cSgd78059 } 1361*1959748cSgd78059 1362*1959748cSgd78059 void 1363*1959748cSgd78059 afe_checklinkcomet(afe_t *afep) 1364*1959748cSgd78059 { 1365*1959748cSgd78059 uint16_t xciis; 1366*1959748cSgd78059 int reinit = 0; 1367*1959748cSgd78059 1368*1959748cSgd78059 xciis = GETCSR16(afep, CSR_XCIIS); 1369*1959748cSgd78059 if (xciis & XCIIS_PDF) { 1370*1959748cSgd78059 afe_error(afep->afe_dip, "Parallel detection fault detected!"); 1371*1959748cSgd78059 } 1372*1959748cSgd78059 if (xciis & XCIIS_RF) { 1373*1959748cSgd78059 afe_error(afep->afe_dip, "Remote fault detected."); 1374*1959748cSgd78059 } 1375*1959748cSgd78059 if (xciis & XCIIS_LFAIL) { 1376*1959748cSgd78059 if (afep->afe_linkup == LINK_STATE_UP) { 1377*1959748cSgd78059 reinit++; 1378*1959748cSgd78059 } 1379*1959748cSgd78059 afep->afe_ifspeed = 0; 1380*1959748cSgd78059 afep->afe_linkup = LINK_STATE_DOWN; 1381*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1382*1959748cSgd78059 afe_reportlink(afep); 1383*1959748cSgd78059 if (reinit) { 1384*1959748cSgd78059 afe_startphy(afep); 1385*1959748cSgd78059 } 1386*1959748cSgd78059 return; 1387*1959748cSgd78059 } 1388*1959748cSgd78059 1389*1959748cSgd78059 afep->afe_linkup = LINK_STATE_UP; 1390*1959748cSgd78059 afep->afe_ifspeed = (xciis & XCIIS_SPEED) ? 100000000 : 10000000; 1391*1959748cSgd78059 if (xciis & XCIIS_DUPLEX) { 1392*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_FULL; 1393*1959748cSgd78059 } else { 1394*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1395*1959748cSgd78059 } 1396*1959748cSgd78059 1397*1959748cSgd78059 afe_reportlink(afep); 1398*1959748cSgd78059 } 1399*1959748cSgd78059 1400*1959748cSgd78059 void 1401*1959748cSgd78059 afe_checklinkcentaur(afe_t *afep) 1402*1959748cSgd78059 { 1403*1959748cSgd78059 unsigned opmode; 1404*1959748cSgd78059 int reinit = 0; 1405*1959748cSgd78059 1406*1959748cSgd78059 opmode = GETCSR(afep, CSR_OPM); 1407*1959748cSgd78059 if ((opmode & OPM_MODE) == OPM_MACONLY) { 1408*1959748cSgd78059 DBG(DPHY, "Centaur running in MAC-only mode"); 1409*1959748cSgd78059 afe_checklinkmii(afep); 1410*1959748cSgd78059 return; 1411*1959748cSgd78059 } 1412*1959748cSgd78059 DBG(DPHY, "Centaur running in single chip mode"); 1413*1959748cSgd78059 if ((opmode & OPM_LINK) == 0) { 1414*1959748cSgd78059 if (afep->afe_linkup == LINK_STATE_UP) { 1415*1959748cSgd78059 reinit++; 1416*1959748cSgd78059 } 1417*1959748cSgd78059 afep->afe_ifspeed = 0; 1418*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1419*1959748cSgd78059 afep->afe_linkup = LINK_STATE_DOWN; 1420*1959748cSgd78059 afe_reportlink(afep); 1421*1959748cSgd78059 if (reinit) { 1422*1959748cSgd78059 afe_startphy(afep); 1423*1959748cSgd78059 } 1424*1959748cSgd78059 return; 1425*1959748cSgd78059 } 1426*1959748cSgd78059 1427*1959748cSgd78059 afep->afe_linkup = LINK_STATE_UP; 1428*1959748cSgd78059 afep->afe_ifspeed = (opmode & OPM_SPEED) ? 100000000 : 10000000; 1429*1959748cSgd78059 if (opmode & OPM_DUPLEX) { 1430*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_FULL; 1431*1959748cSgd78059 } else { 1432*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1433*1959748cSgd78059 } 1434*1959748cSgd78059 afe_reportlink(afep); 1435*1959748cSgd78059 } 1436*1959748cSgd78059 1437*1959748cSgd78059 void 1438*1959748cSgd78059 afe_checklinkmii(afe_t *afep) 1439*1959748cSgd78059 { 1440*1959748cSgd78059 /* read MII state registers */ 1441*1959748cSgd78059 uint16_t bmsr; 1442*1959748cSgd78059 uint16_t bmcr; 1443*1959748cSgd78059 uint16_t anar; 1444*1959748cSgd78059 uint16_t anlpar; 1445*1959748cSgd78059 int reinit = 0; 1446*1959748cSgd78059 1447*1959748cSgd78059 /* read this twice, to clear latched link state */ 1448*1959748cSgd78059 bmsr = afe_miiread(afep, afep->afe_phyaddr, MII_STATUS); 1449*1959748cSgd78059 bmsr = afe_miiread(afep, afep->afe_phyaddr, MII_STATUS); 1450*1959748cSgd78059 bmcr = afe_miiread(afep, afep->afe_phyaddr, MII_CONTROL); 1451*1959748cSgd78059 anar = afe_miiread(afep, afep->afe_phyaddr, MII_AN_ADVERT); 1452*1959748cSgd78059 anlpar = afe_miiread(afep, afep->afe_phyaddr, MII_AN_LPABLE); 1453*1959748cSgd78059 1454*1959748cSgd78059 if (bmsr & MII_STATUS_REMFAULT) { 1455*1959748cSgd78059 afe_error(afep->afe_dip, "Remote fault detected."); 1456*1959748cSgd78059 } 1457*1959748cSgd78059 if (bmsr & MII_STATUS_JABBERING) { 1458*1959748cSgd78059 afe_error(afep->afe_dip, "Jabber condition detected."); 1459*1959748cSgd78059 } 1460*1959748cSgd78059 if ((bmsr & MII_STATUS_LINKUP) == 0) { 1461*1959748cSgd78059 /* no link */ 1462*1959748cSgd78059 if (afep->afe_linkup) { 1463*1959748cSgd78059 reinit = 1; 1464*1959748cSgd78059 } 1465*1959748cSgd78059 afep->afe_ifspeed = 0; 1466*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1467*1959748cSgd78059 afep->afe_linkup = LINK_STATE_DOWN; 1468*1959748cSgd78059 afe_reportlink(afep); 1469*1959748cSgd78059 if (reinit) { 1470*1959748cSgd78059 afe_startphy(afep); 1471*1959748cSgd78059 } 1472*1959748cSgd78059 return; 1473*1959748cSgd78059 } 1474*1959748cSgd78059 1475*1959748cSgd78059 DBG(DCHATTY, "link up!"); 1476*1959748cSgd78059 afep->afe_linkup = LINK_STATE_UP; 1477*1959748cSgd78059 1478*1959748cSgd78059 if (!(bmcr & MII_CONTROL_ANE)) { 1479*1959748cSgd78059 /* forced mode */ 1480*1959748cSgd78059 if (bmcr & MII_CONTROL_100MB) { 1481*1959748cSgd78059 afep->afe_ifspeed = 100000000; 1482*1959748cSgd78059 } else { 1483*1959748cSgd78059 afep->afe_ifspeed = 10000000; 1484*1959748cSgd78059 } 1485*1959748cSgd78059 if (bmcr & MII_CONTROL_FDUPLEX) { 1486*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_FULL; 1487*1959748cSgd78059 } else { 1488*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1489*1959748cSgd78059 } 1490*1959748cSgd78059 } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) || 1491*1959748cSgd78059 (!(bmsr & MII_STATUS_ANDONE))) { 1492*1959748cSgd78059 afep->afe_ifspeed = 0; 1493*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1494*1959748cSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) { 1495*1959748cSgd78059 afep->afe_ifspeed = 100000000; 1496*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_FULL; 1497*1959748cSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_T4) { 1498*1959748cSgd78059 afep->afe_ifspeed = 100000000; 1499*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1500*1959748cSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX) { 1501*1959748cSgd78059 afep->afe_ifspeed = 100000000; 1502*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1503*1959748cSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) { 1504*1959748cSgd78059 afep->afe_ifspeed = 10000000; 1505*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_FULL; 1506*1959748cSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T) { 1507*1959748cSgd78059 afep->afe_ifspeed = 10000000; 1508*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_HALF; 1509*1959748cSgd78059 } else { 1510*1959748cSgd78059 afep->afe_ifspeed = 0; 1511*1959748cSgd78059 afep->afe_duplex = LINK_DUPLEX_UNKNOWN; 1512*1959748cSgd78059 } 1513*1959748cSgd78059 1514*1959748cSgd78059 afe_reportlink(afep); 1515*1959748cSgd78059 } 1516*1959748cSgd78059 1517*1959748cSgd78059 void 1518*1959748cSgd78059 afe_miitristate(afe_t *afep) 1519*1959748cSgd78059 { 1520*1959748cSgd78059 unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL; 1521*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 1522*1959748cSgd78059 drv_usecwait(1); 1523*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 1524*1959748cSgd78059 drv_usecwait(1); 1525*1959748cSgd78059 } 1526*1959748cSgd78059 1527*1959748cSgd78059 void 1528*1959748cSgd78059 afe_miiwritebit(afe_t *afep, int bit) 1529*1959748cSgd78059 { 1530*1959748cSgd78059 unsigned val = bit ? SPR_MII_DOUT : 0; 1531*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 1532*1959748cSgd78059 drv_usecwait(1); 1533*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 1534*1959748cSgd78059 drv_usecwait(1); 1535*1959748cSgd78059 } 1536*1959748cSgd78059 1537*1959748cSgd78059 int 1538*1959748cSgd78059 afe_miireadbit(afe_t *afep) 1539*1959748cSgd78059 { 1540*1959748cSgd78059 unsigned val = SPR_MII_CTRL | SPR_SROM_READ; 1541*1959748cSgd78059 int bit; 1542*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 1543*1959748cSgd78059 drv_usecwait(1); 1544*1959748cSgd78059 bit = (GETCSR(afep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0; 1545*1959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 1546*1959748cSgd78059 drv_usecwait(1); 1547*1959748cSgd78059 return (bit); 1548*1959748cSgd78059 } 1549*1959748cSgd78059 1550*1959748cSgd78059 unsigned 1551*1959748cSgd78059 afe_miiread(afe_t *afep, int phy, int reg) 1552*1959748cSgd78059 { 1553*1959748cSgd78059 /* 1554*1959748cSgd78059 * ADMtek bugs ignore address decode bits -- they only 1555*1959748cSgd78059 * support PHY at 1. 1556*1959748cSgd78059 */ 1557*1959748cSgd78059 if (phy != 1) { 1558*1959748cSgd78059 return (0xffff); 1559*1959748cSgd78059 } 1560*1959748cSgd78059 switch (AFE_MODEL(afep)) { 1561*1959748cSgd78059 case MODEL_COMET: 1562*1959748cSgd78059 return (afe_miireadcomet(afep, phy, reg)); 1563*1959748cSgd78059 case MODEL_CENTAUR: 1564*1959748cSgd78059 return (afe_miireadgeneral(afep, phy, reg)); 1565*1959748cSgd78059 } 1566*1959748cSgd78059 return (0xffff); 1567*1959748cSgd78059 } 1568*1959748cSgd78059 1569*1959748cSgd78059 unsigned 1570*1959748cSgd78059 afe_miireadgeneral(afe_t *afep, int phy, int reg) 1571*1959748cSgd78059 { 1572*1959748cSgd78059 unsigned value = 0; 1573*1959748cSgd78059 int i; 1574*1959748cSgd78059 1575*1959748cSgd78059 /* send the 32 bit preamble */ 1576*1959748cSgd78059 for (i = 0; i < 32; i++) { 1577*1959748cSgd78059 afe_miiwritebit(afep, 1); 1578*1959748cSgd78059 } 1579*1959748cSgd78059 1580*1959748cSgd78059 /* send the start code - 01b */ 1581*1959748cSgd78059 afe_miiwritebit(afep, 0); 1582*1959748cSgd78059 afe_miiwritebit(afep, 1); 1583*1959748cSgd78059 1584*1959748cSgd78059 /* send the opcode for read, - 10b */ 1585*1959748cSgd78059 afe_miiwritebit(afep, 1); 1586*1959748cSgd78059 afe_miiwritebit(afep, 0); 1587*1959748cSgd78059 1588*1959748cSgd78059 /* next we send the 5 bit phy address */ 1589*1959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 1590*1959748cSgd78059 afe_miiwritebit(afep, (phy & i) ? 1 : 0); 1591*1959748cSgd78059 } 1592*1959748cSgd78059 1593*1959748cSgd78059 /* the 5 bit register address goes next */ 1594*1959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 1595*1959748cSgd78059 afe_miiwritebit(afep, (reg & i) ? 1 : 0); 1596*1959748cSgd78059 } 1597*1959748cSgd78059 1598*1959748cSgd78059 /* turnaround - tristate followed by logic 0 */ 1599*1959748cSgd78059 afe_miitristate(afep); 1600*1959748cSgd78059 afe_miiwritebit(afep, 0); 1601*1959748cSgd78059 1602*1959748cSgd78059 /* read the 16 bit register value */ 1603*1959748cSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 1604*1959748cSgd78059 value <<= 1; 1605*1959748cSgd78059 value |= afe_miireadbit(afep); 1606*1959748cSgd78059 } 1607*1959748cSgd78059 afe_miitristate(afep); 1608*1959748cSgd78059 return (value); 1609*1959748cSgd78059 } 1610*1959748cSgd78059 1611*1959748cSgd78059 unsigned 1612*1959748cSgd78059 afe_miireadcomet(afe_t *afep, int phy, int reg) 1613*1959748cSgd78059 { 1614*1959748cSgd78059 if (phy != 1) { 1615*1959748cSgd78059 return (0xffff); 1616*1959748cSgd78059 } 1617*1959748cSgd78059 switch (reg) { 1618*1959748cSgd78059 case MII_CONTROL: 1619*1959748cSgd78059 reg = CSR_BMCR; 1620*1959748cSgd78059 break; 1621*1959748cSgd78059 case MII_STATUS: 1622*1959748cSgd78059 reg = CSR_BMSR; 1623*1959748cSgd78059 break; 1624*1959748cSgd78059 case MII_PHYIDH: 1625*1959748cSgd78059 reg = CSR_PHYIDR1; 1626*1959748cSgd78059 break; 1627*1959748cSgd78059 case MII_PHYIDL: 1628*1959748cSgd78059 reg = CSR_PHYIDR2; 1629*1959748cSgd78059 break; 1630*1959748cSgd78059 case MII_AN_ADVERT: 1631*1959748cSgd78059 reg = CSR_ANAR; 1632*1959748cSgd78059 break; 1633*1959748cSgd78059 case MII_AN_LPABLE: 1634*1959748cSgd78059 reg = CSR_ANLPAR; 1635*1959748cSgd78059 break; 1636*1959748cSgd78059 case MII_AN_EXPANSION: 1637*1959748cSgd78059 reg = CSR_ANER; 1638*1959748cSgd78059 break; 1639*1959748cSgd78059 default: 1640*1959748cSgd78059 return (0); 1641*1959748cSgd78059 } 1642*1959748cSgd78059 return (GETCSR16(afep, reg) & 0xFFFF); 1643*1959748cSgd78059 } 1644*1959748cSgd78059 1645*1959748cSgd78059 void 1646*1959748cSgd78059 afe_miiwrite(afe_t *afep, int phy, int reg, uint16_t val) 1647*1959748cSgd78059 { 1648*1959748cSgd78059 /* 1649*1959748cSgd78059 * ADMtek bugs ignore address decode bits -- they only 1650*1959748cSgd78059 * support PHY at 1. 1651*1959748cSgd78059 */ 1652*1959748cSgd78059 if (phy != 1) { 1653*1959748cSgd78059 return; 1654*1959748cSgd78059 } 1655*1959748cSgd78059 switch (AFE_MODEL(afep)) { 1656*1959748cSgd78059 case MODEL_COMET: 1657*1959748cSgd78059 afe_miiwritecomet(afep, phy, reg, val); 1658*1959748cSgd78059 break; 1659*1959748cSgd78059 case MODEL_CENTAUR: 1660*1959748cSgd78059 afe_miiwritegeneral(afep, phy, reg, val); 1661*1959748cSgd78059 break; 1662*1959748cSgd78059 } 1663*1959748cSgd78059 } 1664*1959748cSgd78059 1665*1959748cSgd78059 void 1666*1959748cSgd78059 afe_miiwritegeneral(afe_t *afep, int phy, int reg, uint16_t val) 1667*1959748cSgd78059 { 1668*1959748cSgd78059 int i; 1669*1959748cSgd78059 1670*1959748cSgd78059 /* send the 32 bit preamble */ 1671*1959748cSgd78059 for (i = 0; i < 32; i++) { 1672*1959748cSgd78059 afe_miiwritebit(afep, 1); 1673*1959748cSgd78059 } 1674*1959748cSgd78059 1675*1959748cSgd78059 /* send the start code - 01b */ 1676*1959748cSgd78059 afe_miiwritebit(afep, 0); 1677*1959748cSgd78059 afe_miiwritebit(afep, 1); 1678*1959748cSgd78059 1679*1959748cSgd78059 /* send the opcode for write, - 01b */ 1680*1959748cSgd78059 afe_miiwritebit(afep, 0); 1681*1959748cSgd78059 afe_miiwritebit(afep, 1); 1682*1959748cSgd78059 1683*1959748cSgd78059 /* next we send the 5 bit phy address */ 1684*1959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 1685*1959748cSgd78059 afe_miiwritebit(afep, (phy & i) ? 1 : 0); 1686*1959748cSgd78059 } 1687*1959748cSgd78059 1688*1959748cSgd78059 /* the 5 bit register address goes next */ 1689*1959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 1690*1959748cSgd78059 afe_miiwritebit(afep, (reg & i) ? 1 : 0); 1691*1959748cSgd78059 } 1692*1959748cSgd78059 1693*1959748cSgd78059 /* turnaround - tristate followed by logic 0 */ 1694*1959748cSgd78059 afe_miitristate(afep); 1695*1959748cSgd78059 afe_miiwritebit(afep, 0); 1696*1959748cSgd78059 1697*1959748cSgd78059 /* now write out our data (16 bits) */ 1698*1959748cSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 1699*1959748cSgd78059 afe_miiwritebit(afep, (val & i) ? 1 : 0); 1700*1959748cSgd78059 } 1701*1959748cSgd78059 1702*1959748cSgd78059 /* idle mode */ 1703*1959748cSgd78059 afe_miitristate(afep); 1704*1959748cSgd78059 } 1705*1959748cSgd78059 1706*1959748cSgd78059 void 1707*1959748cSgd78059 afe_miiwritecomet(afe_t *afep, int phy, int reg, uint16_t val) 1708*1959748cSgd78059 { 1709*1959748cSgd78059 if (phy != 1) { 1710*1959748cSgd78059 return; 1711*1959748cSgd78059 } 1712*1959748cSgd78059 switch (reg) { 1713*1959748cSgd78059 case MII_CONTROL: 1714*1959748cSgd78059 reg = CSR_BMCR; 1715*1959748cSgd78059 break; 1716*1959748cSgd78059 case MII_STATUS: 1717*1959748cSgd78059 reg = CSR_BMSR; 1718*1959748cSgd78059 break; 1719*1959748cSgd78059 case MII_PHYIDH: 1720*1959748cSgd78059 reg = CSR_PHYIDR1; 1721*1959748cSgd78059 break; 1722*1959748cSgd78059 case MII_PHYIDL: 1723*1959748cSgd78059 reg = CSR_PHYIDR2; 1724*1959748cSgd78059 break; 1725*1959748cSgd78059 case MII_AN_ADVERT: 1726*1959748cSgd78059 reg = CSR_ANAR; 1727*1959748cSgd78059 break; 1728*1959748cSgd78059 case MII_AN_LPABLE: 1729*1959748cSgd78059 reg = CSR_ANLPAR; 1730*1959748cSgd78059 break; 1731*1959748cSgd78059 case MII_AN_EXPANSION: 1732*1959748cSgd78059 reg = CSR_ANER; 1733*1959748cSgd78059 break; 1734*1959748cSgd78059 default: 1735*1959748cSgd78059 return; 1736*1959748cSgd78059 } 1737*1959748cSgd78059 PUTCSR16(afep, reg, val); 1738*1959748cSgd78059 } 1739*1959748cSgd78059 1740*1959748cSgd78059 int 1741*1959748cSgd78059 afe_m_start(void *arg) 1742*1959748cSgd78059 { 1743*1959748cSgd78059 afe_t *afep = arg; 1744*1959748cSgd78059 1745*1959748cSgd78059 /* grab exclusive access to the card */ 1746*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 1747*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 1748*1959748cSgd78059 1749*1959748cSgd78059 afe_startall(afep); 1750*1959748cSgd78059 afep->afe_flags |= AFE_RUNNING; 1751*1959748cSgd78059 1752*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 1753*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 1754*1959748cSgd78059 return (0); 1755*1959748cSgd78059 } 1756*1959748cSgd78059 1757*1959748cSgd78059 void 1758*1959748cSgd78059 afe_m_stop(void *arg) 1759*1959748cSgd78059 { 1760*1959748cSgd78059 afe_t *afep = arg; 1761*1959748cSgd78059 1762*1959748cSgd78059 /* exclusive access to the hardware! */ 1763*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 1764*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 1765*1959748cSgd78059 1766*1959748cSgd78059 afe_stopall(afep); 1767*1959748cSgd78059 afep->afe_flags &= ~AFE_RUNNING; 1768*1959748cSgd78059 1769*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 1770*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 1771*1959748cSgd78059 } 1772*1959748cSgd78059 1773*1959748cSgd78059 void 1774*1959748cSgd78059 afe_startmac(afe_t *afep) 1775*1959748cSgd78059 { 1776*1959748cSgd78059 /* verify exclusive access to the card */ 1777*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 1778*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 1779*1959748cSgd78059 1780*1959748cSgd78059 /* start the card */ 1781*1959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 1782*1959748cSgd78059 1783*1959748cSgd78059 if (afep->afe_txavail != AFE_TXRING) 1784*1959748cSgd78059 PUTCSR(afep, CSR_TDR, 0); 1785*1959748cSgd78059 1786*1959748cSgd78059 /* tell the mac that we are ready to go! */ 1787*1959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) 1788*1959748cSgd78059 mac_tx_update(afep->afe_mh); 1789*1959748cSgd78059 } 1790*1959748cSgd78059 1791*1959748cSgd78059 void 1792*1959748cSgd78059 afe_stopmac(afe_t *afep) 1793*1959748cSgd78059 { 1794*1959748cSgd78059 int i; 1795*1959748cSgd78059 1796*1959748cSgd78059 /* exclusive access to the hardware! */ 1797*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 1798*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 1799*1959748cSgd78059 1800*1959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 1801*1959748cSgd78059 1802*1959748cSgd78059 /* 1803*1959748cSgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain. 1804*1959748cSgd78059 * We just add up to the nearest msec (2), which should be 1805*1959748cSgd78059 * plenty to complete. 1806*1959748cSgd78059 * 1807*1959748cSgd78059 * Note that some chips never seem to indicate the transition to 1808*1959748cSgd78059 * the stopped state properly. Experience shows that we can safely 1809*1959748cSgd78059 * proceed anyway, after waiting the requisite timeout. 1810*1959748cSgd78059 */ 1811*1959748cSgd78059 for (i = 2000; i != 0; i -= 10) { 1812*1959748cSgd78059 if ((GETCSR(afep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0) 1813*1959748cSgd78059 break; 1814*1959748cSgd78059 drv_usecwait(10); 1815*1959748cSgd78059 } 1816*1959748cSgd78059 1817*1959748cSgd78059 /* prevent an interrupt */ 1818*1959748cSgd78059 PUTCSR(afep, CSR_SR2, INT_RXSTOPPED | INT_TXSTOPPED); 1819*1959748cSgd78059 } 1820*1959748cSgd78059 1821*1959748cSgd78059 void 1822*1959748cSgd78059 afe_resetrings(afe_t *afep) 1823*1959748cSgd78059 { 1824*1959748cSgd78059 int i; 1825*1959748cSgd78059 1826*1959748cSgd78059 /* now we need to reset the pointers... */ 1827*1959748cSgd78059 PUTCSR(afep, CSR_RDB, 0); 1828*1959748cSgd78059 PUTCSR(afep, CSR_TDB, 0); 1829*1959748cSgd78059 1830*1959748cSgd78059 /* reset the descriptor ring pointers */ 1831*1959748cSgd78059 afep->afe_rxhead = 0; 1832*1959748cSgd78059 afep->afe_txreclaim = 0; 1833*1959748cSgd78059 afep->afe_txsend = 0; 1834*1959748cSgd78059 afep->afe_txavail = AFE_TXRING; 1835*1959748cSgd78059 1836*1959748cSgd78059 /* set up transmit descriptor ring */ 1837*1959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 1838*1959748cSgd78059 afe_desc_t *tmdp = &afep->afe_txdescp[i]; 1839*1959748cSgd78059 unsigned control = 0; 1840*1959748cSgd78059 if (i == (AFE_TXRING - 1)) { 1841*1959748cSgd78059 control |= TXCTL_ENDRING; 1842*1959748cSgd78059 } 1843*1959748cSgd78059 PUTTXDESC(afep, tmdp->desc_status, 0); 1844*1959748cSgd78059 PUTTXDESC(afep, tmdp->desc_control, control); 1845*1959748cSgd78059 PUTTXDESC(afep, tmdp->desc_buffer1, 0); 1846*1959748cSgd78059 PUTTXDESC(afep, tmdp->desc_buffer2, 0); 1847*1959748cSgd78059 SYNCTXDESC(afep, i, DDI_DMA_SYNC_FORDEV); 1848*1959748cSgd78059 } 1849*1959748cSgd78059 PUTCSR(afep, CSR_TDB, afep->afe_txdesc_paddr); 1850*1959748cSgd78059 1851*1959748cSgd78059 /* make the receive buffers available */ 1852*1959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 1853*1959748cSgd78059 afe_rxbuf_t *rxb = afep->afe_rxbufs[i]; 1854*1959748cSgd78059 afe_desc_t *rmdp = &afep->afe_rxdescp[i]; 1855*1959748cSgd78059 unsigned control; 1856*1959748cSgd78059 1857*1959748cSgd78059 control = AFE_BUFSZ & RXCTL_BUFLEN1; 1858*1959748cSgd78059 if (i == (AFE_RXRING - 1)) { 1859*1959748cSgd78059 control |= RXCTL_ENDRING; 1860*1959748cSgd78059 } 1861*1959748cSgd78059 PUTRXDESC(afep, rmdp->desc_buffer1, rxb->rxb_paddr); 1862*1959748cSgd78059 PUTRXDESC(afep, rmdp->desc_buffer2, 0); 1863*1959748cSgd78059 PUTRXDESC(afep, rmdp->desc_control, control); 1864*1959748cSgd78059 PUTRXDESC(afep, rmdp->desc_status, RXSTAT_OWN); 1865*1959748cSgd78059 SYNCRXDESC(afep, i, DDI_DMA_SYNC_FORDEV); 1866*1959748cSgd78059 } 1867*1959748cSgd78059 PUTCSR(afep, CSR_RDB, afep->afe_rxdesc_paddr); 1868*1959748cSgd78059 } 1869*1959748cSgd78059 1870*1959748cSgd78059 void 1871*1959748cSgd78059 afe_stopall(afe_t *afep) 1872*1959748cSgd78059 { 1873*1959748cSgd78059 afe_disableinterrupts(afep); 1874*1959748cSgd78059 1875*1959748cSgd78059 afe_stopmac(afep); 1876*1959748cSgd78059 1877*1959748cSgd78059 /* stop the phy */ 1878*1959748cSgd78059 afe_stopphy(afep); 1879*1959748cSgd78059 } 1880*1959748cSgd78059 1881*1959748cSgd78059 void 1882*1959748cSgd78059 afe_startall(afe_t *afep) 1883*1959748cSgd78059 { 1884*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 1885*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 1886*1959748cSgd78059 1887*1959748cSgd78059 /* make sure interrupts are disabled to begin */ 1888*1959748cSgd78059 afe_disableinterrupts(afep); 1889*1959748cSgd78059 1890*1959748cSgd78059 /* initialize the chip */ 1891*1959748cSgd78059 (void) afe_initialize(afep); 1892*1959748cSgd78059 1893*1959748cSgd78059 /* now we can enable interrupts */ 1894*1959748cSgd78059 afe_enableinterrupts(afep); 1895*1959748cSgd78059 1896*1959748cSgd78059 /* start up the phy */ 1897*1959748cSgd78059 afe_startphy(afep); 1898*1959748cSgd78059 1899*1959748cSgd78059 /* start up the mac */ 1900*1959748cSgd78059 afe_startmac(afep); 1901*1959748cSgd78059 } 1902*1959748cSgd78059 1903*1959748cSgd78059 void 1904*1959748cSgd78059 afe_resetall(afe_t *afep) 1905*1959748cSgd78059 { 1906*1959748cSgd78059 afep->afe_resetting = B_TRUE; 1907*1959748cSgd78059 afe_stopall(afep); 1908*1959748cSgd78059 afep->afe_resetting = B_FALSE; 1909*1959748cSgd78059 afe_startall(afep); 1910*1959748cSgd78059 } 1911*1959748cSgd78059 1912*1959748cSgd78059 afe_txbuf_t * 1913*1959748cSgd78059 afe_alloctxbuf(afe_t *afep) 1914*1959748cSgd78059 { 1915*1959748cSgd78059 ddi_dma_cookie_t dmac; 1916*1959748cSgd78059 unsigned ncookies; 1917*1959748cSgd78059 afe_txbuf_t *txb; 1918*1959748cSgd78059 size_t len; 1919*1959748cSgd78059 1920*1959748cSgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP); 1921*1959748cSgd78059 1922*1959748cSgd78059 if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_txattr, 1923*1959748cSgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) { 1924*1959748cSgd78059 return (NULL); 1925*1959748cSgd78059 } 1926*1959748cSgd78059 1927*1959748cSgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, AFE_BUFSZ, &afe_bufattr, 1928*1959748cSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, &len, 1929*1959748cSgd78059 &txb->txb_acch) != DDI_SUCCESS) { 1930*1959748cSgd78059 return (NULL); 1931*1959748cSgd78059 } 1932*1959748cSgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf, 1933*1959748cSgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 1934*1959748cSgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) { 1935*1959748cSgd78059 return (NULL); 1936*1959748cSgd78059 } 1937*1959748cSgd78059 txb->txb_paddr = dmac.dmac_address; 1938*1959748cSgd78059 1939*1959748cSgd78059 return (txb); 1940*1959748cSgd78059 } 1941*1959748cSgd78059 1942*1959748cSgd78059 void 1943*1959748cSgd78059 afe_destroytxbuf(afe_txbuf_t *txb) 1944*1959748cSgd78059 { 1945*1959748cSgd78059 if (txb != NULL) { 1946*1959748cSgd78059 if (txb->txb_paddr) 1947*1959748cSgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah); 1948*1959748cSgd78059 if (txb->txb_acch) 1949*1959748cSgd78059 ddi_dma_mem_free(&txb->txb_acch); 1950*1959748cSgd78059 if (txb->txb_dmah) 1951*1959748cSgd78059 ddi_dma_free_handle(&txb->txb_dmah); 1952*1959748cSgd78059 kmem_free(txb, sizeof (*txb)); 1953*1959748cSgd78059 } 1954*1959748cSgd78059 } 1955*1959748cSgd78059 1956*1959748cSgd78059 afe_rxbuf_t * 1957*1959748cSgd78059 afe_allocrxbuf(afe_t *afep) 1958*1959748cSgd78059 { 1959*1959748cSgd78059 afe_rxbuf_t *rxb; 1960*1959748cSgd78059 size_t len; 1961*1959748cSgd78059 unsigned ccnt; 1962*1959748cSgd78059 ddi_dma_cookie_t dmac; 1963*1959748cSgd78059 1964*1959748cSgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP); 1965*1959748cSgd78059 1966*1959748cSgd78059 if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 1967*1959748cSgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) { 1968*1959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 1969*1959748cSgd78059 return (NULL); 1970*1959748cSgd78059 } 1971*1959748cSgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, AFE_BUFSZ, &afe_bufattr, 1972*1959748cSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &rxb->rxb_buf, &len, 1973*1959748cSgd78059 &rxb->rxb_acch) != DDI_SUCCESS) { 1974*1959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 1975*1959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 1976*1959748cSgd78059 return (NULL); 1977*1959748cSgd78059 } 1978*1959748cSgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len, 1979*1959748cSgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac, 1980*1959748cSgd78059 &ccnt) != DDI_DMA_MAPPED) { 1981*1959748cSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 1982*1959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 1983*1959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 1984*1959748cSgd78059 return (NULL); 1985*1959748cSgd78059 } 1986*1959748cSgd78059 rxb->rxb_paddr = dmac.dmac_address; 1987*1959748cSgd78059 1988*1959748cSgd78059 return (rxb); 1989*1959748cSgd78059 } 1990*1959748cSgd78059 1991*1959748cSgd78059 void 1992*1959748cSgd78059 afe_destroyrxbuf(afe_rxbuf_t *rxb) 1993*1959748cSgd78059 { 1994*1959748cSgd78059 if (rxb) { 1995*1959748cSgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah); 1996*1959748cSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 1997*1959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 1998*1959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 1999*1959748cSgd78059 } 2000*1959748cSgd78059 } 2001*1959748cSgd78059 2002*1959748cSgd78059 /* 2003*1959748cSgd78059 * Allocate receive resources. 2004*1959748cSgd78059 */ 2005*1959748cSgd78059 int 2006*1959748cSgd78059 afe_allocrxring(afe_t *afep) 2007*1959748cSgd78059 { 2008*1959748cSgd78059 int rval; 2009*1959748cSgd78059 int i; 2010*1959748cSgd78059 size_t size; 2011*1959748cSgd78059 size_t len; 2012*1959748cSgd78059 ddi_dma_cookie_t dmac; 2013*1959748cSgd78059 unsigned ncookies; 2014*1959748cSgd78059 caddr_t kaddr; 2015*1959748cSgd78059 2016*1959748cSgd78059 size = AFE_RXRING * sizeof (afe_desc_t); 2017*1959748cSgd78059 2018*1959748cSgd78059 rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 2019*1959748cSgd78059 DDI_DMA_SLEEP, NULL, &afep->afe_rxdesc_dmah); 2020*1959748cSgd78059 if (rval != DDI_SUCCESS) { 2021*1959748cSgd78059 afe_error(afep->afe_dip, 2022*1959748cSgd78059 "unable to allocate DMA handle for rx descriptors"); 2023*1959748cSgd78059 return (DDI_FAILURE); 2024*1959748cSgd78059 } 2025*1959748cSgd78059 2026*1959748cSgd78059 rval = ddi_dma_mem_alloc(afep->afe_rxdesc_dmah, size, &afe_devattr, 2027*1959748cSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 2028*1959748cSgd78059 &afep->afe_rxdesc_acch); 2029*1959748cSgd78059 if (rval != DDI_SUCCESS) { 2030*1959748cSgd78059 afe_error(afep->afe_dip, 2031*1959748cSgd78059 "unable to allocate DMA memory for rx descriptors"); 2032*1959748cSgd78059 return (DDI_FAILURE); 2033*1959748cSgd78059 } 2034*1959748cSgd78059 2035*1959748cSgd78059 rval = ddi_dma_addr_bind_handle(afep->afe_rxdesc_dmah, NULL, kaddr, 2036*1959748cSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 2037*1959748cSgd78059 &dmac, &ncookies); 2038*1959748cSgd78059 if (rval != DDI_DMA_MAPPED) { 2039*1959748cSgd78059 afe_error(afep->afe_dip, 2040*1959748cSgd78059 "unable to bind DMA for rx descriptors"); 2041*1959748cSgd78059 return (DDI_FAILURE); 2042*1959748cSgd78059 } 2043*1959748cSgd78059 2044*1959748cSgd78059 /* because of afe_dma_attr */ 2045*1959748cSgd78059 ASSERT(ncookies == 1); 2046*1959748cSgd78059 2047*1959748cSgd78059 /* we take the 32-bit physical address out of the cookie */ 2048*1959748cSgd78059 afep->afe_rxdesc_paddr = dmac.dmac_address; 2049*1959748cSgd78059 afep->afe_rxdescp = (void *)kaddr; 2050*1959748cSgd78059 2051*1959748cSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 2052*1959748cSgd78059 afep->afe_rxbufs = kmem_zalloc(AFE_RXRING * sizeof (afe_rxbuf_t *), 2053*1959748cSgd78059 KM_SLEEP); 2054*1959748cSgd78059 2055*1959748cSgd78059 /* now allocate rx buffers */ 2056*1959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 2057*1959748cSgd78059 afe_rxbuf_t *rxb = afe_allocrxbuf(afep); 2058*1959748cSgd78059 if (rxb == NULL) 2059*1959748cSgd78059 return (DDI_FAILURE); 2060*1959748cSgd78059 afep->afe_rxbufs[i] = rxb; 2061*1959748cSgd78059 } 2062*1959748cSgd78059 2063*1959748cSgd78059 return (DDI_SUCCESS); 2064*1959748cSgd78059 } 2065*1959748cSgd78059 2066*1959748cSgd78059 /* 2067*1959748cSgd78059 * Allocate transmit resources. 2068*1959748cSgd78059 */ 2069*1959748cSgd78059 int 2070*1959748cSgd78059 afe_alloctxring(afe_t *afep) 2071*1959748cSgd78059 { 2072*1959748cSgd78059 int rval; 2073*1959748cSgd78059 int i; 2074*1959748cSgd78059 size_t size; 2075*1959748cSgd78059 size_t len; 2076*1959748cSgd78059 ddi_dma_cookie_t dmac; 2077*1959748cSgd78059 unsigned ncookies; 2078*1959748cSgd78059 caddr_t kaddr; 2079*1959748cSgd78059 2080*1959748cSgd78059 size = AFE_TXRING * sizeof (afe_desc_t); 2081*1959748cSgd78059 2082*1959748cSgd78059 rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 2083*1959748cSgd78059 DDI_DMA_SLEEP, NULL, &afep->afe_txdesc_dmah); 2084*1959748cSgd78059 if (rval != DDI_SUCCESS) { 2085*1959748cSgd78059 afe_error(afep->afe_dip, 2086*1959748cSgd78059 "unable to allocate DMA handle for tx descriptors"); 2087*1959748cSgd78059 return (DDI_FAILURE); 2088*1959748cSgd78059 } 2089*1959748cSgd78059 2090*1959748cSgd78059 rval = ddi_dma_mem_alloc(afep->afe_txdesc_dmah, size, &afe_devattr, 2091*1959748cSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 2092*1959748cSgd78059 &afep->afe_txdesc_acch); 2093*1959748cSgd78059 if (rval != DDI_SUCCESS) { 2094*1959748cSgd78059 afe_error(afep->afe_dip, 2095*1959748cSgd78059 "unable to allocate DMA memory for tx descriptors"); 2096*1959748cSgd78059 return (DDI_FAILURE); 2097*1959748cSgd78059 } 2098*1959748cSgd78059 2099*1959748cSgd78059 rval = ddi_dma_addr_bind_handle(afep->afe_txdesc_dmah, NULL, kaddr, 2100*1959748cSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 2101*1959748cSgd78059 &dmac, &ncookies); 2102*1959748cSgd78059 if (rval != DDI_DMA_MAPPED) { 2103*1959748cSgd78059 afe_error(afep->afe_dip, 2104*1959748cSgd78059 "unable to bind DMA for tx descriptors"); 2105*1959748cSgd78059 return (DDI_FAILURE); 2106*1959748cSgd78059 } 2107*1959748cSgd78059 2108*1959748cSgd78059 /* because of afe_dma_attr */ 2109*1959748cSgd78059 ASSERT(ncookies == 1); 2110*1959748cSgd78059 2111*1959748cSgd78059 /* we take the 32-bit physical address out of the cookie */ 2112*1959748cSgd78059 afep->afe_txdesc_paddr = dmac.dmac_address; 2113*1959748cSgd78059 afep->afe_txdescp = (void *)kaddr; 2114*1959748cSgd78059 2115*1959748cSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 2116*1959748cSgd78059 afep->afe_txbufs = kmem_zalloc(AFE_TXRING * sizeof (afe_txbuf_t *), 2117*1959748cSgd78059 KM_SLEEP); 2118*1959748cSgd78059 2119*1959748cSgd78059 /* now allocate tx buffers */ 2120*1959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 2121*1959748cSgd78059 afe_txbuf_t *txb = afe_alloctxbuf(afep); 2122*1959748cSgd78059 if (txb == NULL) 2123*1959748cSgd78059 return (DDI_FAILURE); 2124*1959748cSgd78059 afep->afe_txbufs[i] = txb; 2125*1959748cSgd78059 } 2126*1959748cSgd78059 2127*1959748cSgd78059 return (DDI_SUCCESS); 2128*1959748cSgd78059 } 2129*1959748cSgd78059 2130*1959748cSgd78059 void 2131*1959748cSgd78059 afe_freerxring(afe_t *afep) 2132*1959748cSgd78059 { 2133*1959748cSgd78059 int i; 2134*1959748cSgd78059 2135*1959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 2136*1959748cSgd78059 afe_destroyrxbuf(afep->afe_rxbufs[i]); 2137*1959748cSgd78059 } 2138*1959748cSgd78059 2139*1959748cSgd78059 if (afep->afe_rxbufs) { 2140*1959748cSgd78059 kmem_free(afep->afe_rxbufs, 2141*1959748cSgd78059 AFE_RXRING * sizeof (afe_rxbuf_t *)); 2142*1959748cSgd78059 } 2143*1959748cSgd78059 2144*1959748cSgd78059 if (afep->afe_rxdesc_paddr) 2145*1959748cSgd78059 (void) ddi_dma_unbind_handle(afep->afe_rxdesc_dmah); 2146*1959748cSgd78059 if (afep->afe_rxdesc_acch) 2147*1959748cSgd78059 ddi_dma_mem_free(&afep->afe_rxdesc_acch); 2148*1959748cSgd78059 if (afep->afe_rxdesc_dmah) 2149*1959748cSgd78059 ddi_dma_free_handle(&afep->afe_rxdesc_dmah); 2150*1959748cSgd78059 } 2151*1959748cSgd78059 2152*1959748cSgd78059 void 2153*1959748cSgd78059 afe_freetxring(afe_t *afep) 2154*1959748cSgd78059 { 2155*1959748cSgd78059 int i; 2156*1959748cSgd78059 2157*1959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 2158*1959748cSgd78059 afe_destroytxbuf(afep->afe_txbufs[i]); 2159*1959748cSgd78059 } 2160*1959748cSgd78059 2161*1959748cSgd78059 if (afep->afe_txbufs) { 2162*1959748cSgd78059 kmem_free(afep->afe_txbufs, 2163*1959748cSgd78059 AFE_TXRING * sizeof (afe_txbuf_t *)); 2164*1959748cSgd78059 } 2165*1959748cSgd78059 if (afep->afe_txdesc_paddr) 2166*1959748cSgd78059 (void) ddi_dma_unbind_handle(afep->afe_txdesc_dmah); 2167*1959748cSgd78059 if (afep->afe_txdesc_acch) 2168*1959748cSgd78059 ddi_dma_mem_free(&afep->afe_txdesc_acch); 2169*1959748cSgd78059 if (afep->afe_txdesc_dmah) 2170*1959748cSgd78059 ddi_dma_free_handle(&afep->afe_txdesc_dmah); 2171*1959748cSgd78059 } 2172*1959748cSgd78059 2173*1959748cSgd78059 /* 2174*1959748cSgd78059 * Interrupt service routine. 2175*1959748cSgd78059 */ 2176*1959748cSgd78059 unsigned 2177*1959748cSgd78059 afe_intr(caddr_t arg) 2178*1959748cSgd78059 { 2179*1959748cSgd78059 afe_t *afep = (void *)arg; 2180*1959748cSgd78059 uint32_t status; 2181*1959748cSgd78059 mblk_t *mp = NULL; 2182*1959748cSgd78059 2183*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 2184*1959748cSgd78059 2185*1959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 2186*1959748cSgd78059 /* we cannot receive interrupts! */ 2187*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 2188*1959748cSgd78059 return (DDI_INTR_UNCLAIMED); 2189*1959748cSgd78059 } 2190*1959748cSgd78059 2191*1959748cSgd78059 /* check interrupt status bits, did we interrupt? */ 2192*1959748cSgd78059 status = GETCSR(afep, CSR_SR2) & INT_ALL; 2193*1959748cSgd78059 2194*1959748cSgd78059 if (status == 0) { 2195*1959748cSgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 2196*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 2197*1959748cSgd78059 return (DDI_INTR_UNCLAIMED); 2198*1959748cSgd78059 } 2199*1959748cSgd78059 /* ack the interrupt */ 2200*1959748cSgd78059 PUTCSR(afep, CSR_SR2, status); 2201*1959748cSgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++; 2202*1959748cSgd78059 2203*1959748cSgd78059 if (!(afep->afe_flags & AFE_RUNNING)) { 2204*1959748cSgd78059 /* not running, don't touch anything */ 2205*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 2206*1959748cSgd78059 return (DDI_INTR_CLAIMED); 2207*1959748cSgd78059 } 2208*1959748cSgd78059 2209*1959748cSgd78059 if (status & (INT_RXOK|INT_RXNOBUF)) { 2210*1959748cSgd78059 /* receive packets */ 2211*1959748cSgd78059 mp = afe_receive(afep); 2212*1959748cSgd78059 if (status & INT_RXNOBUF) 2213*1959748cSgd78059 PUTCSR(afep, CSR_RDR, 0); /* wake up chip */ 2214*1959748cSgd78059 } 2215*1959748cSgd78059 2216*1959748cSgd78059 if (status & INT_TXOK) { 2217*1959748cSgd78059 /* transmit completed */ 2218*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2219*1959748cSgd78059 afe_reclaim(afep); 2220*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2221*1959748cSgd78059 } 2222*1959748cSgd78059 2223*1959748cSgd78059 if (status & (INT_LINKCHG|INT_TIMER)) { 2224*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2225*1959748cSgd78059 afe_checklink(afep); 2226*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2227*1959748cSgd78059 } 2228*1959748cSgd78059 2229*1959748cSgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED| 2230*1959748cSgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) { 2231*1959748cSgd78059 2232*1959748cSgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) { 2233*1959748cSgd78059 afep->afe_jabber++; 2234*1959748cSgd78059 } 2235*1959748cSgd78059 DBG(DWARN, "resetting mac, status %x", status); 2236*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2237*1959748cSgd78059 afe_resetall(afep); 2238*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2239*1959748cSgd78059 } 2240*1959748cSgd78059 2241*1959748cSgd78059 if (status & INT_BUSERR) { 2242*1959748cSgd78059 switch (GETCSR(afep, CSR_SR) & SR_BERR_TYPE) { 2243*1959748cSgd78059 case SR_BERR_PARITY: 2244*1959748cSgd78059 afe_error(afep->afe_dip, "PCI parity error"); 2245*1959748cSgd78059 break; 2246*1959748cSgd78059 case SR_BERR_TARGET_ABORT: 2247*1959748cSgd78059 afe_error(afep->afe_dip, "PCI target abort"); 2248*1959748cSgd78059 break; 2249*1959748cSgd78059 case SR_BERR_MASTER_ABORT: 2250*1959748cSgd78059 afe_error(afep->afe_dip, "PCI master abort"); 2251*1959748cSgd78059 break; 2252*1959748cSgd78059 default: 2253*1959748cSgd78059 afe_error(afep->afe_dip, "Unknown PCI error"); 2254*1959748cSgd78059 break; 2255*1959748cSgd78059 } 2256*1959748cSgd78059 2257*1959748cSgd78059 /* reset the chip in an attempt to fix things */ 2258*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2259*1959748cSgd78059 afe_resetall(afep); 2260*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2261*1959748cSgd78059 } 2262*1959748cSgd78059 2263*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 2264*1959748cSgd78059 2265*1959748cSgd78059 /* 2266*1959748cSgd78059 * Send up packets. We do this outside of the intrlock. 2267*1959748cSgd78059 */ 2268*1959748cSgd78059 if (mp) { 2269*1959748cSgd78059 mac_rx(afep->afe_mh, NULL, mp); 2270*1959748cSgd78059 } 2271*1959748cSgd78059 2272*1959748cSgd78059 return (DDI_INTR_CLAIMED); 2273*1959748cSgd78059 } 2274*1959748cSgd78059 2275*1959748cSgd78059 void 2276*1959748cSgd78059 afe_enableinterrupts(afe_t *afep) 2277*1959748cSgd78059 { 2278*1959748cSgd78059 unsigned mask = INT_WANTED; 2279*1959748cSgd78059 2280*1959748cSgd78059 if (afep->afe_wantw) 2281*1959748cSgd78059 mask |= INT_TXOK; 2282*1959748cSgd78059 2283*1959748cSgd78059 PUTCSR(afep, CSR_IER2, mask); 2284*1959748cSgd78059 2285*1959748cSgd78059 if (AFE_MODEL(afep) == MODEL_COMET) { 2286*1959748cSgd78059 /* 2287*1959748cSgd78059 * On the Comet, this is the internal transceiver 2288*1959748cSgd78059 * interrupt. We program the Comet's built-in PHY to 2289*1959748cSgd78059 * enable certain interrupts. 2290*1959748cSgd78059 */ 2291*1959748cSgd78059 PUTCSR16(afep, CSR_XIE, XIE_LDE | XIE_ANCE); 2292*1959748cSgd78059 } 2293*1959748cSgd78059 } 2294*1959748cSgd78059 2295*1959748cSgd78059 void 2296*1959748cSgd78059 afe_disableinterrupts(afe_t *afep) 2297*1959748cSgd78059 { 2298*1959748cSgd78059 /* disable further interrupts */ 2299*1959748cSgd78059 PUTCSR(afep, CSR_IER2, INT_NONE); 2300*1959748cSgd78059 2301*1959748cSgd78059 /* clear any pending interrupts */ 2302*1959748cSgd78059 PUTCSR(afep, CSR_SR2, INT_ALL); 2303*1959748cSgd78059 } 2304*1959748cSgd78059 2305*1959748cSgd78059 boolean_t 2306*1959748cSgd78059 afe_send(afe_t *afep, mblk_t *mp) 2307*1959748cSgd78059 { 2308*1959748cSgd78059 size_t len; 2309*1959748cSgd78059 afe_txbuf_t *txb; 2310*1959748cSgd78059 afe_desc_t *tmd; 2311*1959748cSgd78059 uint32_t control; 2312*1959748cSgd78059 int txsend; 2313*1959748cSgd78059 2314*1959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 2315*1959748cSgd78059 ASSERT(mp != NULL); 2316*1959748cSgd78059 2317*1959748cSgd78059 len = msgsize(mp); 2318*1959748cSgd78059 if (len > ETHERVLANMTU) { 2319*1959748cSgd78059 DBG(DXMIT, "frame too long: %d", len); 2320*1959748cSgd78059 afep->afe_macxmt_errors++; 2321*1959748cSgd78059 freemsg(mp); 2322*1959748cSgd78059 return (B_TRUE); 2323*1959748cSgd78059 } 2324*1959748cSgd78059 2325*1959748cSgd78059 if (afep->afe_txavail < AFE_TXRECLAIM) 2326*1959748cSgd78059 afe_reclaim(afep); 2327*1959748cSgd78059 2328*1959748cSgd78059 if (afep->afe_txavail == 0) { 2329*1959748cSgd78059 /* no more tmds */ 2330*1959748cSgd78059 afep->afe_wantw = B_TRUE; 2331*1959748cSgd78059 /* enable TX interrupt */ 2332*1959748cSgd78059 afe_enableinterrupts(afep); 2333*1959748cSgd78059 return (B_FALSE); 2334*1959748cSgd78059 } 2335*1959748cSgd78059 2336*1959748cSgd78059 txsend = afep->afe_txsend; 2337*1959748cSgd78059 2338*1959748cSgd78059 /* 2339*1959748cSgd78059 * For simplicity, we just do a copy into a preallocated 2340*1959748cSgd78059 * DMA buffer. 2341*1959748cSgd78059 */ 2342*1959748cSgd78059 2343*1959748cSgd78059 txb = afep->afe_txbufs[txsend]; 2344*1959748cSgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */ 2345*1959748cSgd78059 2346*1959748cSgd78059 /* 2347*1959748cSgd78059 * Statistics. 2348*1959748cSgd78059 */ 2349*1959748cSgd78059 afep->afe_opackets++; 2350*1959748cSgd78059 afep->afe_obytes += len; 2351*1959748cSgd78059 if (txb->txb_buf[0] & 0x1) { 2352*1959748cSgd78059 if (bcmp(txb->txb_buf, afe_broadcast, ETHERADDRL) != 0) 2353*1959748cSgd78059 afep->afe_multixmt++; 2354*1959748cSgd78059 else 2355*1959748cSgd78059 afep->afe_brdcstxmt++; 2356*1959748cSgd78059 } 2357*1959748cSgd78059 2358*1959748cSgd78059 /* note len is already known to be a small unsigned */ 2359*1959748cSgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE; 2360*1959748cSgd78059 2361*1959748cSgd78059 if (txsend == (AFE_TXRING - 1)) 2362*1959748cSgd78059 control |= TXCTL_ENDRING; 2363*1959748cSgd78059 2364*1959748cSgd78059 tmd = &afep->afe_txdescp[txsend]; 2365*1959748cSgd78059 2366*1959748cSgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV); 2367*1959748cSgd78059 PUTTXDESC(afep, tmd->desc_control, control); 2368*1959748cSgd78059 PUTTXDESC(afep, tmd->desc_buffer1, txb->txb_paddr); 2369*1959748cSgd78059 PUTTXDESC(afep, tmd->desc_buffer2, 0); 2370*1959748cSgd78059 PUTTXDESC(afep, tmd->desc_status, TXSTAT_OWN); 2371*1959748cSgd78059 /* sync the descriptor out to the device */ 2372*1959748cSgd78059 SYNCTXDESC(afep, txsend, DDI_DMA_SYNC_FORDEV); 2373*1959748cSgd78059 2374*1959748cSgd78059 /* 2375*1959748cSgd78059 * Note the new values of txavail and txsend. 2376*1959748cSgd78059 */ 2377*1959748cSgd78059 afep->afe_txavail--; 2378*1959748cSgd78059 afep->afe_txsend = (txsend + 1) % AFE_TXRING; 2379*1959748cSgd78059 2380*1959748cSgd78059 /* 2381*1959748cSgd78059 * It should never, ever take more than 5 seconds to drain 2382*1959748cSgd78059 * the ring. If it happens, then we are stuck! 2383*1959748cSgd78059 */ 2384*1959748cSgd78059 afep->afe_txstall_time = gethrtime() + (5 * 1000000000ULL); 2385*1959748cSgd78059 2386*1959748cSgd78059 /* 2387*1959748cSgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 2388*1959748cSgd78059 * etc. 2389*1959748cSgd78059 */ 2390*1959748cSgd78059 PUTCSR(afep, CSR_TDR, 0); 2391*1959748cSgd78059 2392*1959748cSgd78059 return (B_TRUE); 2393*1959748cSgd78059 } 2394*1959748cSgd78059 2395*1959748cSgd78059 /* 2396*1959748cSgd78059 * Reclaim buffers that have completed transmission. 2397*1959748cSgd78059 */ 2398*1959748cSgd78059 void 2399*1959748cSgd78059 afe_reclaim(afe_t *afep) 2400*1959748cSgd78059 { 2401*1959748cSgd78059 afe_desc_t *tmdp; 2402*1959748cSgd78059 2403*1959748cSgd78059 while (afep->afe_txavail != AFE_TXRING) { 2404*1959748cSgd78059 uint32_t status; 2405*1959748cSgd78059 uint32_t control; 2406*1959748cSgd78059 int index = afep->afe_txreclaim; 2407*1959748cSgd78059 2408*1959748cSgd78059 tmdp = &afep->afe_txdescp[index]; 2409*1959748cSgd78059 2410*1959748cSgd78059 /* sync it before we read it */ 2411*1959748cSgd78059 SYNCTXDESC(afep, index, DDI_DMA_SYNC_FORKERNEL); 2412*1959748cSgd78059 2413*1959748cSgd78059 control = GETTXDESC(afep, tmdp->desc_control); 2414*1959748cSgd78059 status = GETTXDESC(afep, tmdp->desc_status); 2415*1959748cSgd78059 2416*1959748cSgd78059 if (status & TXSTAT_OWN) { 2417*1959748cSgd78059 /* chip is still working on it, we're done */ 2418*1959748cSgd78059 break; 2419*1959748cSgd78059 } 2420*1959748cSgd78059 2421*1959748cSgd78059 afep->afe_txavail++; 2422*1959748cSgd78059 afep->afe_txreclaim = (index + 1) % AFE_TXRING; 2423*1959748cSgd78059 2424*1959748cSgd78059 /* in the most common successful case, all bits are clear */ 2425*1959748cSgd78059 if (status == 0) 2426*1959748cSgd78059 continue; 2427*1959748cSgd78059 2428*1959748cSgd78059 if ((control & TXCTL_LAST) == 0) 2429*1959748cSgd78059 continue; 2430*1959748cSgd78059 2431*1959748cSgd78059 if (status & TXSTAT_TXERR) { 2432*1959748cSgd78059 afep->afe_errxmt++; 2433*1959748cSgd78059 2434*1959748cSgd78059 if (status & TXSTAT_JABBER) { 2435*1959748cSgd78059 /* transmit jabber timeout */ 2436*1959748cSgd78059 afep->afe_macxmt_errors++; 2437*1959748cSgd78059 } 2438*1959748cSgd78059 if (status & 2439*1959748cSgd78059 (TXSTAT_CARRLOST | TXSTAT_NOCARR)) { 2440*1959748cSgd78059 afep->afe_carrier_errors++; 2441*1959748cSgd78059 } 2442*1959748cSgd78059 if (status & TXSTAT_UFLOW) { 2443*1959748cSgd78059 afep->afe_underflow++; 2444*1959748cSgd78059 } 2445*1959748cSgd78059 if (status & TXSTAT_LATECOL) { 2446*1959748cSgd78059 afep->afe_tx_late_collisions++; 2447*1959748cSgd78059 } 2448*1959748cSgd78059 if (status & TXSTAT_EXCOLL) { 2449*1959748cSgd78059 afep->afe_ex_collisions++; 2450*1959748cSgd78059 afep->afe_collisions += 16; 2451*1959748cSgd78059 } 2452*1959748cSgd78059 } 2453*1959748cSgd78059 2454*1959748cSgd78059 if (status & TXSTAT_DEFER) { 2455*1959748cSgd78059 afep->afe_defer_xmts++; 2456*1959748cSgd78059 } 2457*1959748cSgd78059 2458*1959748cSgd78059 /* collision counting */ 2459*1959748cSgd78059 if (TXCOLLCNT(status) == 1) { 2460*1959748cSgd78059 afep->afe_collisions++; 2461*1959748cSgd78059 afep->afe_first_collisions++; 2462*1959748cSgd78059 } else if (TXCOLLCNT(status)) { 2463*1959748cSgd78059 afep->afe_collisions += TXCOLLCNT(status); 2464*1959748cSgd78059 afep->afe_multi_collisions += TXCOLLCNT(status); 2465*1959748cSgd78059 } 2466*1959748cSgd78059 } 2467*1959748cSgd78059 2468*1959748cSgd78059 if (afep->afe_txavail >= AFE_TXRESCHED) { 2469*1959748cSgd78059 if (afep->afe_wantw) { 2470*1959748cSgd78059 /* 2471*1959748cSgd78059 * we were able to reclaim some packets, so 2472*1959748cSgd78059 * disable tx interrupts 2473*1959748cSgd78059 */ 2474*1959748cSgd78059 afep->afe_wantw = B_FALSE; 2475*1959748cSgd78059 afe_enableinterrupts(afep); 2476*1959748cSgd78059 mac_tx_update(afep->afe_mh); 2477*1959748cSgd78059 } 2478*1959748cSgd78059 } 2479*1959748cSgd78059 } 2480*1959748cSgd78059 2481*1959748cSgd78059 mblk_t * 2482*1959748cSgd78059 afe_receive(afe_t *afep) 2483*1959748cSgd78059 { 2484*1959748cSgd78059 unsigned len; 2485*1959748cSgd78059 afe_rxbuf_t *rxb; 2486*1959748cSgd78059 afe_desc_t *rmd; 2487*1959748cSgd78059 uint32_t status; 2488*1959748cSgd78059 mblk_t *mpchain, **mpp, *mp; 2489*1959748cSgd78059 int head, cnt; 2490*1959748cSgd78059 2491*1959748cSgd78059 mpchain = NULL; 2492*1959748cSgd78059 mpp = &mpchain; 2493*1959748cSgd78059 head = afep->afe_rxhead; 2494*1959748cSgd78059 2495*1959748cSgd78059 /* limit the number of packets we process to a half ring size */ 2496*1959748cSgd78059 for (cnt = 0; cnt < AFE_RXRING / 2; cnt++) { 2497*1959748cSgd78059 2498*1959748cSgd78059 DBG(DRECV, "receive at index %d", head); 2499*1959748cSgd78059 2500*1959748cSgd78059 rmd = &afep->afe_rxdescp[head]; 2501*1959748cSgd78059 rxb = afep->afe_rxbufs[head]; 2502*1959748cSgd78059 2503*1959748cSgd78059 SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORKERNEL); 2504*1959748cSgd78059 status = GETRXDESC(afep, rmd->desc_status); 2505*1959748cSgd78059 if (status & RXSTAT_OWN) { 2506*1959748cSgd78059 /* chip is still chewing on it */ 2507*1959748cSgd78059 break; 2508*1959748cSgd78059 } 2509*1959748cSgd78059 2510*1959748cSgd78059 /* discard the ethernet frame checksum */ 2511*1959748cSgd78059 len = RXLENGTH(status) - ETHERFCSL; 2512*1959748cSgd78059 2513*1959748cSgd78059 DBG(DRECV, "recv length %d, status %x", len, status); 2514*1959748cSgd78059 2515*1959748cSgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) != 2516*1959748cSgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) { 2517*1959748cSgd78059 2518*1959748cSgd78059 afep->afe_errrcv++; 2519*1959748cSgd78059 2520*1959748cSgd78059 /* 2521*1959748cSgd78059 * Abnormal status bits detected, analyze further. 2522*1959748cSgd78059 */ 2523*1959748cSgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) != 2524*1959748cSgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) { 2525*1959748cSgd78059 DBG(DRECV, "rx packet overspill"); 2526*1959748cSgd78059 if (status & RXSTAT_FIRST) { 2527*1959748cSgd78059 afep->afe_toolong_errors++; 2528*1959748cSgd78059 } 2529*1959748cSgd78059 } else if (status & RXSTAT_DESCERR) { 2530*1959748cSgd78059 afep->afe_macrcv_errors++; 2531*1959748cSgd78059 2532*1959748cSgd78059 } else if (status & RXSTAT_RUNT) { 2533*1959748cSgd78059 afep->afe_runt++; 2534*1959748cSgd78059 2535*1959748cSgd78059 } else if (status & RXSTAT_COLLSEEN) { 2536*1959748cSgd78059 /* this should really be rx_late_collisions */ 2537*1959748cSgd78059 afep->afe_macrcv_errors++; 2538*1959748cSgd78059 2539*1959748cSgd78059 } else if (status & RXSTAT_DRIBBLE) { 2540*1959748cSgd78059 afep->afe_align_errors++; 2541*1959748cSgd78059 2542*1959748cSgd78059 } else if (status & RXSTAT_CRCERR) { 2543*1959748cSgd78059 afep->afe_fcs_errors++; 2544*1959748cSgd78059 2545*1959748cSgd78059 } else if (status & RXSTAT_OFLOW) { 2546*1959748cSgd78059 afep->afe_overflow++; 2547*1959748cSgd78059 } 2548*1959748cSgd78059 } 2549*1959748cSgd78059 2550*1959748cSgd78059 else if (len > ETHERVLANMTU) { 2551*1959748cSgd78059 afep->afe_errrcv++; 2552*1959748cSgd78059 afep->afe_toolong_errors++; 2553*1959748cSgd78059 } 2554*1959748cSgd78059 2555*1959748cSgd78059 /* 2556*1959748cSgd78059 * At this point, the chip thinks the packet is OK. 2557*1959748cSgd78059 */ 2558*1959748cSgd78059 else { 2559*1959748cSgd78059 mp = allocb(len + AFE_HEADROOM, 0); 2560*1959748cSgd78059 if (mp == NULL) { 2561*1959748cSgd78059 afep->afe_errrcv++; 2562*1959748cSgd78059 afep->afe_norcvbuf++; 2563*1959748cSgd78059 goto skip; 2564*1959748cSgd78059 } 2565*1959748cSgd78059 2566*1959748cSgd78059 /* sync the buffer before we look at it */ 2567*1959748cSgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL); 2568*1959748cSgd78059 mp->b_rptr += AFE_HEADROOM; 2569*1959748cSgd78059 mp->b_wptr = mp->b_rptr + len; 2570*1959748cSgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len); 2571*1959748cSgd78059 2572*1959748cSgd78059 afep->afe_ipackets++; 2573*1959748cSgd78059 afep->afe_rbytes += len; 2574*1959748cSgd78059 if (status & RXSTAT_GROUP) { 2575*1959748cSgd78059 if (bcmp(mp->b_rptr, afe_broadcast, 2576*1959748cSgd78059 ETHERADDRL) == 0) 2577*1959748cSgd78059 afep->afe_brdcstrcv++; 2578*1959748cSgd78059 else 2579*1959748cSgd78059 afep->afe_multircv++; 2580*1959748cSgd78059 } 2581*1959748cSgd78059 *mpp = mp; 2582*1959748cSgd78059 mpp = &mp->b_next; 2583*1959748cSgd78059 } 2584*1959748cSgd78059 2585*1959748cSgd78059 skip: 2586*1959748cSgd78059 /* return ring entry to the hardware */ 2587*1959748cSgd78059 PUTRXDESC(afep, rmd->desc_status, RXSTAT_OWN); 2588*1959748cSgd78059 SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORDEV); 2589*1959748cSgd78059 2590*1959748cSgd78059 /* advance to next RMD */ 2591*1959748cSgd78059 head = (head + 1) % AFE_RXRING; 2592*1959748cSgd78059 } 2593*1959748cSgd78059 2594*1959748cSgd78059 afep->afe_rxhead = head; 2595*1959748cSgd78059 2596*1959748cSgd78059 return (mpchain); 2597*1959748cSgd78059 } 2598*1959748cSgd78059 2599*1959748cSgd78059 int 2600*1959748cSgd78059 afe_getmiibit(afe_t *afep, uint16_t reg, uint16_t bit) 2601*1959748cSgd78059 { 2602*1959748cSgd78059 unsigned val; 2603*1959748cSgd78059 2604*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2605*1959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 2606*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2607*1959748cSgd78059 /* device is suspended */ 2608*1959748cSgd78059 return (0); 2609*1959748cSgd78059 } 2610*1959748cSgd78059 val = afe_miiread(afep, afep->afe_phyaddr, reg); 2611*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2612*1959748cSgd78059 2613*1959748cSgd78059 return (val & bit ? 1 : 0); 2614*1959748cSgd78059 } 2615*1959748cSgd78059 #define GETMIIBIT(reg, bit) afe_getmiibit(afep, reg, bit) 2616*1959748cSgd78059 2617*1959748cSgd78059 int 2618*1959748cSgd78059 afe_m_stat(void *arg, uint_t stat, uint64_t *val) 2619*1959748cSgd78059 { 2620*1959748cSgd78059 afe_t *afep = arg; 2621*1959748cSgd78059 2622*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 2623*1959748cSgd78059 if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == AFE_RUNNING) 2624*1959748cSgd78059 afe_reclaim(afep); 2625*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 2626*1959748cSgd78059 2627*1959748cSgd78059 switch (stat) { 2628*1959748cSgd78059 case MAC_STAT_IFSPEED: 2629*1959748cSgd78059 *val = afep->afe_ifspeed; 2630*1959748cSgd78059 break; 2631*1959748cSgd78059 2632*1959748cSgd78059 case MAC_STAT_MULTIRCV: 2633*1959748cSgd78059 *val = afep->afe_multircv; 2634*1959748cSgd78059 break; 2635*1959748cSgd78059 2636*1959748cSgd78059 case MAC_STAT_BRDCSTRCV: 2637*1959748cSgd78059 *val = afep->afe_brdcstrcv; 2638*1959748cSgd78059 break; 2639*1959748cSgd78059 2640*1959748cSgd78059 case MAC_STAT_MULTIXMT: 2641*1959748cSgd78059 *val = afep->afe_multixmt; 2642*1959748cSgd78059 break; 2643*1959748cSgd78059 2644*1959748cSgd78059 case MAC_STAT_BRDCSTXMT: 2645*1959748cSgd78059 *val = afep->afe_brdcstxmt; 2646*1959748cSgd78059 break; 2647*1959748cSgd78059 2648*1959748cSgd78059 case MAC_STAT_IPACKETS: 2649*1959748cSgd78059 *val = afep->afe_ipackets; 2650*1959748cSgd78059 break; 2651*1959748cSgd78059 2652*1959748cSgd78059 case MAC_STAT_RBYTES: 2653*1959748cSgd78059 *val = afep->afe_rbytes; 2654*1959748cSgd78059 break; 2655*1959748cSgd78059 2656*1959748cSgd78059 case MAC_STAT_OPACKETS: 2657*1959748cSgd78059 *val = afep->afe_opackets; 2658*1959748cSgd78059 break; 2659*1959748cSgd78059 2660*1959748cSgd78059 case MAC_STAT_OBYTES: 2661*1959748cSgd78059 *val = afep->afe_obytes; 2662*1959748cSgd78059 break; 2663*1959748cSgd78059 2664*1959748cSgd78059 case MAC_STAT_NORCVBUF: 2665*1959748cSgd78059 *val = afep->afe_norcvbuf; 2666*1959748cSgd78059 break; 2667*1959748cSgd78059 2668*1959748cSgd78059 case MAC_STAT_NOXMTBUF: 2669*1959748cSgd78059 *val = 0; 2670*1959748cSgd78059 break; 2671*1959748cSgd78059 2672*1959748cSgd78059 case MAC_STAT_COLLISIONS: 2673*1959748cSgd78059 *val = afep->afe_collisions; 2674*1959748cSgd78059 break; 2675*1959748cSgd78059 2676*1959748cSgd78059 case MAC_STAT_IERRORS: 2677*1959748cSgd78059 *val = afep->afe_errrcv; 2678*1959748cSgd78059 break; 2679*1959748cSgd78059 2680*1959748cSgd78059 case MAC_STAT_OERRORS: 2681*1959748cSgd78059 *val = afep->afe_errxmt; 2682*1959748cSgd78059 break; 2683*1959748cSgd78059 2684*1959748cSgd78059 case ETHER_STAT_LINK_DUPLEX: 2685*1959748cSgd78059 *val = afep->afe_duplex; 2686*1959748cSgd78059 break; 2687*1959748cSgd78059 2688*1959748cSgd78059 case ETHER_STAT_ALIGN_ERRORS: 2689*1959748cSgd78059 *val = afep->afe_align_errors; 2690*1959748cSgd78059 break; 2691*1959748cSgd78059 2692*1959748cSgd78059 case ETHER_STAT_FCS_ERRORS: 2693*1959748cSgd78059 *val = afep->afe_fcs_errors; 2694*1959748cSgd78059 break; 2695*1959748cSgd78059 2696*1959748cSgd78059 case ETHER_STAT_SQE_ERRORS: 2697*1959748cSgd78059 *val = afep->afe_sqe_errors; 2698*1959748cSgd78059 break; 2699*1959748cSgd78059 2700*1959748cSgd78059 case ETHER_STAT_DEFER_XMTS: 2701*1959748cSgd78059 *val = afep->afe_defer_xmts; 2702*1959748cSgd78059 break; 2703*1959748cSgd78059 2704*1959748cSgd78059 case ETHER_STAT_FIRST_COLLISIONS: 2705*1959748cSgd78059 *val = afep->afe_first_collisions; 2706*1959748cSgd78059 break; 2707*1959748cSgd78059 2708*1959748cSgd78059 case ETHER_STAT_MULTI_COLLISIONS: 2709*1959748cSgd78059 *val = afep->afe_multi_collisions; 2710*1959748cSgd78059 break; 2711*1959748cSgd78059 2712*1959748cSgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 2713*1959748cSgd78059 *val = afep->afe_tx_late_collisions; 2714*1959748cSgd78059 break; 2715*1959748cSgd78059 2716*1959748cSgd78059 case ETHER_STAT_EX_COLLISIONS: 2717*1959748cSgd78059 *val = afep->afe_ex_collisions; 2718*1959748cSgd78059 break; 2719*1959748cSgd78059 2720*1959748cSgd78059 case ETHER_STAT_MACXMT_ERRORS: 2721*1959748cSgd78059 *val = afep->afe_macxmt_errors; 2722*1959748cSgd78059 break; 2723*1959748cSgd78059 2724*1959748cSgd78059 case ETHER_STAT_CARRIER_ERRORS: 2725*1959748cSgd78059 *val = afep->afe_carrier_errors; 2726*1959748cSgd78059 break; 2727*1959748cSgd78059 2728*1959748cSgd78059 case ETHER_STAT_TOOLONG_ERRORS: 2729*1959748cSgd78059 *val = afep->afe_toolong_errors; 2730*1959748cSgd78059 break; 2731*1959748cSgd78059 2732*1959748cSgd78059 case ETHER_STAT_MACRCV_ERRORS: 2733*1959748cSgd78059 *val = afep->afe_macrcv_errors; 2734*1959748cSgd78059 break; 2735*1959748cSgd78059 2736*1959748cSgd78059 case MAC_STAT_OVERFLOWS: 2737*1959748cSgd78059 *val = afep->afe_overflow; 2738*1959748cSgd78059 break; 2739*1959748cSgd78059 2740*1959748cSgd78059 case MAC_STAT_UNDERFLOWS: 2741*1959748cSgd78059 *val = afep->afe_underflow; 2742*1959748cSgd78059 break; 2743*1959748cSgd78059 2744*1959748cSgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 2745*1959748cSgd78059 *val = afep->afe_runt; 2746*1959748cSgd78059 break; 2747*1959748cSgd78059 2748*1959748cSgd78059 case ETHER_STAT_JABBER_ERRORS: 2749*1959748cSgd78059 *val = afep->afe_jabber; 2750*1959748cSgd78059 break; 2751*1959748cSgd78059 2752*1959748cSgd78059 case ETHER_STAT_CAP_100T4: 2753*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASE_T4); 2754*1959748cSgd78059 break; 2755*1959748cSgd78059 2756*1959748cSgd78059 case ETHER_STAT_CAP_100FDX: 2757*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASEX_FD); 2758*1959748cSgd78059 break; 2759*1959748cSgd78059 2760*1959748cSgd78059 case ETHER_STAT_CAP_100HDX: 2761*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_100_BASEX); 2762*1959748cSgd78059 break; 2763*1959748cSgd78059 2764*1959748cSgd78059 case ETHER_STAT_CAP_10FDX: 2765*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_10_FD); 2766*1959748cSgd78059 break; 2767*1959748cSgd78059 2768*1959748cSgd78059 case ETHER_STAT_CAP_10HDX: 2769*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_10); 2770*1959748cSgd78059 break; 2771*1959748cSgd78059 2772*1959748cSgd78059 case ETHER_STAT_CAP_AUTONEG: 2773*1959748cSgd78059 *val = GETMIIBIT(MII_STATUS, MII_STATUS_CANAUTONEG); 2774*1959748cSgd78059 break; 2775*1959748cSgd78059 2776*1959748cSgd78059 case ETHER_STAT_LINK_AUTONEG: 2777*1959748cSgd78059 *val = ((afep->afe_adv_aneg != 0) && 2778*1959748cSgd78059 (GETMIIBIT(MII_AN_LPABLE, MII_AN_EXP_LPCANAN) != 0)); 2779*1959748cSgd78059 break; 2780*1959748cSgd78059 2781*1959748cSgd78059 case ETHER_STAT_ADV_CAP_100T4: 2782*1959748cSgd78059 *val = afep->afe_adv_100T4; 2783*1959748cSgd78059 break; 2784*1959748cSgd78059 2785*1959748cSgd78059 case ETHER_STAT_ADV_CAP_100FDX: 2786*1959748cSgd78059 *val = afep->afe_adv_100fdx; 2787*1959748cSgd78059 break; 2788*1959748cSgd78059 2789*1959748cSgd78059 case ETHER_STAT_ADV_CAP_100HDX: 2790*1959748cSgd78059 *val = afep->afe_adv_100hdx; 2791*1959748cSgd78059 break; 2792*1959748cSgd78059 2793*1959748cSgd78059 case ETHER_STAT_ADV_CAP_10FDX: 2794*1959748cSgd78059 *val = afep->afe_adv_10fdx; 2795*1959748cSgd78059 break; 2796*1959748cSgd78059 2797*1959748cSgd78059 case ETHER_STAT_ADV_CAP_10HDX: 2798*1959748cSgd78059 *val = afep->afe_adv_10hdx; 2799*1959748cSgd78059 break; 2800*1959748cSgd78059 2801*1959748cSgd78059 case ETHER_STAT_ADV_CAP_AUTONEG: 2802*1959748cSgd78059 *val = afep->afe_adv_aneg; 2803*1959748cSgd78059 break; 2804*1959748cSgd78059 2805*1959748cSgd78059 case ETHER_STAT_LP_CAP_100T4: 2806*1959748cSgd78059 *val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_T4); 2807*1959748cSgd78059 break; 2808*1959748cSgd78059 2809*1959748cSgd78059 case ETHER_STAT_LP_CAP_100FDX: 2810*1959748cSgd78059 *val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_TX_FD); 2811*1959748cSgd78059 break; 2812*1959748cSgd78059 2813*1959748cSgd78059 case ETHER_STAT_LP_CAP_100HDX: 2814*1959748cSgd78059 *val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_100BASE_TX); 2815*1959748cSgd78059 break; 2816*1959748cSgd78059 2817*1959748cSgd78059 case ETHER_STAT_LP_CAP_10FDX: 2818*1959748cSgd78059 *val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_10BASE_T_FD); 2819*1959748cSgd78059 break; 2820*1959748cSgd78059 2821*1959748cSgd78059 case ETHER_STAT_LP_CAP_10HDX: 2822*1959748cSgd78059 *val = GETMIIBIT(MII_AN_LPABLE, MII_ABILITY_10BASE_T); 2823*1959748cSgd78059 break; 2824*1959748cSgd78059 2825*1959748cSgd78059 case ETHER_STAT_LP_CAP_AUTONEG: 2826*1959748cSgd78059 *val = GETMIIBIT(MII_AN_EXPANSION, MII_AN_EXP_LPCANAN); 2827*1959748cSgd78059 break; 2828*1959748cSgd78059 2829*1959748cSgd78059 case ETHER_STAT_XCVR_ADDR: 2830*1959748cSgd78059 *val = afep->afe_phyaddr; 2831*1959748cSgd78059 break; 2832*1959748cSgd78059 2833*1959748cSgd78059 case ETHER_STAT_XCVR_ID: 2834*1959748cSgd78059 *val = afep->afe_phyid; 2835*1959748cSgd78059 break; 2836*1959748cSgd78059 2837*1959748cSgd78059 default: 2838*1959748cSgd78059 return (ENOTSUP); 2839*1959748cSgd78059 } 2840*1959748cSgd78059 return (0); 2841*1959748cSgd78059 } 2842*1959748cSgd78059 2843*1959748cSgd78059 /* 2844*1959748cSgd78059 * NDD support. 2845*1959748cSgd78059 */ 2846*1959748cSgd78059 afe_nd_t * 2847*1959748cSgd78059 afe_ndfind(afe_t *afep, char *name) 2848*1959748cSgd78059 { 2849*1959748cSgd78059 afe_nd_t *ndp; 2850*1959748cSgd78059 2851*1959748cSgd78059 for (ndp = afep->afe_ndp; ndp != NULL; ndp = ndp->nd_next) { 2852*1959748cSgd78059 if (strcmp(name, ndp->nd_name) == 0) { 2853*1959748cSgd78059 break; 2854*1959748cSgd78059 } 2855*1959748cSgd78059 } 2856*1959748cSgd78059 return (ndp); 2857*1959748cSgd78059 } 2858*1959748cSgd78059 2859*1959748cSgd78059 void 2860*1959748cSgd78059 afe_ndadd(afe_t *afep, char *name, afe_nd_pf_t get, afe_nd_pf_t set, 2861*1959748cSgd78059 intptr_t arg1, intptr_t arg2) 2862*1959748cSgd78059 { 2863*1959748cSgd78059 afe_nd_t *newndp; 2864*1959748cSgd78059 afe_nd_t **ndpp; 2865*1959748cSgd78059 2866*1959748cSgd78059 newndp = (afe_nd_t *)kmem_alloc(sizeof (afe_nd_t), KM_SLEEP); 2867*1959748cSgd78059 newndp->nd_next = NULL; 2868*1959748cSgd78059 newndp->nd_name = name; 2869*1959748cSgd78059 newndp->nd_get = get; 2870*1959748cSgd78059 newndp->nd_set = set; 2871*1959748cSgd78059 newndp->nd_arg1 = arg1; 2872*1959748cSgd78059 newndp->nd_arg2 = arg2; 2873*1959748cSgd78059 2874*1959748cSgd78059 /* seek to the end of the list */ 2875*1959748cSgd78059 for (ndpp = &afep->afe_ndp; *ndpp; ndpp = &(*ndpp)->nd_next) { 2876*1959748cSgd78059 } 2877*1959748cSgd78059 2878*1959748cSgd78059 *ndpp = newndp; 2879*1959748cSgd78059 } 2880*1959748cSgd78059 2881*1959748cSgd78059 void 2882*1959748cSgd78059 afe_ndempty(mblk_t *mp) 2883*1959748cSgd78059 { 2884*1959748cSgd78059 while (mp != NULL) { 2885*1959748cSgd78059 mp->b_rptr = mp->b_datap->db_base; 2886*1959748cSgd78059 mp->b_wptr = mp->b_rptr; 2887*1959748cSgd78059 mp = mp->b_cont; 2888*1959748cSgd78059 } 2889*1959748cSgd78059 } 2890*1959748cSgd78059 2891*1959748cSgd78059 void 2892*1959748cSgd78059 afe_ndget(afe_t *afep, queue_t *wq, mblk_t *mp) 2893*1959748cSgd78059 { 2894*1959748cSgd78059 mblk_t *nmp = mp->b_cont; 2895*1959748cSgd78059 afe_nd_t *ndp; 2896*1959748cSgd78059 int rv; 2897*1959748cSgd78059 char name[128]; 2898*1959748cSgd78059 2899*1959748cSgd78059 /* assumption, name will fit in first mblk of chain */ 2900*1959748cSgd78059 if ((nmp == NULL) || (nmp->b_wptr <= nmp->b_rptr)) { 2901*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2902*1959748cSgd78059 return; 2903*1959748cSgd78059 } 2904*1959748cSgd78059 2905*1959748cSgd78059 if (afe_ndparselen(nmp) >= sizeof (name)) { 2906*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2907*1959748cSgd78059 return; 2908*1959748cSgd78059 } 2909*1959748cSgd78059 afe_ndparsestring(nmp, name, sizeof (name)); 2910*1959748cSgd78059 2911*1959748cSgd78059 /* locate variable */ 2912*1959748cSgd78059 if ((ndp = afe_ndfind(afep, name)) == NULL) { 2913*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2914*1959748cSgd78059 return; 2915*1959748cSgd78059 } 2916*1959748cSgd78059 2917*1959748cSgd78059 /* locate get callback */ 2918*1959748cSgd78059 if (ndp->nd_get == NULL) { 2919*1959748cSgd78059 miocnak(wq, mp, 0, EACCES); 2920*1959748cSgd78059 return; 2921*1959748cSgd78059 } 2922*1959748cSgd78059 2923*1959748cSgd78059 /* clear the result buffer */ 2924*1959748cSgd78059 afe_ndempty(nmp); 2925*1959748cSgd78059 2926*1959748cSgd78059 rv = (*ndp->nd_get)(afep, nmp, ndp); 2927*1959748cSgd78059 if (rv == 0) { 2928*1959748cSgd78059 /* add final null bytes */ 2929*1959748cSgd78059 rv = afe_ndaddbytes(nmp, "\0", 1); 2930*1959748cSgd78059 } 2931*1959748cSgd78059 2932*1959748cSgd78059 if (rv == 0) { 2933*1959748cSgd78059 miocack(wq, mp, msgsize(nmp), 0); 2934*1959748cSgd78059 } else { 2935*1959748cSgd78059 miocnak(wq, mp, 0, rv); 2936*1959748cSgd78059 } 2937*1959748cSgd78059 } 2938*1959748cSgd78059 2939*1959748cSgd78059 void 2940*1959748cSgd78059 afe_ndset(afe_t *afep, queue_t *wq, mblk_t *mp) 2941*1959748cSgd78059 { 2942*1959748cSgd78059 struct iocblk *iocp = (void *)mp->b_rptr; 2943*1959748cSgd78059 mblk_t *nmp = mp->b_cont; 2944*1959748cSgd78059 afe_nd_t *ndp; 2945*1959748cSgd78059 int rv; 2946*1959748cSgd78059 char name[128]; 2947*1959748cSgd78059 2948*1959748cSgd78059 /* enforce policy */ 2949*1959748cSgd78059 if ((rv = priv_getbyname(PRIV_SYS_NET_CONFIG, 0)) < 0) { 2950*1959748cSgd78059 /* priv_getbyname returns a negative errno */ 2951*1959748cSgd78059 miocnak(wq, mp, 0, -rv); 2952*1959748cSgd78059 return; 2953*1959748cSgd78059 } 2954*1959748cSgd78059 if ((rv = priv_policy(iocp->ioc_cr, rv, B_FALSE, EPERM, NULL)) != 0) { 2955*1959748cSgd78059 miocnak(wq, mp, 0, rv); 2956*1959748cSgd78059 return; 2957*1959748cSgd78059 } 2958*1959748cSgd78059 2959*1959748cSgd78059 /* assumption, name will fit in first mblk of chain */ 2960*1959748cSgd78059 if ((nmp == NULL) || (nmp->b_wptr <= nmp->b_rptr)) { 2961*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2962*1959748cSgd78059 return; 2963*1959748cSgd78059 } 2964*1959748cSgd78059 2965*1959748cSgd78059 if (afe_ndparselen(nmp) >= sizeof (name)) { 2966*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2967*1959748cSgd78059 return; 2968*1959748cSgd78059 } 2969*1959748cSgd78059 afe_ndparsestring(nmp, name, sizeof (name)); 2970*1959748cSgd78059 2971*1959748cSgd78059 /* locate variable */ 2972*1959748cSgd78059 if ((ndp = afe_ndfind(afep, name)) == NULL) { 2973*1959748cSgd78059 miocnak(wq, mp, 0, EINVAL); 2974*1959748cSgd78059 return; 2975*1959748cSgd78059 } 2976*1959748cSgd78059 2977*1959748cSgd78059 /* locate set callback */ 2978*1959748cSgd78059 if (ndp->nd_set == NULL) { 2979*1959748cSgd78059 miocnak(wq, mp, 0, EACCES); 2980*1959748cSgd78059 return; 2981*1959748cSgd78059 } 2982*1959748cSgd78059 2983*1959748cSgd78059 rv = (*ndp->nd_set)(afep, nmp, ndp); 2984*1959748cSgd78059 2985*1959748cSgd78059 if (rv == 0) { 2986*1959748cSgd78059 miocack(wq, mp, 0, 0); 2987*1959748cSgd78059 } else { 2988*1959748cSgd78059 miocnak(wq, mp, 0, rv); 2989*1959748cSgd78059 } 2990*1959748cSgd78059 } 2991*1959748cSgd78059 2992*1959748cSgd78059 int 2993*1959748cSgd78059 afe_ndaddbytes(mblk_t *mp, char *bytes, int cnt) 2994*1959748cSgd78059 { 2995*1959748cSgd78059 int index; 2996*1959748cSgd78059 2997*1959748cSgd78059 for (index = 0; index < cnt; index++) { 2998*1959748cSgd78059 while (mp && (mp->b_wptr >= DB_LIM(mp))) { 2999*1959748cSgd78059 mp = mp->b_cont; 3000*1959748cSgd78059 } 3001*1959748cSgd78059 if (mp == NULL) { 3002*1959748cSgd78059 return (ENOSPC); 3003*1959748cSgd78059 } 3004*1959748cSgd78059 *(mp->b_wptr) = *bytes; 3005*1959748cSgd78059 mp->b_wptr++; 3006*1959748cSgd78059 bytes++; 3007*1959748cSgd78059 } 3008*1959748cSgd78059 return (0); 3009*1959748cSgd78059 } 3010*1959748cSgd78059 3011*1959748cSgd78059 int 3012*1959748cSgd78059 afe_ndaddstr(mblk_t *mp, char *str, int addnull) 3013*1959748cSgd78059 { 3014*1959748cSgd78059 /* store the string, plus the terminating null */ 3015*1959748cSgd78059 return (afe_ndaddbytes(mp, str, strlen(str) + (addnull ? 1 : 0))); 3016*1959748cSgd78059 } 3017*1959748cSgd78059 3018*1959748cSgd78059 int 3019*1959748cSgd78059 afe_ndparselen(mblk_t *mp) 3020*1959748cSgd78059 { 3021*1959748cSgd78059 int len = 0; 3022*1959748cSgd78059 int done = 0; 3023*1959748cSgd78059 uchar_t *ptr; 3024*1959748cSgd78059 3025*1959748cSgd78059 while (mp && !done) { 3026*1959748cSgd78059 for (ptr = mp->b_rptr; ptr < mp->b_wptr; ptr++) { 3027*1959748cSgd78059 if (!(*ptr)) { 3028*1959748cSgd78059 done = 1; 3029*1959748cSgd78059 break; 3030*1959748cSgd78059 } 3031*1959748cSgd78059 len++; 3032*1959748cSgd78059 } 3033*1959748cSgd78059 mp = mp->b_cont; 3034*1959748cSgd78059 } 3035*1959748cSgd78059 return (len); 3036*1959748cSgd78059 } 3037*1959748cSgd78059 3038*1959748cSgd78059 int 3039*1959748cSgd78059 afe_ndparseint(mblk_t *mp) 3040*1959748cSgd78059 { 3041*1959748cSgd78059 int done = 0; 3042*1959748cSgd78059 int val = 0; 3043*1959748cSgd78059 while (mp && !done) { 3044*1959748cSgd78059 while (mp->b_rptr < mp->b_wptr) { 3045*1959748cSgd78059 uchar_t ch = *(mp->b_rptr); 3046*1959748cSgd78059 mp->b_rptr++; 3047*1959748cSgd78059 if ((ch >= '0') && (ch <= '9')) { 3048*1959748cSgd78059 val *= 10; 3049*1959748cSgd78059 val += ch - '0'; 3050*1959748cSgd78059 } else if (ch == 0) { 3051*1959748cSgd78059 return (val); 3052*1959748cSgd78059 } else { 3053*1959748cSgd78059 /* parse error, put back rptr */ 3054*1959748cSgd78059 mp->b_rptr--; 3055*1959748cSgd78059 return (val); 3056*1959748cSgd78059 } 3057*1959748cSgd78059 } 3058*1959748cSgd78059 mp = mp->b_cont; 3059*1959748cSgd78059 } 3060*1959748cSgd78059 return (val); 3061*1959748cSgd78059 } 3062*1959748cSgd78059 3063*1959748cSgd78059 void 3064*1959748cSgd78059 afe_ndparsestring(mblk_t *mp, char *buf, int maxlen) 3065*1959748cSgd78059 { 3066*1959748cSgd78059 int done = 0; 3067*1959748cSgd78059 int len = 0; 3068*1959748cSgd78059 3069*1959748cSgd78059 /* ensure null termination */ 3070*1959748cSgd78059 buf[maxlen - 1] = 0; 3071*1959748cSgd78059 while (mp && !done) { 3072*1959748cSgd78059 while (mp->b_rptr < mp->b_wptr) { 3073*1959748cSgd78059 char ch = *((char *)mp->b_rptr); 3074*1959748cSgd78059 mp->b_rptr++; 3075*1959748cSgd78059 buf[len++] = ch; 3076*1959748cSgd78059 if ((ch == 0) || (len == maxlen)) { 3077*1959748cSgd78059 return; 3078*1959748cSgd78059 } 3079*1959748cSgd78059 } 3080*1959748cSgd78059 mp = mp->b_cont; 3081*1959748cSgd78059 } 3082*1959748cSgd78059 } 3083*1959748cSgd78059 3084*1959748cSgd78059 int 3085*1959748cSgd78059 afe_ndquestion(afe_t *afep, mblk_t *mp, afe_nd_t *ndp) 3086*1959748cSgd78059 { 3087*1959748cSgd78059 for (ndp = afep->afe_ndp; ndp; ndp = ndp->nd_next) { 3088*1959748cSgd78059 int rv; 3089*1959748cSgd78059 char *s; 3090*1959748cSgd78059 if ((rv = afe_ndaddstr(mp, ndp->nd_name, 0)) != 0) { 3091*1959748cSgd78059 return (rv); 3092*1959748cSgd78059 } 3093*1959748cSgd78059 if (ndp->nd_get && ndp->nd_set) { 3094*1959748cSgd78059 s = " (read and write)"; 3095*1959748cSgd78059 } else if (ndp->nd_get) { 3096*1959748cSgd78059 s = " (read only)"; 3097*1959748cSgd78059 } else if (ndp->nd_set) { 3098*1959748cSgd78059 s = " (write only)"; 3099*1959748cSgd78059 } else { 3100*1959748cSgd78059 s = " (no read or write)"; 3101*1959748cSgd78059 } 3102*1959748cSgd78059 if ((rv = afe_ndaddstr(mp, s, 1)) != 0) { 3103*1959748cSgd78059 return (rv); 3104*1959748cSgd78059 } 3105*1959748cSgd78059 } 3106*1959748cSgd78059 return (0); 3107*1959748cSgd78059 } 3108*1959748cSgd78059 3109*1959748cSgd78059 /*ARGSUSED*/ 3110*1959748cSgd78059 int 3111*1959748cSgd78059 afe_ndgetint(afe_t *afep, mblk_t *mp, afe_nd_t *ndp) 3112*1959748cSgd78059 { 3113*1959748cSgd78059 int val; 3114*1959748cSgd78059 char buf[16]; 3115*1959748cSgd78059 3116*1959748cSgd78059 val = *(int *)ndp->nd_arg1; 3117*1959748cSgd78059 3118*1959748cSgd78059 (void) snprintf(buf, sizeof (buf), "%d", val); 3119*1959748cSgd78059 return (afe_ndaddstr(mp, buf, 1)); 3120*1959748cSgd78059 } 3121*1959748cSgd78059 3122*1959748cSgd78059 int 3123*1959748cSgd78059 afe_ndgetmiibit(afe_t *afep, mblk_t *mp, afe_nd_t *ndp) 3124*1959748cSgd78059 { 3125*1959748cSgd78059 unsigned val; 3126*1959748cSgd78059 unsigned mask; 3127*1959748cSgd78059 int reg; 3128*1959748cSgd78059 3129*1959748cSgd78059 reg = (int)ndp->nd_arg1; 3130*1959748cSgd78059 mask = (unsigned)ndp->nd_arg2; 3131*1959748cSgd78059 3132*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 3133*1959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 3134*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 3135*1959748cSgd78059 /* device is suspended */ 3136*1959748cSgd78059 return (EIO); 3137*1959748cSgd78059 } 3138*1959748cSgd78059 val = afe_miiread(afep, afep->afe_phyaddr, reg); 3139*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 3140*1959748cSgd78059 3141*1959748cSgd78059 return (afe_ndaddstr(mp, val & mask ? "1" : "0", 1)); 3142*1959748cSgd78059 } 3143*1959748cSgd78059 3144*1959748cSgd78059 int 3145*1959748cSgd78059 afe_ndsetadv(afe_t *afep, mblk_t *mp, afe_nd_t *ndp) 3146*1959748cSgd78059 { 3147*1959748cSgd78059 unsigned *ptr = (unsigned *)ndp->nd_arg1; 3148*1959748cSgd78059 unsigned oldval, newval; 3149*1959748cSgd78059 3150*1959748cSgd78059 newval = afe_ndparseint(mp) ? 1 : 0; 3151*1959748cSgd78059 3152*1959748cSgd78059 mutex_enter(&afep->afe_intrlock); 3153*1959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 3154*1959748cSgd78059 3155*1959748cSgd78059 oldval = *ptr; 3156*1959748cSgd78059 if (oldval != newval) { 3157*1959748cSgd78059 *ptr = newval; 3158*1959748cSgd78059 if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == 3159*1959748cSgd78059 AFE_RUNNING) { 3160*1959748cSgd78059 /* 3161*1959748cSgd78059 * This re-initializes the phy, but it also 3162*1959748cSgd78059 * restarts transmit and receive rings. 3163*1959748cSgd78059 * Needless to say, changing the link 3164*1959748cSgd78059 * parameters is destructive to traffic in 3165*1959748cSgd78059 * progress. 3166*1959748cSgd78059 */ 3167*1959748cSgd78059 afe_resetall(afep); 3168*1959748cSgd78059 } 3169*1959748cSgd78059 } 3170*1959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 3171*1959748cSgd78059 mutex_exit(&afep->afe_intrlock); 3172*1959748cSgd78059 3173*1959748cSgd78059 return (0); 3174*1959748cSgd78059 } 3175*1959748cSgd78059 3176*1959748cSgd78059 void 3177*1959748cSgd78059 afe_ndfini(afe_t *afep) 3178*1959748cSgd78059 { 3179*1959748cSgd78059 afe_nd_t *ndp; 3180*1959748cSgd78059 3181*1959748cSgd78059 while ((ndp = afep->afe_ndp) != NULL) { 3182*1959748cSgd78059 afep->afe_ndp = ndp->nd_next; 3183*1959748cSgd78059 kmem_free(ndp, sizeof (afe_nd_t)); 3184*1959748cSgd78059 } 3185*1959748cSgd78059 } 3186*1959748cSgd78059 3187*1959748cSgd78059 void 3188*1959748cSgd78059 afe_ndinit(afe_t *afep) 3189*1959748cSgd78059 { 3190*1959748cSgd78059 afe_ndadd(afep, "?", afe_ndquestion, NULL, 0, 0); 3191*1959748cSgd78059 afe_ndadd(afep, "link_status", afe_ndgetint, NULL, 3192*1959748cSgd78059 (intptr_t)&afep->afe_linkup, 0); 3193*1959748cSgd78059 afe_ndadd(afep, "link_speed", afe_ndgetint, NULL, 3194*1959748cSgd78059 (intptr_t)&afep->afe_ifspeed, 0); 3195*1959748cSgd78059 afe_ndadd(afep, "link_duplex", afe_ndgetint, NULL, 3196*1959748cSgd78059 (intptr_t)&afep->afe_duplex, 0); 3197*1959748cSgd78059 afe_ndadd(afep, "adv_autoneg_cap", afe_ndgetint, afe_ndsetadv, 3198*1959748cSgd78059 (intptr_t)&afep->afe_adv_aneg, 0); 3199*1959748cSgd78059 afe_ndadd(afep, "adv_100T4_cap", afe_ndgetint, afe_ndsetadv, 3200*1959748cSgd78059 (intptr_t)&afep->afe_adv_100T4, 0); 3201*1959748cSgd78059 afe_ndadd(afep, "adv_100fdx_cap", afe_ndgetint, afe_ndsetadv, 3202*1959748cSgd78059 (intptr_t)&afep->afe_adv_100fdx, 0); 3203*1959748cSgd78059 afe_ndadd(afep, "adv_100hdx_cap", afe_ndgetint, afe_ndsetadv, 3204*1959748cSgd78059 (intptr_t)&afep->afe_adv_100hdx, 0); 3205*1959748cSgd78059 afe_ndadd(afep, "adv_10fdx_cap", afe_ndgetint, afe_ndsetadv, 3206*1959748cSgd78059 (intptr_t)&afep->afe_adv_10fdx, 0); 3207*1959748cSgd78059 afe_ndadd(afep, "adv_10hdx_cap", afe_ndgetint, afe_ndsetadv, 3208*1959748cSgd78059 (intptr_t)&afep->afe_adv_10hdx, 0); 3209*1959748cSgd78059 afe_ndadd(afep, "autoneg_cap", afe_ndgetmiibit, NULL, 3210*1959748cSgd78059 MII_STATUS, MII_STATUS_CANAUTONEG); 3211*1959748cSgd78059 afe_ndadd(afep, "100T4_cap", afe_ndgetmiibit, NULL, 3212*1959748cSgd78059 MII_STATUS, MII_STATUS_100_BASE_T4); 3213*1959748cSgd78059 afe_ndadd(afep, "100fdx_cap", afe_ndgetmiibit, NULL, 3214*1959748cSgd78059 MII_STATUS, MII_STATUS_100_BASEX_FD); 3215*1959748cSgd78059 afe_ndadd(afep, "100hdx_cap", afe_ndgetmiibit, NULL, 3216*1959748cSgd78059 MII_STATUS, MII_STATUS_100_BASEX); 3217*1959748cSgd78059 afe_ndadd(afep, "10fdx_cap", afe_ndgetmiibit, NULL, 3218*1959748cSgd78059 MII_STATUS, MII_STATUS_10_FD); 3219*1959748cSgd78059 afe_ndadd(afep, "10hdx_cap", afe_ndgetmiibit, NULL, 3220*1959748cSgd78059 MII_STATUS, MII_STATUS_10); 3221*1959748cSgd78059 afe_ndadd(afep, "lp_autoneg_cap", afe_ndgetmiibit, NULL, 3222*1959748cSgd78059 MII_AN_EXPANSION, MII_AN_EXP_LPCANAN); 3223*1959748cSgd78059 afe_ndadd(afep, "lp_100T4_cap", afe_ndgetmiibit, NULL, 3224*1959748cSgd78059 MII_AN_LPABLE, MII_ABILITY_100BASE_T4); 3225*1959748cSgd78059 afe_ndadd(afep, "lp_100fdx_cap", afe_ndgetmiibit, NULL, 3226*1959748cSgd78059 MII_AN_LPABLE, MII_ABILITY_100BASE_TX_FD); 3227*1959748cSgd78059 afe_ndadd(afep, "lp_100hdx_cap", afe_ndgetmiibit, NULL, 3228*1959748cSgd78059 MII_AN_LPABLE, MII_ABILITY_100BASE_TX); 3229*1959748cSgd78059 afe_ndadd(afep, "lp_10fdx_cap", afe_ndgetmiibit, NULL, 3230*1959748cSgd78059 MII_AN_LPABLE, MII_ABILITY_10BASE_T_FD); 3231*1959748cSgd78059 afe_ndadd(afep, "lp_10hdx_cap", afe_ndgetmiibit, NULL, 3232*1959748cSgd78059 MII_AN_LPABLE, MII_ABILITY_10BASE_T); 3233*1959748cSgd78059 } 3234*1959748cSgd78059 3235*1959748cSgd78059 /* 3236*1959748cSgd78059 * Debugging and error reporting. 3237*1959748cSgd78059 */ 3238*1959748cSgd78059 void 3239*1959748cSgd78059 afe_error(dev_info_t *dip, char *fmt, ...) 3240*1959748cSgd78059 { 3241*1959748cSgd78059 va_list ap; 3242*1959748cSgd78059 char buf[256]; 3243*1959748cSgd78059 3244*1959748cSgd78059 va_start(ap, fmt); 3245*1959748cSgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 3246*1959748cSgd78059 va_end(ap); 3247*1959748cSgd78059 3248*1959748cSgd78059 if (dip) { 3249*1959748cSgd78059 cmn_err(CE_WARN, "%s%d: %s", 3250*1959748cSgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf); 3251*1959748cSgd78059 } else { 3252*1959748cSgd78059 cmn_err(CE_WARN, "afe: %s", buf); 3253*1959748cSgd78059 } 3254*1959748cSgd78059 } 3255*1959748cSgd78059 3256*1959748cSgd78059 #ifdef DEBUG 3257*1959748cSgd78059 3258*1959748cSgd78059 void 3259*1959748cSgd78059 afe_dprintf(afe_t *afep, const char *func, int level, char *fmt, ...) 3260*1959748cSgd78059 { 3261*1959748cSgd78059 va_list ap; 3262*1959748cSgd78059 3263*1959748cSgd78059 va_start(ap, fmt); 3264*1959748cSgd78059 if (afe_debug & level) { 3265*1959748cSgd78059 char tag[64]; 3266*1959748cSgd78059 char buf[256]; 3267*1959748cSgd78059 3268*1959748cSgd78059 if (afep && afep->afe_dip) { 3269*1959748cSgd78059 (void) snprintf(tag, sizeof (tag), "%s%d", 3270*1959748cSgd78059 ddi_driver_name(afep->afe_dip), 3271*1959748cSgd78059 ddi_get_instance(afep->afe_dip)); 3272*1959748cSgd78059 } else { 3273*1959748cSgd78059 (void) snprintf(tag, sizeof (tag), "afe"); 3274*1959748cSgd78059 } 3275*1959748cSgd78059 3276*1959748cSgd78059 (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", 3277*1959748cSgd78059 tag, func, fmt); 3278*1959748cSgd78059 3279*1959748cSgd78059 vcmn_err(CE_CONT, buf, ap); 3280*1959748cSgd78059 } 3281*1959748cSgd78059 va_end(ap); 3282*1959748cSgd78059 } 3283*1959748cSgd78059 3284*1959748cSgd78059 #endif 3285