11959748cSgd78059 /* 21959748cSgd78059 * Solaris driver for ethernet cards based on the ADMtek Centaur 31959748cSgd78059 * 41959748cSgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>. 51959748cSgd78059 * All rights reserved. 61959748cSgd78059 * 71959748cSgd78059 * Redistribution and use in source and binary forms, with or without 81959748cSgd78059 * modification, are permitted provided that the following conditions 91959748cSgd78059 * are met: 101959748cSgd78059 * 1. Redistributions of source code must retain the above copyright 111959748cSgd78059 * notice, this list of conditions and the following disclaimer. 121959748cSgd78059 * 2. Redistributions in binary form must reproduce the above copyright 131959748cSgd78059 * notice, this list of conditions and the following disclaimer in the 141959748cSgd78059 * documentation and/or other materials provided with the distribution. 151959748cSgd78059 * 3. Neither the name of the author nor the names of any co-contributors 161959748cSgd78059 * may be used to endorse or promote products derived from this software 171959748cSgd78059 * without specific prior written permission. 181959748cSgd78059 * 191959748cSgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' 201959748cSgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211959748cSgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221959748cSgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 231959748cSgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241959748cSgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251959748cSgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261959748cSgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271959748cSgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281959748cSgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291959748cSgd78059 * POSSIBILITY OF SUCH DAMAGE. 301959748cSgd78059 */ 3196fb08b9Sgd78059 /* 32*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3396fb08b9Sgd78059 * Use is subject to license terms. 3496fb08b9Sgd78059 */ 351959748cSgd78059 361959748cSgd78059 371959748cSgd78059 #include <sys/varargs.h> 381959748cSgd78059 #include <sys/types.h> 391959748cSgd78059 #include <sys/modctl.h> 401959748cSgd78059 #include <sys/conf.h> 411959748cSgd78059 #include <sys/devops.h> 421959748cSgd78059 #include <sys/stream.h> 431959748cSgd78059 #include <sys/strsun.h> 441959748cSgd78059 #include <sys/cmn_err.h> 451959748cSgd78059 #include <sys/ethernet.h> 461959748cSgd78059 #include <sys/kmem.h> 471959748cSgd78059 #include <sys/time.h> 481959748cSgd78059 #include <sys/crc32.h> 49bdb9230aSGarrett D'Amore #include <sys/mii.h> 501959748cSgd78059 #include <sys/miiregs.h> 511959748cSgd78059 #include <sys/mac.h> 521959748cSgd78059 #include <sys/mac_ether.h> 531959748cSgd78059 #include <sys/ddi.h> 541959748cSgd78059 #include <sys/sunddi.h> 55d62bc4baSyz147064 #include <sys/vlan.h> 561959748cSgd78059 571959748cSgd78059 #include "afe.h" 581959748cSgd78059 #include "afeimpl.h" 591959748cSgd78059 601959748cSgd78059 /* 611959748cSgd78059 * Driver globals. 621959748cSgd78059 */ 631959748cSgd78059 641959748cSgd78059 /* table of supported devices */ 651959748cSgd78059 static afe_card_t afe_cards[] = { 661959748cSgd78059 671959748cSgd78059 /* 681959748cSgd78059 * ADMtek Centaur and Comet 691959748cSgd78059 */ 701959748cSgd78059 { 0x1317, 0x0981, "ADMtek AL981", MODEL_COMET }, 711959748cSgd78059 { 0x1317, 0x0985, "ADMtek AN983", MODEL_CENTAUR }, 721959748cSgd78059 { 0x1317, 0x1985, "ADMtek AN985", MODEL_CENTAUR }, 731959748cSgd78059 { 0x1317, 0x9511, "ADMtek ADM9511", MODEL_CENTAUR }, 741959748cSgd78059 { 0x1317, 0x9513, "ADMtek ADM9513", MODEL_CENTAUR }, 751959748cSgd78059 /* 761959748cSgd78059 * Accton just relabels other companies' controllers 771959748cSgd78059 */ 781959748cSgd78059 { 0x1113, 0x1216, "Accton EN5251", MODEL_CENTAUR }, 791959748cSgd78059 /* 801959748cSgd78059 * Models listed here. 811959748cSgd78059 */ 821959748cSgd78059 { 0x10b7, 0x9300, "3Com 3CSOHO100B-TX", MODEL_CENTAUR }, 831959748cSgd78059 { 0x1113, 0xec02, "SMC SMC1244TX", MODEL_CENTAUR }, 841959748cSgd78059 { 0x10b8, 0x1255, "SMC SMC1255TX", MODEL_CENTAUR }, 851959748cSgd78059 { 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR }, 861959748cSgd78059 { 0x1113, 0x1207, "Accton EN1207F", MODEL_CENTAUR }, 871959748cSgd78059 { 0x1113, 0x2242, "Accton EN2242", MODEL_CENTAUR }, 881959748cSgd78059 { 0x1113, 0x2220, "Accton EN2220", MODEL_CENTAUR }, 891959748cSgd78059 { 0x1113, 0x9216, "3M VOL-N100VF+TX", MODEL_CENTAUR }, 901959748cSgd78059 { 0x1317, 0x0574, "Linksys LNE100TX", MODEL_CENTAUR }, 911959748cSgd78059 { 0x1317, 0x0570, "Linksys NC100", MODEL_CENTAUR }, 921959748cSgd78059 { 0x1385, 0x511a, "Netgear FA511", MODEL_CENTAUR }, 931959748cSgd78059 { 0x13d1, 0xab02, "AboCom FE2500", MODEL_CENTAUR }, 941959748cSgd78059 { 0x13d1, 0xab03, "AboCom PCM200", MODEL_CENTAUR }, 951959748cSgd78059 { 0x13d1, 0xab08, "AboCom FE2500MX", MODEL_CENTAUR }, 961959748cSgd78059 { 0x1414, 0x0001, "Microsoft MN-120", MODEL_CENTAUR }, 971959748cSgd78059 { 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR }, 981959748cSgd78059 { 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR }, 991959748cSgd78059 { 0x1737, 0xab08, "Linksys PCMPC200", MODEL_CENTAUR }, 1001959748cSgd78059 { 0x1737, 0xab09, "Linksys PCM200", MODEL_CENTAUR }, 1011959748cSgd78059 { 0x17b3, 0xab08, "Hawking PN672TX", MODEL_CENTAUR }, 1021959748cSgd78059 }; 1031959748cSgd78059 1041959748cSgd78059 #define ETHERVLANMTU (ETHERMAX + 4) 1051959748cSgd78059 1061959748cSgd78059 /* 1071959748cSgd78059 * Function prototypes 1081959748cSgd78059 */ 1091959748cSgd78059 static int afe_attach(dev_info_t *, ddi_attach_cmd_t); 1101959748cSgd78059 static int afe_detach(dev_info_t *, ddi_detach_cmd_t); 1111959748cSgd78059 static int afe_resume(dev_info_t *); 11238415b01SGarrett D'Amore static int afe_quiesce(dev_info_t *); 1131959748cSgd78059 static int afe_m_unicst(void *, const uint8_t *); 1141959748cSgd78059 static int afe_m_multicst(void *, boolean_t, const uint8_t *); 1151959748cSgd78059 static int afe_m_promisc(void *, boolean_t); 1161959748cSgd78059 static mblk_t *afe_m_tx(void *, mblk_t *); 117bdb9230aSGarrett D'Amore static void afe_m_ioctl(void *, queue_t *, mblk_t *); 1181959748cSgd78059 static int afe_m_stat(void *, uint_t, uint64_t *); 1191959748cSgd78059 static int afe_m_start(void *); 1201959748cSgd78059 static void afe_m_stop(void *); 12196fb08b9Sgd78059 static int afe_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 122*0dc2366fSVenugopal Iyer void *); 12396fb08b9Sgd78059 static int afe_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 12496fb08b9Sgd78059 const void *); 125*0dc2366fSVenugopal Iyer static void afe_m_propinfo(void *, const char *, mac_prop_id_t, 126*0dc2366fSVenugopal Iyer mac_prop_info_handle_t); 1271959748cSgd78059 static unsigned afe_intr(caddr_t); 1281959748cSgd78059 static void afe_startmac(afe_t *); 1291959748cSgd78059 static void afe_stopmac(afe_t *); 1301959748cSgd78059 static void afe_resetrings(afe_t *); 1311959748cSgd78059 static boolean_t afe_initialize(afe_t *); 1321959748cSgd78059 static void afe_startall(afe_t *); 1331959748cSgd78059 static void afe_stopall(afe_t *); 1341959748cSgd78059 static void afe_resetall(afe_t *); 1351959748cSgd78059 static afe_txbuf_t *afe_alloctxbuf(afe_t *); 1361959748cSgd78059 static void afe_destroytxbuf(afe_txbuf_t *); 1371959748cSgd78059 static afe_rxbuf_t *afe_allocrxbuf(afe_t *); 1381959748cSgd78059 static void afe_destroyrxbuf(afe_rxbuf_t *); 1391959748cSgd78059 static boolean_t afe_send(afe_t *, mblk_t *); 1401959748cSgd78059 static int afe_allocrxring(afe_t *); 1411959748cSgd78059 static void afe_freerxring(afe_t *); 1421959748cSgd78059 static int afe_alloctxring(afe_t *); 1431959748cSgd78059 static void afe_freetxring(afe_t *); 1441959748cSgd78059 static void afe_error(dev_info_t *, char *, ...); 1451959748cSgd78059 static void afe_setrxfilt(afe_t *); 146bdb9230aSGarrett D'Amore static int afe_watchdog(afe_t *); 1471959748cSgd78059 static uint8_t afe_sromwidth(afe_t *); 1481959748cSgd78059 static uint16_t afe_readsromword(afe_t *, unsigned); 1491959748cSgd78059 static void afe_readsrom(afe_t *, unsigned, unsigned, char *); 1501959748cSgd78059 static void afe_getfactaddr(afe_t *, uchar_t *); 15196fb08b9Sgd78059 static uint8_t afe_miireadbit(afe_t *); 15296fb08b9Sgd78059 static void afe_miiwritebit(afe_t *, uint8_t); 1531959748cSgd78059 static void afe_miitristate(afe_t *); 154bdb9230aSGarrett D'Amore static uint16_t afe_miireadgeneral(afe_t *, uint8_t, uint8_t); 155bdb9230aSGarrett D'Amore static void afe_miiwritegeneral(afe_t *, uint8_t, uint8_t, uint16_t); 156bdb9230aSGarrett D'Amore static uint16_t afe_miireadcomet(afe_t *, uint8_t, uint8_t); 157bdb9230aSGarrett D'Amore static void afe_miiwritecomet(afe_t *, uint8_t, uint8_t, uint16_t); 158bdb9230aSGarrett D'Amore static uint16_t afe_mii_read(void *, uint8_t, uint8_t); 159bdb9230aSGarrett D'Amore static void afe_mii_write(void *, uint8_t, uint8_t, uint16_t); 160bdb9230aSGarrett D'Amore static void afe_mii_notify(void *, link_state_t); 161bdb9230aSGarrett D'Amore static void afe_mii_reset(void *); 1621959748cSgd78059 static void afe_disableinterrupts(afe_t *); 1631959748cSgd78059 static void afe_enableinterrupts(afe_t *); 1641959748cSgd78059 static void afe_reclaim(afe_t *); 1651959748cSgd78059 static mblk_t *afe_receive(afe_t *); 1661959748cSgd78059 1671959748cSgd78059 #define KIOIP KSTAT_INTR_PTR(afep->afe_intrstat) 1681959748cSgd78059 169bdb9230aSGarrett D'Amore static mii_ops_t afe_mii_ops = { 170bdb9230aSGarrett D'Amore MII_OPS_VERSION, 171bdb9230aSGarrett D'Amore afe_mii_read, 172bdb9230aSGarrett D'Amore afe_mii_write, 173bdb9230aSGarrett D'Amore afe_mii_notify, 174bdb9230aSGarrett D'Amore afe_mii_reset 175bdb9230aSGarrett D'Amore }; 176bdb9230aSGarrett D'Amore 1771959748cSgd78059 static mac_callbacks_t afe_m_callbacks = { 178*0dc2366fSVenugopal Iyer MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 1791959748cSgd78059 afe_m_stat, 1801959748cSgd78059 afe_m_start, 1811959748cSgd78059 afe_m_stop, 1821959748cSgd78059 afe_m_promisc, 1831959748cSgd78059 afe_m_multicst, 1841959748cSgd78059 afe_m_unicst, 1851959748cSgd78059 afe_m_tx, 186*0dc2366fSVenugopal Iyer NULL, 187bdb9230aSGarrett D'Amore afe_m_ioctl, /* mc_ioctl */ 18896fb08b9Sgd78059 NULL, /* mc_getcapab */ 18996fb08b9Sgd78059 NULL, /* mc_open */ 19096fb08b9Sgd78059 NULL, /* mc_close */ 19196fb08b9Sgd78059 afe_m_setprop, 19296fb08b9Sgd78059 afe_m_getprop, 193*0dc2366fSVenugopal Iyer afe_m_propinfo 1941959748cSgd78059 }; 1951959748cSgd78059 1961959748cSgd78059 1971959748cSgd78059 /* 1981959748cSgd78059 * Stream information 1991959748cSgd78059 */ 2001959748cSgd78059 DDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach, 20138415b01SGarrett D'Amore nodev, NULL, D_MP, NULL, afe_quiesce); 2021959748cSgd78059 2031959748cSgd78059 /* 2041959748cSgd78059 * Module linkage information. 2051959748cSgd78059 */ 2061959748cSgd78059 2071959748cSgd78059 static struct modldrv afe_modldrv = { 2081959748cSgd78059 &mod_driverops, /* drv_modops */ 2091959748cSgd78059 "ADMtek Fast Ethernet", /* drv_linkinfo */ 2101959748cSgd78059 &afe_devops /* drv_dev_ops */ 2111959748cSgd78059 }; 2121959748cSgd78059 2131959748cSgd78059 static struct modlinkage afe_modlinkage = { 2141959748cSgd78059 MODREV_1, /* ml_rev */ 2151959748cSgd78059 { &afe_modldrv, NULL } /* ml_linkage */ 2161959748cSgd78059 }; 2171959748cSgd78059 2181959748cSgd78059 /* 2191959748cSgd78059 * Device attributes. 2201959748cSgd78059 */ 2211959748cSgd78059 static ddi_device_acc_attr_t afe_devattr = { 2221959748cSgd78059 DDI_DEVICE_ATTR_V0, 2231959748cSgd78059 DDI_STRUCTURE_LE_ACC, 2241959748cSgd78059 DDI_STRICTORDER_ACC 2251959748cSgd78059 }; 2261959748cSgd78059 2271959748cSgd78059 static ddi_device_acc_attr_t afe_bufattr = { 2281959748cSgd78059 DDI_DEVICE_ATTR_V0, 2291959748cSgd78059 DDI_NEVERSWAP_ACC, 2301959748cSgd78059 DDI_STRICTORDER_ACC 2311959748cSgd78059 }; 2321959748cSgd78059 2331959748cSgd78059 static ddi_dma_attr_t afe_dma_attr = { 2341959748cSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 2351959748cSgd78059 0, /* dma_attr_addr_lo */ 2361959748cSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 2371959748cSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 2381959748cSgd78059 4, /* dma_attr_align */ 2391959748cSgd78059 0x3F, /* dma_attr_burstsizes */ 2401959748cSgd78059 1, /* dma_attr_minxfer */ 2411959748cSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 2421959748cSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 2431959748cSgd78059 1, /* dma_attr_sgllen */ 2441959748cSgd78059 1, /* dma_attr_granular */ 2451959748cSgd78059 0 /* dma_attr_flags */ 2461959748cSgd78059 }; 2471959748cSgd78059 2481959748cSgd78059 /* 2491959748cSgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can 2501959748cSgd78059 * cross a page boundary, so we use the two buffer addresses of the 2511959748cSgd78059 * chip to provide a two-entry scatter-gather list. 2521959748cSgd78059 */ 2531959748cSgd78059 static ddi_dma_attr_t afe_dma_txattr = { 2541959748cSgd78059 DMA_ATTR_V0, /* dma_attr_version */ 2551959748cSgd78059 0, /* dma_attr_addr_lo */ 2561959748cSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 2571959748cSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 2581959748cSgd78059 1, /* dma_attr_align */ 2591959748cSgd78059 0x3F, /* dma_attr_burstsizes */ 2601959748cSgd78059 1, /* dma_attr_minxfer */ 2611959748cSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 2621959748cSgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 2631959748cSgd78059 2, /* dma_attr_sgllen */ 2641959748cSgd78059 1, /* dma_attr_granular */ 2651959748cSgd78059 0 /* dma_attr_flags */ 2661959748cSgd78059 }; 2671959748cSgd78059 2681959748cSgd78059 /* 2691959748cSgd78059 * Ethernet addresses. 2701959748cSgd78059 */ 2711959748cSgd78059 static uchar_t afe_broadcast[ETHERADDRL] = { 2721959748cSgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2731959748cSgd78059 }; 2741959748cSgd78059 2751959748cSgd78059 /* 2761959748cSgd78059 * DDI entry points. 2771959748cSgd78059 */ 2781959748cSgd78059 int 2791959748cSgd78059 _init(void) 2801959748cSgd78059 { 2811959748cSgd78059 int rv; 2821959748cSgd78059 mac_init_ops(&afe_devops, "afe"); 2831959748cSgd78059 if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) { 2841959748cSgd78059 mac_fini_ops(&afe_devops); 2851959748cSgd78059 } 2861959748cSgd78059 return (rv); 2871959748cSgd78059 } 2881959748cSgd78059 2891959748cSgd78059 int 2901959748cSgd78059 _fini(void) 2911959748cSgd78059 { 2921959748cSgd78059 int rv; 2931959748cSgd78059 if ((rv = mod_remove(&afe_modlinkage)) == DDI_SUCCESS) { 2941959748cSgd78059 mac_fini_ops(&afe_devops); 2951959748cSgd78059 } 2961959748cSgd78059 return (rv); 2971959748cSgd78059 } 2981959748cSgd78059 2991959748cSgd78059 int 3001959748cSgd78059 _info(struct modinfo *modinfop) 3011959748cSgd78059 { 3021959748cSgd78059 return (mod_info(&afe_modlinkage, modinfop)); 3031959748cSgd78059 } 3041959748cSgd78059 3051959748cSgd78059 int 3061959748cSgd78059 afe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3071959748cSgd78059 { 3081959748cSgd78059 afe_t *afep; 3091959748cSgd78059 mac_register_t *macp; 3101959748cSgd78059 int inst = ddi_get_instance(dip); 3111959748cSgd78059 ddi_acc_handle_t pci; 3121959748cSgd78059 uint16_t venid; 3131959748cSgd78059 uint16_t devid; 3141959748cSgd78059 uint16_t svid; 3151959748cSgd78059 uint16_t ssid; 3161959748cSgd78059 uint16_t cachesize; 3171959748cSgd78059 afe_card_t *cardp; 3181959748cSgd78059 int i; 3191959748cSgd78059 3201959748cSgd78059 switch (cmd) { 3211959748cSgd78059 case DDI_RESUME: 3221959748cSgd78059 return (afe_resume(dip)); 3231959748cSgd78059 3241959748cSgd78059 case DDI_ATTACH: 3251959748cSgd78059 break; 3261959748cSgd78059 3271959748cSgd78059 default: 3281959748cSgd78059 return (DDI_FAILURE); 3291959748cSgd78059 } 3301959748cSgd78059 3311959748cSgd78059 /* this card is a bus master, reject any slave-only slot */ 3321959748cSgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) { 3331959748cSgd78059 afe_error(dip, "slot does not support PCI bus-master"); 3341959748cSgd78059 return (DDI_FAILURE); 3351959748cSgd78059 } 3361959748cSgd78059 /* PCI devices shouldn't generate hilevel interrupts */ 3371959748cSgd78059 if (ddi_intr_hilevel(dip, 0) != 0) { 3381959748cSgd78059 afe_error(dip, "hilevel interrupts not supported"); 3391959748cSgd78059 return (DDI_FAILURE); 3401959748cSgd78059 } 3411959748cSgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 3421959748cSgd78059 afe_error(dip, "unable to setup PCI config handle"); 3431959748cSgd78059 return (DDI_FAILURE); 3441959748cSgd78059 } 3451959748cSgd78059 3461959748cSgd78059 venid = pci_config_get16(pci, PCI_VID); 3471959748cSgd78059 devid = pci_config_get16(pci, PCI_DID); 3481959748cSgd78059 svid = pci_config_get16(pci, PCI_SVID); 3491959748cSgd78059 ssid = pci_config_get16(pci, PCI_SSID); 3501959748cSgd78059 3511959748cSgd78059 /* 3521959748cSgd78059 * Note: ADMtek boards seem to misprogram themselves with bogus 3531959748cSgd78059 * timings, which do not seem to work properly on SPARC. We 3541959748cSgd78059 * reprogram them zero (but only if they appear to be broken), 3551959748cSgd78059 * which seems to at least work. Its unclear that this is a 3561959748cSgd78059 * legal or wise practice to me, but it certainly works better 3571959748cSgd78059 * than the original values. (I would love to hear 3581959748cSgd78059 * suggestions for better values, or a better strategy.) 3591959748cSgd78059 */ 3601959748cSgd78059 if ((pci_config_get8(pci, PCI_MINGNT) == 0xff) && 3611959748cSgd78059 (pci_config_get8(pci, PCI_MAXLAT) == 0xff)) { 3621959748cSgd78059 pci_config_put8(pci, PCI_MINGNT, 0); 3631959748cSgd78059 pci_config_put8(pci, PCI_MAXLAT, 0); 3641959748cSgd78059 } 3651959748cSgd78059 3661959748cSgd78059 /* 3671959748cSgd78059 * the last entry in the card table matches every possible 3681959748cSgd78059 * card, so the for-loop always terminates properly. 3691959748cSgd78059 */ 3701959748cSgd78059 cardp = NULL; 3711959748cSgd78059 for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) { 3721959748cSgd78059 if ((venid == afe_cards[i].card_venid) && 3731959748cSgd78059 (devid == afe_cards[i].card_devid)) { 3741959748cSgd78059 cardp = &afe_cards[i]; 3751959748cSgd78059 } 3761959748cSgd78059 if ((svid == afe_cards[i].card_venid) && 3771959748cSgd78059 (ssid == afe_cards[i].card_devid)) { 3781959748cSgd78059 cardp = &afe_cards[i]; 3791959748cSgd78059 break; 3801959748cSgd78059 } 3811959748cSgd78059 } 3821959748cSgd78059 3831959748cSgd78059 if (cardp == NULL) { 3841959748cSgd78059 pci_config_teardown(&pci); 3851959748cSgd78059 afe_error(dip, "Unable to identify PCI card"); 3861959748cSgd78059 return (DDI_FAILURE); 3871959748cSgd78059 } 3881959748cSgd78059 3891959748cSgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model", 3901959748cSgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) { 3911959748cSgd78059 pci_config_teardown(&pci); 3921959748cSgd78059 afe_error(dip, "Unable to create model property"); 3931959748cSgd78059 return (DDI_FAILURE); 3941959748cSgd78059 } 3951959748cSgd78059 3961959748cSgd78059 /* 3971959748cSgd78059 * Grab the PCI cachesize -- we use this to program the 3981959748cSgd78059 * cache-optimization bus access bits. 3991959748cSgd78059 */ 4001959748cSgd78059 cachesize = pci_config_get8(pci, PCI_CLS); 4011959748cSgd78059 4021959748cSgd78059 /* this cannot fail */ 4031959748cSgd78059 afep = kmem_zalloc(sizeof (afe_t), KM_SLEEP); 4041959748cSgd78059 ddi_set_driver_private(dip, afep); 4051959748cSgd78059 4061959748cSgd78059 /* get the interrupt block cookie */ 4071959748cSgd78059 if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) { 4081959748cSgd78059 afe_error(dip, "ddi_get_iblock_cookie failed"); 4091959748cSgd78059 pci_config_teardown(&pci); 4101959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 4111959748cSgd78059 return (DDI_FAILURE); 4121959748cSgd78059 } 4131959748cSgd78059 4141959748cSgd78059 afep->afe_dip = dip; 4151959748cSgd78059 afep->afe_cardp = cardp; 4161959748cSgd78059 afep->afe_phyaddr = -1; 4171959748cSgd78059 afep->afe_cachesize = cachesize; 4181959748cSgd78059 4191959748cSgd78059 afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4201959748cSgd78059 "fiber", 0); 4211959748cSgd78059 4221959748cSgd78059 mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie); 4231959748cSgd78059 mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie); 4241959748cSgd78059 4251959748cSgd78059 /* 4261959748cSgd78059 * Enable bus master, IO space, and memory space accesses. 4271959748cSgd78059 */ 4281959748cSgd78059 pci_config_put16(pci, PCI_CMD, 4291959748cSgd78059 pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE); 4301959748cSgd78059 4311959748cSgd78059 /* we're done with this now, drop it */ 4321959748cSgd78059 pci_config_teardown(&pci); 4331959748cSgd78059 4341959748cSgd78059 /* 4351959748cSgd78059 * Initialize interrupt kstat. This should not normally fail, since 4361959748cSgd78059 * we don't use a persistent stat. We do it this way to avoid having 4371959748cSgd78059 * to test for it at run time on the hot path. 4381959748cSgd78059 */ 4391959748cSgd78059 afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller", 4401959748cSgd78059 KSTAT_TYPE_INTR, 1, 0); 4411959748cSgd78059 if (afep->afe_intrstat == NULL) { 4421959748cSgd78059 afe_error(dip, "kstat_create failed"); 4431959748cSgd78059 goto failed; 4441959748cSgd78059 } 4451959748cSgd78059 kstat_install(afep->afe_intrstat); 4461959748cSgd78059 4471959748cSgd78059 /* 448bdb9230aSGarrett D'Amore * Set up the MII. 449bdb9230aSGarrett D'Amore */ 450bdb9230aSGarrett D'Amore if ((afep->afe_mii = mii_alloc(afep, dip, &afe_mii_ops)) == NULL) { 451bdb9230aSGarrett D'Amore goto failed; 452bdb9230aSGarrett D'Amore } 453bdb9230aSGarrett D'Amore 454bdb9230aSGarrett D'Amore /* 455bdb9230aSGarrett D'Amore * Centaur can support PAUSE, but Comet can't. 456bdb9230aSGarrett D'Amore */ 457bdb9230aSGarrett D'Amore if (AFE_MODEL(afep) == MODEL_CENTAUR) { 458bdb9230aSGarrett D'Amore mii_set_pauseable(afep->afe_mii, B_TRUE, B_FALSE); 459bdb9230aSGarrett D'Amore } else { 460bdb9230aSGarrett D'Amore mii_set_pauseable(afep->afe_mii, B_FALSE, B_FALSE); 461bdb9230aSGarrett D'Amore } 462bdb9230aSGarrett D'Amore 463bdb9230aSGarrett D'Amore /* 4641959748cSgd78059 * Map in the device registers. 4651959748cSgd78059 */ 4661959748cSgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs, 4671959748cSgd78059 0, 0, &afe_devattr, &afep->afe_regshandle)) { 4681959748cSgd78059 afe_error(dip, "ddi_regs_map_setup failed"); 4691959748cSgd78059 goto failed; 4701959748cSgd78059 } 4711959748cSgd78059 4721959748cSgd78059 /* 4731959748cSgd78059 * Allocate DMA resources (descriptor rings and buffers). 4741959748cSgd78059 */ 4751959748cSgd78059 if ((afe_allocrxring(afep) != DDI_SUCCESS) || 4761959748cSgd78059 (afe_alloctxring(afep) != DDI_SUCCESS)) { 4771959748cSgd78059 afe_error(dip, "unable to allocate DMA resources"); 4781959748cSgd78059 goto failed; 4791959748cSgd78059 } 4801959748cSgd78059 4811959748cSgd78059 /* Initialize the chip. */ 4821959748cSgd78059 mutex_enter(&afep->afe_intrlock); 4831959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 4841959748cSgd78059 if (!afe_initialize(afep)) { 4851959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 4861959748cSgd78059 mutex_exit(&afep->afe_intrlock); 4871959748cSgd78059 goto failed; 4881959748cSgd78059 } 4891959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 4901959748cSgd78059 mutex_exit(&afep->afe_intrlock); 4911959748cSgd78059 4921959748cSgd78059 /* Determine the number of address bits to our EEPROM. */ 4931959748cSgd78059 afep->afe_sromwidth = afe_sromwidth(afep); 4941959748cSgd78059 4951959748cSgd78059 /* 4961959748cSgd78059 * Get the factory ethernet address. This becomes the current 4971959748cSgd78059 * ethernet address (it can be overridden later via ifconfig). 4981959748cSgd78059 */ 4991959748cSgd78059 afe_getfactaddr(afep, afep->afe_curraddr); 5001959748cSgd78059 afep->afe_promisc = B_FALSE; 5011959748cSgd78059 5021959748cSgd78059 /* make sure we add configure the initial filter */ 5031959748cSgd78059 (void) afe_m_unicst(afep, afep->afe_curraddr); 5041959748cSgd78059 (void) afe_m_multicst(afep, B_TRUE, afe_broadcast); 5051959748cSgd78059 5061959748cSgd78059 /* 5071959748cSgd78059 * Establish interrupt handler. 5081959748cSgd78059 */ 5091959748cSgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) != 5101959748cSgd78059 DDI_SUCCESS) { 5111959748cSgd78059 afe_error(dip, "unable to add interrupt"); 5121959748cSgd78059 goto failed; 5131959748cSgd78059 } 5141959748cSgd78059 5151959748cSgd78059 /* TODO: do the power management stuff */ 5161959748cSgd78059 5171959748cSgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 5181959748cSgd78059 afe_error(dip, "mac_alloc failed"); 5191959748cSgd78059 goto failed; 5201959748cSgd78059 } 5211959748cSgd78059 5221959748cSgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 5231959748cSgd78059 macp->m_driver = afep; 5241959748cSgd78059 macp->m_dip = dip; 5251959748cSgd78059 macp->m_src_addr = afep->afe_curraddr; 5261959748cSgd78059 macp->m_callbacks = &afe_m_callbacks; 5271959748cSgd78059 macp->m_min_sdu = 0; 5281959748cSgd78059 macp->m_max_sdu = ETHERMTU; 529d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ; 5301959748cSgd78059 5311959748cSgd78059 if (mac_register(macp, &afep->afe_mh) == DDI_SUCCESS) { 5321959748cSgd78059 mac_free(macp); 5331959748cSgd78059 return (DDI_SUCCESS); 5341959748cSgd78059 } 5351959748cSgd78059 5361959748cSgd78059 /* failed to register with MAC */ 5371959748cSgd78059 mac_free(macp); 5381959748cSgd78059 failed: 5391959748cSgd78059 if (afep->afe_icookie != NULL) { 5401959748cSgd78059 ddi_remove_intr(dip, 0, afep->afe_icookie); 5411959748cSgd78059 } 5421959748cSgd78059 if (afep->afe_intrstat) { 5431959748cSgd78059 kstat_delete(afep->afe_intrstat); 5441959748cSgd78059 } 5451959748cSgd78059 mutex_destroy(&afep->afe_intrlock); 5461959748cSgd78059 mutex_destroy(&afep->afe_xmtlock); 5471959748cSgd78059 5481959748cSgd78059 afe_freerxring(afep); 5491959748cSgd78059 afe_freetxring(afep); 5501959748cSgd78059 5511959748cSgd78059 if (afep->afe_regshandle != NULL) { 5521959748cSgd78059 ddi_regs_map_free(&afep->afe_regshandle); 5531959748cSgd78059 } 5541959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 5551959748cSgd78059 return (DDI_FAILURE); 5561959748cSgd78059 } 5571959748cSgd78059 5581959748cSgd78059 int 5591959748cSgd78059 afe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5601959748cSgd78059 { 5611959748cSgd78059 afe_t *afep; 5621959748cSgd78059 5631959748cSgd78059 afep = ddi_get_driver_private(dip); 5641959748cSgd78059 if (afep == NULL) { 5651959748cSgd78059 afe_error(dip, "no soft state in detach!"); 5661959748cSgd78059 return (DDI_FAILURE); 5671959748cSgd78059 } 5681959748cSgd78059 5691959748cSgd78059 switch (cmd) { 5701959748cSgd78059 case DDI_DETACH: 5711959748cSgd78059 5721959748cSgd78059 if (mac_unregister(afep->afe_mh) != 0) { 5731959748cSgd78059 return (DDI_FAILURE); 5741959748cSgd78059 } 5751959748cSgd78059 5761959748cSgd78059 /* make sure hardware is quiesced */ 5771959748cSgd78059 mutex_enter(&afep->afe_intrlock); 5781959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 5791959748cSgd78059 afep->afe_flags &= ~AFE_RUNNING; 5801959748cSgd78059 afe_stopall(afep); 5811959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 5821959748cSgd78059 mutex_exit(&afep->afe_intrlock); 5831959748cSgd78059 5841959748cSgd78059 /* clean up and shut down device */ 5851959748cSgd78059 ddi_remove_intr(dip, 0, afep->afe_icookie); 5861959748cSgd78059 587bdb9230aSGarrett D'Amore /* clean up MII layer */ 588bdb9230aSGarrett D'Amore mii_free(afep->afe_mii); 589bdb9230aSGarrett D'Amore 5901959748cSgd78059 /* clean up kstats */ 5911959748cSgd78059 kstat_delete(afep->afe_intrstat); 5921959748cSgd78059 5931959748cSgd78059 ddi_prop_remove_all(dip); 5941959748cSgd78059 5951959748cSgd78059 /* free up any left over buffers or DMA resources */ 5961959748cSgd78059 afe_freerxring(afep); 5971959748cSgd78059 afe_freetxring(afep); 5981959748cSgd78059 5991959748cSgd78059 ddi_regs_map_free(&afep->afe_regshandle); 6001959748cSgd78059 mutex_destroy(&afep->afe_intrlock); 6011959748cSgd78059 mutex_destroy(&afep->afe_xmtlock); 6021959748cSgd78059 6031959748cSgd78059 kmem_free(afep, sizeof (afe_t)); 6041959748cSgd78059 return (DDI_SUCCESS); 6051959748cSgd78059 6061959748cSgd78059 case DDI_SUSPEND: 607bdb9230aSGarrett D'Amore /* stop MII monitoring */ 608bdb9230aSGarrett D'Amore mii_suspend(afep->afe_mii); 609bdb9230aSGarrett D'Amore 6101959748cSgd78059 /* quiesce the hardware */ 6111959748cSgd78059 mutex_enter(&afep->afe_intrlock); 6121959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 6131959748cSgd78059 afep->afe_flags |= AFE_SUSPENDED; 6141959748cSgd78059 afe_stopall(afep); 6151959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 6161959748cSgd78059 mutex_exit(&afep->afe_intrlock); 6171959748cSgd78059 return (DDI_SUCCESS); 6181959748cSgd78059 default: 6191959748cSgd78059 return (DDI_FAILURE); 6201959748cSgd78059 } 6211959748cSgd78059 } 6221959748cSgd78059 6231959748cSgd78059 int 6241959748cSgd78059 afe_resume(dev_info_t *dip) 6251959748cSgd78059 { 6261959748cSgd78059 afe_t *afep; 6271959748cSgd78059 6281959748cSgd78059 if ((afep = ddi_get_driver_private(dip)) == NULL) { 6291959748cSgd78059 return (DDI_FAILURE); 6301959748cSgd78059 } 6311959748cSgd78059 6321959748cSgd78059 mutex_enter(&afep->afe_intrlock); 6331959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 6341959748cSgd78059 6351959748cSgd78059 afep->afe_flags &= ~AFE_SUSPENDED; 6361959748cSgd78059 6371959748cSgd78059 /* re-initialize chip */ 6381959748cSgd78059 if (!afe_initialize(afep)) { 6391959748cSgd78059 afe_error(afep->afe_dip, "unable to resume chip!"); 6401959748cSgd78059 afep->afe_flags |= AFE_SUSPENDED; 6411959748cSgd78059 mutex_exit(&afep->afe_intrlock); 6421959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 6431959748cSgd78059 return (DDI_SUCCESS); 6441959748cSgd78059 } 6451959748cSgd78059 6461959748cSgd78059 /* start the chip */ 6471959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) { 6481959748cSgd78059 afe_startall(afep); 6491959748cSgd78059 } 6501959748cSgd78059 6511959748cSgd78059 /* drop locks */ 6521959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 6531959748cSgd78059 mutex_exit(&afep->afe_intrlock); 6541959748cSgd78059 655bdb9230aSGarrett D'Amore mii_resume(afep->afe_mii); 656bdb9230aSGarrett D'Amore 6571959748cSgd78059 return (DDI_SUCCESS); 6581959748cSgd78059 } 6591959748cSgd78059 66038415b01SGarrett D'Amore int 66138415b01SGarrett D'Amore afe_quiesce(dev_info_t *dip) 66238415b01SGarrett D'Amore { 66338415b01SGarrett D'Amore afe_t *afep; 66438415b01SGarrett D'Amore 66538415b01SGarrett D'Amore if ((afep = ddi_get_driver_private(dip)) == NULL) { 66638415b01SGarrett D'Amore return (DDI_FAILURE); 66738415b01SGarrett D'Amore } 66838415b01SGarrett D'Amore 66938415b01SGarrett D'Amore SETBIT(afep, CSR_PAR, PAR_RESET); 67038415b01SGarrett D'Amore /* 67138415b01SGarrett D'Amore * At 66 MHz it is 16 nsec per access or more (always more) 67238415b01SGarrett D'Amore * So we need 3,333 times to retry for 50 usec. We just 67338415b01SGarrett D'Amore * round up to 5000 times. Unless the hardware is horked, 67438415b01SGarrett D'Amore * it will always terminate *well* before that anyway. 67538415b01SGarrett D'Amore */ 67638415b01SGarrett D'Amore for (int i = 0; i < 5000; i++) { 67738415b01SGarrett D'Amore if ((GETCSR(afep, CSR_PAR) & PAR_RESET) == 0) { 67838415b01SGarrett D'Amore return (DDI_SUCCESS); 67938415b01SGarrett D'Amore } 68038415b01SGarrett D'Amore } 68138415b01SGarrett D'Amore 68238415b01SGarrett D'Amore /* hardware didn't quiesce - force a full reboot (PCI reset) */ 68338415b01SGarrett D'Amore return (DDI_FAILURE); 68438415b01SGarrett D'Amore } 68538415b01SGarrett D'Amore 6861959748cSgd78059 void 6871959748cSgd78059 afe_setrxfilt(afe_t *afep) 6881959748cSgd78059 { 6891959748cSgd78059 unsigned rxen, pa0, pa1; 6901959748cSgd78059 6911959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 6921959748cSgd78059 /* don't touch a suspended interface */ 6931959748cSgd78059 return; 6941959748cSgd78059 } 6951959748cSgd78059 6961959748cSgd78059 rxen = GETCSR(afep, CSR_NAR) & NAR_RX_ENABLE; 6971959748cSgd78059 6981959748cSgd78059 /* stop receiver */ 6991959748cSgd78059 if (rxen) { 7001959748cSgd78059 afe_stopmac(afep); 7011959748cSgd78059 } 7021959748cSgd78059 7031959748cSgd78059 /* program promiscuous mode */ 7041959748cSgd78059 if (afep->afe_promisc) 7051959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_RX_PROMISC); 7061959748cSgd78059 else 7071959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_PROMISC); 7081959748cSgd78059 7091959748cSgd78059 /* program mac address */ 7101959748cSgd78059 pa0 = (afep->afe_curraddr[3] << 24) | (afep->afe_curraddr[2] << 16) | 7111959748cSgd78059 (afep->afe_curraddr[1] << 8) | afep->afe_curraddr[0]; 7121959748cSgd78059 pa1 = (afep->afe_curraddr[5] << 8) | afep->afe_curraddr[4]; 7131959748cSgd78059 7141959748cSgd78059 PUTCSR(afep, CSR_PAR0, pa0); 7151959748cSgd78059 PUTCSR(afep, CSR_PAR1, pa1); 7161959748cSgd78059 if (rxen) { 7171959748cSgd78059 SETBIT(afep, CSR_NAR, rxen); 7181959748cSgd78059 } 7191959748cSgd78059 7201959748cSgd78059 /* program multicast filter */ 7211959748cSgd78059 if (AFE_MODEL(afep) == MODEL_COMET) { 7221959748cSgd78059 if (afep->afe_mctab[0] || afep->afe_mctab[1]) { 7231959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_RX_MULTI); 7241959748cSgd78059 } else { 7251959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_MULTI); 7261959748cSgd78059 } 7271959748cSgd78059 } else { 7281959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_RX_MULTI); 7291959748cSgd78059 PUTCSR(afep, CSR_MAR0, afep->afe_mctab[0]); 7301959748cSgd78059 PUTCSR(afep, CSR_MAR1, afep->afe_mctab[1]); 7311959748cSgd78059 } 7321959748cSgd78059 7331959748cSgd78059 /* restart receiver */ 7341959748cSgd78059 if (rxen) { 7351959748cSgd78059 afe_startmac(afep); 7361959748cSgd78059 } 7371959748cSgd78059 } 7381959748cSgd78059 7391959748cSgd78059 int 740bdb9230aSGarrett D'Amore afe_watchdog(afe_t *afep) 741bdb9230aSGarrett D'Amore { 742bdb9230aSGarrett D'Amore if ((afep->afe_txstall_time != 0) && 743bdb9230aSGarrett D'Amore (gethrtime() > afep->afe_txstall_time) && 744bdb9230aSGarrett D'Amore (afep->afe_txavail != AFE_TXRING)) { 745bdb9230aSGarrett D'Amore afep->afe_txstall_time = 0; 746bdb9230aSGarrett D'Amore afe_error(afep->afe_dip, "TX stall detected!"); 747bdb9230aSGarrett D'Amore return (DDI_FAILURE); 748bdb9230aSGarrett D'Amore } else { 749bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 750bdb9230aSGarrett D'Amore } 751bdb9230aSGarrett D'Amore } 752bdb9230aSGarrett D'Amore 753bdb9230aSGarrett D'Amore int 7541959748cSgd78059 afe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 7551959748cSgd78059 { 7561959748cSgd78059 afe_t *afep = arg; 7571959748cSgd78059 int index; 7581959748cSgd78059 uint32_t crc; 7591959748cSgd78059 uint32_t bit; 7601959748cSgd78059 uint32_t newval, oldval; 7611959748cSgd78059 7621959748cSgd78059 CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table); 7631959748cSgd78059 crc %= AFE_MCHASH; 7641959748cSgd78059 7651959748cSgd78059 /* bit within a 32-bit word */ 7661959748cSgd78059 index = crc / 32; 7671959748cSgd78059 bit = (1 << (crc % 32)); 7681959748cSgd78059 7691959748cSgd78059 mutex_enter(&afep->afe_intrlock); 7701959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 7711959748cSgd78059 newval = oldval = afep->afe_mctab[index]; 7721959748cSgd78059 7731959748cSgd78059 if (add) { 7741959748cSgd78059 afep->afe_mccount[crc]++; 7751959748cSgd78059 if (afep->afe_mccount[crc] == 1) 7761959748cSgd78059 newval |= bit; 7771959748cSgd78059 } else { 7781959748cSgd78059 afep->afe_mccount[crc]--; 7791959748cSgd78059 if (afep->afe_mccount[crc] == 0) 7801959748cSgd78059 newval &= ~bit; 7811959748cSgd78059 } 7821959748cSgd78059 if (newval != oldval) { 7831959748cSgd78059 afep->afe_mctab[index] = newval; 7841959748cSgd78059 afe_setrxfilt(afep); 7851959748cSgd78059 } 7861959748cSgd78059 7871959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 7881959748cSgd78059 mutex_exit(&afep->afe_intrlock); 7891959748cSgd78059 7901959748cSgd78059 return (0); 7911959748cSgd78059 } 7921959748cSgd78059 7931959748cSgd78059 int 7941959748cSgd78059 afe_m_promisc(void *arg, boolean_t on) 7951959748cSgd78059 { 7961959748cSgd78059 afe_t *afep = arg; 7971959748cSgd78059 7981959748cSgd78059 /* exclusive access to the card while we reprogram it */ 7991959748cSgd78059 mutex_enter(&afep->afe_intrlock); 8001959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 8011959748cSgd78059 /* save current promiscuous mode state for replay in resume */ 8021959748cSgd78059 afep->afe_promisc = on; 8031959748cSgd78059 8041959748cSgd78059 afe_setrxfilt(afep); 8051959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 8061959748cSgd78059 mutex_exit(&afep->afe_intrlock); 8071959748cSgd78059 8081959748cSgd78059 return (0); 8091959748cSgd78059 } 8101959748cSgd78059 8111959748cSgd78059 int 8121959748cSgd78059 afe_m_unicst(void *arg, const uint8_t *macaddr) 8131959748cSgd78059 { 8141959748cSgd78059 afe_t *afep = arg; 8151959748cSgd78059 8161959748cSgd78059 /* exclusive access to the card while we reprogram it */ 8171959748cSgd78059 mutex_enter(&afep->afe_intrlock); 8181959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 8191959748cSgd78059 8201959748cSgd78059 bcopy(macaddr, afep->afe_curraddr, ETHERADDRL); 8211959748cSgd78059 afe_setrxfilt(afep); 8221959748cSgd78059 8231959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 8241959748cSgd78059 mutex_exit(&afep->afe_intrlock); 8251959748cSgd78059 8261959748cSgd78059 return (0); 8271959748cSgd78059 } 8281959748cSgd78059 8291959748cSgd78059 mblk_t * 8301959748cSgd78059 afe_m_tx(void *arg, mblk_t *mp) 8311959748cSgd78059 { 8321959748cSgd78059 afe_t *afep = arg; 8331959748cSgd78059 mblk_t *nmp; 8341959748cSgd78059 8351959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 8361959748cSgd78059 8371959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 8381959748cSgd78059 while ((nmp = mp) != NULL) { 8391959748cSgd78059 afep->afe_carrier_errors++; 8401959748cSgd78059 mp = mp->b_next; 8411959748cSgd78059 freemsg(nmp); 8421959748cSgd78059 } 8431959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 8441959748cSgd78059 return (NULL); 8451959748cSgd78059 } 8461959748cSgd78059 8471959748cSgd78059 while (mp != NULL) { 8481959748cSgd78059 nmp = mp->b_next; 8491959748cSgd78059 mp->b_next = NULL; 8501959748cSgd78059 8511959748cSgd78059 if (!afe_send(afep, mp)) { 8521959748cSgd78059 mp->b_next = nmp; 8531959748cSgd78059 break; 8541959748cSgd78059 } 8551959748cSgd78059 mp = nmp; 8561959748cSgd78059 } 8571959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 8581959748cSgd78059 8591959748cSgd78059 return (mp); 8601959748cSgd78059 } 8611959748cSgd78059 862bdb9230aSGarrett D'Amore void 863bdb9230aSGarrett D'Amore afe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 864bdb9230aSGarrett D'Amore { 865bdb9230aSGarrett D'Amore afe_t *afep = arg; 866bdb9230aSGarrett D'Amore 867bdb9230aSGarrett D'Amore if (mii_m_loop_ioctl(afep->afe_mii, wq, mp)) 868bdb9230aSGarrett D'Amore return; 869bdb9230aSGarrett D'Amore 870bdb9230aSGarrett D'Amore miocnak(wq, mp, 0, EINVAL); 871bdb9230aSGarrett D'Amore } 872bdb9230aSGarrett D'Amore 8731959748cSgd78059 /* 8741959748cSgd78059 * Hardware management. 8751959748cSgd78059 */ 8761959748cSgd78059 static boolean_t 8771959748cSgd78059 afe_initialize(afe_t *afep) 8781959748cSgd78059 { 8791959748cSgd78059 int i; 8801959748cSgd78059 unsigned val; 8811959748cSgd78059 uint32_t par, nar; 8821959748cSgd78059 8831959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 8841959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 8851959748cSgd78059 8861959748cSgd78059 SETBIT(afep, CSR_PAR, PAR_RESET); 8871959748cSgd78059 for (i = 1; i < 10; i++) { 8881959748cSgd78059 drv_usecwait(5); 8891959748cSgd78059 val = GETCSR(afep, CSR_PAR); 8901959748cSgd78059 if (!(val & PAR_RESET)) { 8911959748cSgd78059 break; 8921959748cSgd78059 } 8931959748cSgd78059 } 8941959748cSgd78059 if (i == 10) { 8951959748cSgd78059 afe_error(afep->afe_dip, "timed out waiting for reset!"); 8961959748cSgd78059 return (B_FALSE); 8971959748cSgd78059 } 8981959748cSgd78059 8991959748cSgd78059 /* 9001959748cSgd78059 * Updated Centaur data sheets show that the Comet and Centaur are 9011959748cSgd78059 * alike here (contrary to earlier versions of the data sheet). 9021959748cSgd78059 */ 9031959748cSgd78059 /* XXX:? chip problems */ 9041959748cSgd78059 /* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */ 9051959748cSgd78059 par = 0; 9061959748cSgd78059 switch (afep->afe_cachesize) { 9071959748cSgd78059 case 8: 9081959748cSgd78059 par |= PAR_CALIGN_8 | PAR_BURST_8; 9091959748cSgd78059 break; 9101959748cSgd78059 case 16: 9111959748cSgd78059 par |= PAR_CALIGN_16 | PAR_BURST_16; 9121959748cSgd78059 break; 9131959748cSgd78059 case 32: 9141959748cSgd78059 par |= PAR_CALIGN_32 | PAR_BURST_32; 9151959748cSgd78059 break; 9161959748cSgd78059 default: 9171959748cSgd78059 par |= PAR_BURST_32; 9181959748cSgd78059 par &= ~(PAR_MWIE | PAR_MRLE | PAR_MRME); 9191959748cSgd78059 break; 9201959748cSgd78059 9211959748cSgd78059 } 9221959748cSgd78059 9231959748cSgd78059 PUTCSR(afep, CSR_PAR, par); 9241959748cSgd78059 9251959748cSgd78059 /* enable transmit underrun auto-recovery */ 9261959748cSgd78059 SETBIT(afep, CSR_CR, CR_TXURAUTOR); 9271959748cSgd78059 9281959748cSgd78059 afe_resetrings(afep); 9291959748cSgd78059 9301959748cSgd78059 /* clear the lost packet counter (cleared on read) */ 9311959748cSgd78059 (void) GETCSR(afep, CSR_LPC); 9321959748cSgd78059 9331959748cSgd78059 nar = GETCSR(afep, CSR_NAR); 9341959748cSgd78059 nar &= ~NAR_TR; /* clear tx threshold */ 9351959748cSgd78059 nar |= NAR_SF; /* store-and-forward */ 9361959748cSgd78059 nar |= NAR_HBD; /* disable SQE test */ 9371959748cSgd78059 PUTCSR(afep, CSR_NAR, nar); 9381959748cSgd78059 9391959748cSgd78059 afe_setrxfilt(afep); 9401959748cSgd78059 9411959748cSgd78059 return (B_TRUE); 9421959748cSgd78059 } 9431959748cSgd78059 9441959748cSgd78059 /* 9451959748cSgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation. 9461959748cSgd78059 */ 9471959748cSgd78059 9481959748cSgd78059 uint8_t 9491959748cSgd78059 afe_sromwidth(afe_t *afep) 9501959748cSgd78059 { 9511959748cSgd78059 int i; 9521959748cSgd78059 uint32_t eeread; 9531959748cSgd78059 uint8_t addrlen = 8; 9541959748cSgd78059 9551959748cSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 9561959748cSgd78059 9571959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 9581959748cSgd78059 drv_usecwait(1); 9591959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 9601959748cSgd78059 9611959748cSgd78059 /* command bits first */ 9621959748cSgd78059 for (i = 4; i != 0; i >>= 1) { 9631959748cSgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0; 9641959748cSgd78059 9651959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val); 9661959748cSgd78059 drv_usecwait(1); 9671959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 9681959748cSgd78059 drv_usecwait(1); 9691959748cSgd78059 } 9701959748cSgd78059 9711959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 9721959748cSgd78059 9731959748cSgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) { 9741959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK); 9751959748cSgd78059 drv_usecwait(1); 9761959748cSgd78059 if (!(GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT)) { 9771959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 9781959748cSgd78059 drv_usecwait(1); 9791959748cSgd78059 break; 9801959748cSgd78059 } 9811959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 9821959748cSgd78059 drv_usecwait(1); 9831959748cSgd78059 } 9841959748cSgd78059 9851959748cSgd78059 /* turn off accesses to the EEPROM */ 9861959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 9871959748cSgd78059 9881959748cSgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen); 9891959748cSgd78059 } 9901959748cSgd78059 9911959748cSgd78059 /* 9921959748cSgd78059 * The words in EEPROM are stored in little endian order. We 9931959748cSgd78059 * shift bits out in big endian order, though. This requires 9941959748cSgd78059 * a byte swap on some platforms. 9951959748cSgd78059 */ 9961959748cSgd78059 uint16_t 9971959748cSgd78059 afe_readsromword(afe_t *afep, unsigned romaddr) 9981959748cSgd78059 { 9991959748cSgd78059 int i; 10001959748cSgd78059 uint16_t word = 0; 10011959748cSgd78059 uint16_t retval; 10021959748cSgd78059 int eeread; 10031959748cSgd78059 uint8_t addrlen; 10041959748cSgd78059 int readcmd; 10051959748cSgd78059 uchar_t *ptr; 10061959748cSgd78059 10071959748cSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 10081959748cSgd78059 addrlen = afep->afe_sromwidth; 10091959748cSgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr; 10101959748cSgd78059 10111959748cSgd78059 if (romaddr >= (1 << addrlen)) { 10121959748cSgd78059 /* too big to fit! */ 10131959748cSgd78059 return (0); 10141959748cSgd78059 } 10151959748cSgd78059 10161959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 10171959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 10181959748cSgd78059 10191959748cSgd78059 /* command and address bits */ 10201959748cSgd78059 for (i = 4 + addrlen; i >= 0; i--) { 10211959748cSgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0; 10221959748cSgd78059 10231959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val); 10241959748cSgd78059 drv_usecwait(1); 10251959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 10261959748cSgd78059 drv_usecwait(1); 10271959748cSgd78059 } 10281959748cSgd78059 10291959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 10301959748cSgd78059 10311959748cSgd78059 for (i = 0; i < 16; i++) { 10321959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK); 10331959748cSgd78059 drv_usecwait(1); 10341959748cSgd78059 word <<= 1; 10351959748cSgd78059 if (GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT) { 10361959748cSgd78059 word |= 1; 10371959748cSgd78059 } 10381959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread); 10391959748cSgd78059 drv_usecwait(1); 10401959748cSgd78059 } 10411959748cSgd78059 10421959748cSgd78059 /* turn off accesses to the EEPROM */ 10431959748cSgd78059 PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 10441959748cSgd78059 10451959748cSgd78059 /* 10461959748cSgd78059 * Fix up the endianness thing. Note that the values 10471959748cSgd78059 * are stored in little endian format on the SROM. 10481959748cSgd78059 */ 10491959748cSgd78059 ptr = (uchar_t *)&word; 10501959748cSgd78059 retval = (ptr[1] << 8) | ptr[0]; 10511959748cSgd78059 return (retval); 10521959748cSgd78059 } 10531959748cSgd78059 10541959748cSgd78059 void 10551959748cSgd78059 afe_readsrom(afe_t *afep, unsigned romaddr, unsigned len, char *dest) 10561959748cSgd78059 { 10571959748cSgd78059 int i; 10581959748cSgd78059 uint16_t word; 10591959748cSgd78059 uint16_t *ptr = (uint16_t *)((void *)dest); 10601959748cSgd78059 for (i = 0; i < len; i++) { 10611959748cSgd78059 word = afe_readsromword(afep, romaddr + i); 10621959748cSgd78059 *ptr = word; 10631959748cSgd78059 ptr++; 10641959748cSgd78059 } 10651959748cSgd78059 } 10661959748cSgd78059 10671959748cSgd78059 void 10681959748cSgd78059 afe_getfactaddr(afe_t *afep, uchar_t *eaddr) 10691959748cSgd78059 { 10701959748cSgd78059 afe_readsrom(afep, SROM_ENADDR, ETHERADDRL / 2, (char *)eaddr); 10711959748cSgd78059 } 10721959748cSgd78059 1073bdb9230aSGarrett D'Amore 1074bdb9230aSGarrett D'Amore 10751959748cSgd78059 /* 10761959748cSgd78059 * MII management. 10771959748cSgd78059 */ 10781959748cSgd78059 void 1079bdb9230aSGarrett D'Amore afe_mii_reset(void *arg) 10801959748cSgd78059 { 1081bdb9230aSGarrett D'Amore afe_t *afep = arg; 10821959748cSgd78059 int fiber; 1083bdb9230aSGarrett D'Amore uint16_t mcr; 1084bdb9230aSGarrett D'Amore uint16_t pilr; 1085bdb9230aSGarrett D'Amore uint8_t phyaddr; 10861959748cSgd78059 10871959748cSgd78059 /* 1088bdb9230aSGarrett D'Amore * Its entirely possible that this belongs as a PHY specific 1089bdb9230aSGarrett D'Amore * override. 10901959748cSgd78059 */ 1091bdb9230aSGarrett D'Amore if ((mii_get_id(afep->afe_mii) & 0xfffffff0) != 0x225410) { 1092bdb9230aSGarrett D'Amore /* if its not an AN983B, we don't care */ 10931959748cSgd78059 return; 10941959748cSgd78059 } 10951959748cSgd78059 1096bdb9230aSGarrett D'Amore phyaddr = mii_get_addr(afep->afe_mii); 10971959748cSgd78059 10981959748cSgd78059 fiber = 0; 10991959748cSgd78059 11001959748cSgd78059 switch (afep->afe_forcefiber) { 11011959748cSgd78059 case 0: 11021959748cSgd78059 /* UTP Port */ 11031959748cSgd78059 fiber = 0; 11041959748cSgd78059 break; 11051959748cSgd78059 case 1: 11061959748cSgd78059 /* Fiber Port */ 11071959748cSgd78059 fiber = 1; 11081959748cSgd78059 break; 1109bdb9230aSGarrett D'Amore } 11101959748cSgd78059 1111bdb9230aSGarrett D'Amore mcr = afe_mii_read(afep, phyaddr, PHY_MCR); 1112bdb9230aSGarrett D'Amore switch (fiber) { 1113bdb9230aSGarrett D'Amore case 0: 11141959748cSgd78059 mcr &= ~MCR_FIBER; 1115bdb9230aSGarrett D'Amore break; 1116bdb9230aSGarrett D'Amore 1117bdb9230aSGarrett D'Amore case 1: 1118bdb9230aSGarrett D'Amore mcr |= MCR_FIBER; 11191959748cSgd78059 break; 11201959748cSgd78059 } 1121bdb9230aSGarrett D'Amore afe_mii_write(afep, phyaddr, PHY_MCR, mcr); 11221959748cSgd78059 drv_usecwait(500); 11231959748cSgd78059 11241959748cSgd78059 /* 11251959748cSgd78059 * work around for errata 983B_0416 -- duplex light flashes 11261959748cSgd78059 * in 10 HDX. we just disable SQE testing on the device. 11271959748cSgd78059 */ 1128bdb9230aSGarrett D'Amore pilr = afe_mii_read(afep, phyaddr, PHY_PILR); 11291959748cSgd78059 pilr |= PILR_NOSQE; 1130bdb9230aSGarrett D'Amore afe_mii_write(afep, phyaddr, PHY_PILR, pilr); 11311959748cSgd78059 } 11321959748cSgd78059 11331959748cSgd78059 void 1134bdb9230aSGarrett D'Amore afe_mii_notify(void *arg, link_state_t link) 11351959748cSgd78059 { 1136bdb9230aSGarrett D'Amore afe_t *afep = arg; 11371959748cSgd78059 1138bdb9230aSGarrett D'Amore if (AFE_MODEL(afep) == MODEL_CENTAUR) { 1139bdb9230aSGarrett D'Amore if (mii_get_flowctrl(afep->afe_mii) == LINK_FLOWCTRL_BI) { 1140bdb9230aSGarrett D'Amore SETBIT(afep, CSR_CR, CR_PAUSE); 11411959748cSgd78059 } else { 1142bdb9230aSGarrett D'Amore CLRBIT(afep, CSR_CR, CR_PAUSE); 11431959748cSgd78059 } 11441959748cSgd78059 } 1145bdb9230aSGarrett D'Amore mac_link_update(afep->afe_mh, link); 11461959748cSgd78059 } 11471959748cSgd78059 11481959748cSgd78059 void 11491959748cSgd78059 afe_miitristate(afe_t *afep) 11501959748cSgd78059 { 115196fb08b9Sgd78059 uint32_t val = SPR_SROM_WRITE | SPR_MII_CTRL; 115296fb08b9Sgd78059 11531959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 11541959748cSgd78059 drv_usecwait(1); 11551959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 11561959748cSgd78059 drv_usecwait(1); 11571959748cSgd78059 } 11581959748cSgd78059 11591959748cSgd78059 void 116096fb08b9Sgd78059 afe_miiwritebit(afe_t *afep, uint8_t bit) 11611959748cSgd78059 { 116296fb08b9Sgd78059 uint32_t val = bit ? SPR_MII_DOUT : 0; 116396fb08b9Sgd78059 11641959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 11651959748cSgd78059 drv_usecwait(1); 11661959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 11671959748cSgd78059 drv_usecwait(1); 11681959748cSgd78059 } 11691959748cSgd78059 117096fb08b9Sgd78059 uint8_t 11711959748cSgd78059 afe_miireadbit(afe_t *afep) 11721959748cSgd78059 { 117396fb08b9Sgd78059 uint32_t val = SPR_MII_CTRL | SPR_SROM_READ; 117496fb08b9Sgd78059 uint8_t bit; 117596fb08b9Sgd78059 11761959748cSgd78059 PUTCSR(afep, CSR_SPR, val); 11771959748cSgd78059 drv_usecwait(1); 11781959748cSgd78059 bit = (GETCSR(afep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0; 11791959748cSgd78059 PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK); 11801959748cSgd78059 drv_usecwait(1); 11811959748cSgd78059 return (bit); 11821959748cSgd78059 } 11831959748cSgd78059 118496fb08b9Sgd78059 uint16_t 1185bdb9230aSGarrett D'Amore afe_mii_read(void *arg, uint8_t phy, uint8_t reg) 11861959748cSgd78059 { 1187bdb9230aSGarrett D'Amore afe_t *afep = arg; 11881959748cSgd78059 /* 11891959748cSgd78059 * ADMtek bugs ignore address decode bits -- they only 11901959748cSgd78059 * support PHY at 1. 11911959748cSgd78059 */ 11921959748cSgd78059 if (phy != 1) { 11931959748cSgd78059 return (0xffff); 11941959748cSgd78059 } 11951959748cSgd78059 switch (AFE_MODEL(afep)) { 11961959748cSgd78059 case MODEL_COMET: 11971959748cSgd78059 return (afe_miireadcomet(afep, phy, reg)); 11981959748cSgd78059 case MODEL_CENTAUR: 11991959748cSgd78059 return (afe_miireadgeneral(afep, phy, reg)); 12001959748cSgd78059 } 12011959748cSgd78059 return (0xffff); 12021959748cSgd78059 } 12031959748cSgd78059 120496fb08b9Sgd78059 uint16_t 1205bdb9230aSGarrett D'Amore afe_miireadgeneral(afe_t *afep, uint8_t phy, uint8_t reg) 12061959748cSgd78059 { 120796fb08b9Sgd78059 uint16_t value = 0; 12081959748cSgd78059 int i; 12091959748cSgd78059 12101959748cSgd78059 /* send the 32 bit preamble */ 12111959748cSgd78059 for (i = 0; i < 32; i++) { 12121959748cSgd78059 afe_miiwritebit(afep, 1); 12131959748cSgd78059 } 12141959748cSgd78059 12151959748cSgd78059 /* send the start code - 01b */ 12161959748cSgd78059 afe_miiwritebit(afep, 0); 12171959748cSgd78059 afe_miiwritebit(afep, 1); 12181959748cSgd78059 12191959748cSgd78059 /* send the opcode for read, - 10b */ 12201959748cSgd78059 afe_miiwritebit(afep, 1); 12211959748cSgd78059 afe_miiwritebit(afep, 0); 12221959748cSgd78059 12231959748cSgd78059 /* next we send the 5 bit phy address */ 12241959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 12251959748cSgd78059 afe_miiwritebit(afep, (phy & i) ? 1 : 0); 12261959748cSgd78059 } 12271959748cSgd78059 12281959748cSgd78059 /* the 5 bit register address goes next */ 12291959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 12301959748cSgd78059 afe_miiwritebit(afep, (reg & i) ? 1 : 0); 12311959748cSgd78059 } 12321959748cSgd78059 12331959748cSgd78059 /* turnaround - tristate followed by logic 0 */ 12341959748cSgd78059 afe_miitristate(afep); 12351959748cSgd78059 afe_miiwritebit(afep, 0); 12361959748cSgd78059 12371959748cSgd78059 /* read the 16 bit register value */ 12381959748cSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 12391959748cSgd78059 value <<= 1; 12401959748cSgd78059 value |= afe_miireadbit(afep); 12411959748cSgd78059 } 12421959748cSgd78059 afe_miitristate(afep); 12431959748cSgd78059 return (value); 12441959748cSgd78059 } 12451959748cSgd78059 124696fb08b9Sgd78059 uint16_t 1247bdb9230aSGarrett D'Amore afe_miireadcomet(afe_t *afep, uint8_t phy, uint8_t reg) 12481959748cSgd78059 { 12491959748cSgd78059 if (phy != 1) { 12501959748cSgd78059 return (0xffff); 12511959748cSgd78059 } 12521959748cSgd78059 switch (reg) { 12531959748cSgd78059 case MII_CONTROL: 12541959748cSgd78059 reg = CSR_BMCR; 12551959748cSgd78059 break; 12561959748cSgd78059 case MII_STATUS: 12571959748cSgd78059 reg = CSR_BMSR; 12581959748cSgd78059 break; 12591959748cSgd78059 case MII_PHYIDH: 12601959748cSgd78059 reg = CSR_PHYIDR1; 12611959748cSgd78059 break; 12621959748cSgd78059 case MII_PHYIDL: 12631959748cSgd78059 reg = CSR_PHYIDR2; 12641959748cSgd78059 break; 12651959748cSgd78059 case MII_AN_ADVERT: 12661959748cSgd78059 reg = CSR_ANAR; 12671959748cSgd78059 break; 12681959748cSgd78059 case MII_AN_LPABLE: 12691959748cSgd78059 reg = CSR_ANLPAR; 12701959748cSgd78059 break; 12711959748cSgd78059 case MII_AN_EXPANSION: 12721959748cSgd78059 reg = CSR_ANER; 12731959748cSgd78059 break; 12741959748cSgd78059 default: 12751959748cSgd78059 return (0); 12761959748cSgd78059 } 12771959748cSgd78059 return (GETCSR16(afep, reg) & 0xFFFF); 12781959748cSgd78059 } 12791959748cSgd78059 12801959748cSgd78059 void 1281bdb9230aSGarrett D'Amore afe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val) 12821959748cSgd78059 { 1283bdb9230aSGarrett D'Amore afe_t *afep = arg; 1284bdb9230aSGarrett D'Amore 12851959748cSgd78059 /* 12861959748cSgd78059 * ADMtek bugs ignore address decode bits -- they only 12871959748cSgd78059 * support PHY at 1. 12881959748cSgd78059 */ 12891959748cSgd78059 if (phy != 1) { 12901959748cSgd78059 return; 12911959748cSgd78059 } 12921959748cSgd78059 switch (AFE_MODEL(afep)) { 12931959748cSgd78059 case MODEL_COMET: 12941959748cSgd78059 afe_miiwritecomet(afep, phy, reg, val); 12951959748cSgd78059 break; 12961959748cSgd78059 case MODEL_CENTAUR: 12971959748cSgd78059 afe_miiwritegeneral(afep, phy, reg, val); 12981959748cSgd78059 break; 12991959748cSgd78059 } 13001959748cSgd78059 } 13011959748cSgd78059 13021959748cSgd78059 void 1303bdb9230aSGarrett D'Amore afe_miiwritegeneral(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val) 13041959748cSgd78059 { 13051959748cSgd78059 int i; 13061959748cSgd78059 13071959748cSgd78059 /* send the 32 bit preamble */ 13081959748cSgd78059 for (i = 0; i < 32; i++) { 13091959748cSgd78059 afe_miiwritebit(afep, 1); 13101959748cSgd78059 } 13111959748cSgd78059 13121959748cSgd78059 /* send the start code - 01b */ 13131959748cSgd78059 afe_miiwritebit(afep, 0); 13141959748cSgd78059 afe_miiwritebit(afep, 1); 13151959748cSgd78059 13161959748cSgd78059 /* send the opcode for write, - 01b */ 13171959748cSgd78059 afe_miiwritebit(afep, 0); 13181959748cSgd78059 afe_miiwritebit(afep, 1); 13191959748cSgd78059 13201959748cSgd78059 /* next we send the 5 bit phy address */ 13211959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 13221959748cSgd78059 afe_miiwritebit(afep, (phy & i) ? 1 : 0); 13231959748cSgd78059 } 13241959748cSgd78059 13251959748cSgd78059 /* the 5 bit register address goes next */ 13261959748cSgd78059 for (i = 0x10; i > 0; i >>= 1) { 13271959748cSgd78059 afe_miiwritebit(afep, (reg & i) ? 1 : 0); 13281959748cSgd78059 } 13291959748cSgd78059 1330bdb9230aSGarrett D'Amore /* turnaround - 1 bit followed by logic 0 */ 1331bdb9230aSGarrett D'Amore afe_miiwritebit(afep, 1); 13321959748cSgd78059 afe_miiwritebit(afep, 0); 13331959748cSgd78059 13341959748cSgd78059 /* now write out our data (16 bits) */ 13351959748cSgd78059 for (i = 0x8000; i > 0; i >>= 1) { 13361959748cSgd78059 afe_miiwritebit(afep, (val & i) ? 1 : 0); 13371959748cSgd78059 } 13381959748cSgd78059 13391959748cSgd78059 /* idle mode */ 13401959748cSgd78059 afe_miitristate(afep); 13411959748cSgd78059 } 13421959748cSgd78059 13431959748cSgd78059 void 1344bdb9230aSGarrett D'Amore afe_miiwritecomet(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val) 13451959748cSgd78059 { 13461959748cSgd78059 if (phy != 1) { 13471959748cSgd78059 return; 13481959748cSgd78059 } 13491959748cSgd78059 switch (reg) { 13501959748cSgd78059 case MII_CONTROL: 13511959748cSgd78059 reg = CSR_BMCR; 13521959748cSgd78059 break; 13531959748cSgd78059 case MII_STATUS: 13541959748cSgd78059 reg = CSR_BMSR; 13551959748cSgd78059 break; 13561959748cSgd78059 case MII_PHYIDH: 13571959748cSgd78059 reg = CSR_PHYIDR1; 13581959748cSgd78059 break; 13591959748cSgd78059 case MII_PHYIDL: 13601959748cSgd78059 reg = CSR_PHYIDR2; 13611959748cSgd78059 break; 13621959748cSgd78059 case MII_AN_ADVERT: 13631959748cSgd78059 reg = CSR_ANAR; 13641959748cSgd78059 break; 13651959748cSgd78059 case MII_AN_LPABLE: 13661959748cSgd78059 reg = CSR_ANLPAR; 13671959748cSgd78059 break; 13681959748cSgd78059 case MII_AN_EXPANSION: 13691959748cSgd78059 reg = CSR_ANER; 13701959748cSgd78059 break; 13711959748cSgd78059 default: 13721959748cSgd78059 return; 13731959748cSgd78059 } 13741959748cSgd78059 PUTCSR16(afep, reg, val); 13751959748cSgd78059 } 13761959748cSgd78059 13771959748cSgd78059 int 13781959748cSgd78059 afe_m_start(void *arg) 13791959748cSgd78059 { 13801959748cSgd78059 afe_t *afep = arg; 13811959748cSgd78059 13821959748cSgd78059 /* grab exclusive access to the card */ 13831959748cSgd78059 mutex_enter(&afep->afe_intrlock); 13841959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 13851959748cSgd78059 13861959748cSgd78059 afe_startall(afep); 13871959748cSgd78059 afep->afe_flags |= AFE_RUNNING; 13881959748cSgd78059 13891959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 13901959748cSgd78059 mutex_exit(&afep->afe_intrlock); 1391bdb9230aSGarrett D'Amore 1392bdb9230aSGarrett D'Amore mii_start(afep->afe_mii); 1393bdb9230aSGarrett D'Amore 13941959748cSgd78059 return (0); 13951959748cSgd78059 } 13961959748cSgd78059 13971959748cSgd78059 void 13981959748cSgd78059 afe_m_stop(void *arg) 13991959748cSgd78059 { 14001959748cSgd78059 afe_t *afep = arg; 14011959748cSgd78059 1402bdb9230aSGarrett D'Amore mii_stop(afep->afe_mii); 1403bdb9230aSGarrett D'Amore 14041959748cSgd78059 /* exclusive access to the hardware! */ 14051959748cSgd78059 mutex_enter(&afep->afe_intrlock); 14061959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 14071959748cSgd78059 14081959748cSgd78059 afe_stopall(afep); 14091959748cSgd78059 afep->afe_flags &= ~AFE_RUNNING; 14101959748cSgd78059 14111959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 14121959748cSgd78059 mutex_exit(&afep->afe_intrlock); 14131959748cSgd78059 } 14141959748cSgd78059 14151959748cSgd78059 void 14161959748cSgd78059 afe_startmac(afe_t *afep) 14171959748cSgd78059 { 14181959748cSgd78059 /* verify exclusive access to the card */ 14191959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 14201959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 14211959748cSgd78059 14221959748cSgd78059 /* start the card */ 14231959748cSgd78059 SETBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 14241959748cSgd78059 14251959748cSgd78059 if (afep->afe_txavail != AFE_TXRING) 14261959748cSgd78059 PUTCSR(afep, CSR_TDR, 0); 14271959748cSgd78059 14281959748cSgd78059 /* tell the mac that we are ready to go! */ 14291959748cSgd78059 if (afep->afe_flags & AFE_RUNNING) 14301959748cSgd78059 mac_tx_update(afep->afe_mh); 1431bdb9230aSGarrett D'Amore 1432bdb9230aSGarrett D'Amore /* start watchdog timer */ 1433bdb9230aSGarrett D'Amore PUTCSR(afep, CSR_TIMER, TIMER_LOOP | 1434bdb9230aSGarrett D'Amore (AFE_WDOGTIMER * 1000 / TIMER_USEC)); 14351959748cSgd78059 } 14361959748cSgd78059 14371959748cSgd78059 void 14381959748cSgd78059 afe_stopmac(afe_t *afep) 14391959748cSgd78059 { 14401959748cSgd78059 int i; 14411959748cSgd78059 14421959748cSgd78059 /* exclusive access to the hardware! */ 14431959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 14441959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 14451959748cSgd78059 14461959748cSgd78059 CLRBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 14471959748cSgd78059 14481959748cSgd78059 /* 14491959748cSgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain. 14501959748cSgd78059 * We just add up to the nearest msec (2), which should be 14511959748cSgd78059 * plenty to complete. 14521959748cSgd78059 * 14531959748cSgd78059 * Note that some chips never seem to indicate the transition to 14541959748cSgd78059 * the stopped state properly. Experience shows that we can safely 14551959748cSgd78059 * proceed anyway, after waiting the requisite timeout. 14561959748cSgd78059 */ 14571959748cSgd78059 for (i = 2000; i != 0; i -= 10) { 14581959748cSgd78059 if ((GETCSR(afep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0) 14591959748cSgd78059 break; 14601959748cSgd78059 drv_usecwait(10); 14611959748cSgd78059 } 14621959748cSgd78059 14631959748cSgd78059 /* prevent an interrupt */ 14641959748cSgd78059 PUTCSR(afep, CSR_SR2, INT_RXSTOPPED | INT_TXSTOPPED); 1465bdb9230aSGarrett D'Amore 1466bdb9230aSGarrett D'Amore /* stop the watchdog timer */ 1467bdb9230aSGarrett D'Amore PUTCSR(afep, CSR_TIMER, 0); 14681959748cSgd78059 } 14691959748cSgd78059 14701959748cSgd78059 void 14711959748cSgd78059 afe_resetrings(afe_t *afep) 14721959748cSgd78059 { 14731959748cSgd78059 int i; 14741959748cSgd78059 14751959748cSgd78059 /* now we need to reset the pointers... */ 14761959748cSgd78059 PUTCSR(afep, CSR_RDB, 0); 14771959748cSgd78059 PUTCSR(afep, CSR_TDB, 0); 14781959748cSgd78059 14791959748cSgd78059 /* reset the descriptor ring pointers */ 14801959748cSgd78059 afep->afe_rxhead = 0; 14811959748cSgd78059 afep->afe_txreclaim = 0; 14821959748cSgd78059 afep->afe_txsend = 0; 14831959748cSgd78059 afep->afe_txavail = AFE_TXRING; 14841959748cSgd78059 14851959748cSgd78059 /* set up transmit descriptor ring */ 14861959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 14871959748cSgd78059 afe_desc_t *tmdp = &afep->afe_txdescp[i]; 14881959748cSgd78059 unsigned control = 0; 14891959748cSgd78059 if (i == (AFE_TXRING - 1)) { 14901959748cSgd78059 control |= TXCTL_ENDRING; 14911959748cSgd78059 } 14921959748cSgd78059 PUTTXDESC(afep, tmdp->desc_status, 0); 14931959748cSgd78059 PUTTXDESC(afep, tmdp->desc_control, control); 14941959748cSgd78059 PUTTXDESC(afep, tmdp->desc_buffer1, 0); 14951959748cSgd78059 PUTTXDESC(afep, tmdp->desc_buffer2, 0); 14961959748cSgd78059 SYNCTXDESC(afep, i, DDI_DMA_SYNC_FORDEV); 14971959748cSgd78059 } 14981959748cSgd78059 PUTCSR(afep, CSR_TDB, afep->afe_txdesc_paddr); 14991959748cSgd78059 15001959748cSgd78059 /* make the receive buffers available */ 15011959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 15021959748cSgd78059 afe_rxbuf_t *rxb = afep->afe_rxbufs[i]; 15031959748cSgd78059 afe_desc_t *rmdp = &afep->afe_rxdescp[i]; 15041959748cSgd78059 unsigned control; 15051959748cSgd78059 15061959748cSgd78059 control = AFE_BUFSZ & RXCTL_BUFLEN1; 15071959748cSgd78059 if (i == (AFE_RXRING - 1)) { 15081959748cSgd78059 control |= RXCTL_ENDRING; 15091959748cSgd78059 } 15101959748cSgd78059 PUTRXDESC(afep, rmdp->desc_buffer1, rxb->rxb_paddr); 15111959748cSgd78059 PUTRXDESC(afep, rmdp->desc_buffer2, 0); 15121959748cSgd78059 PUTRXDESC(afep, rmdp->desc_control, control); 15131959748cSgd78059 PUTRXDESC(afep, rmdp->desc_status, RXSTAT_OWN); 15141959748cSgd78059 SYNCRXDESC(afep, i, DDI_DMA_SYNC_FORDEV); 15151959748cSgd78059 } 15161959748cSgd78059 PUTCSR(afep, CSR_RDB, afep->afe_rxdesc_paddr); 15171959748cSgd78059 } 15181959748cSgd78059 15191959748cSgd78059 void 15201959748cSgd78059 afe_stopall(afe_t *afep) 15211959748cSgd78059 { 15221959748cSgd78059 afe_disableinterrupts(afep); 15231959748cSgd78059 afe_stopmac(afep); 15241959748cSgd78059 } 15251959748cSgd78059 15261959748cSgd78059 void 15271959748cSgd78059 afe_startall(afe_t *afep) 15281959748cSgd78059 { 15291959748cSgd78059 ASSERT(mutex_owned(&afep->afe_intrlock)); 15301959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 15311959748cSgd78059 15321959748cSgd78059 /* make sure interrupts are disabled to begin */ 15331959748cSgd78059 afe_disableinterrupts(afep); 15341959748cSgd78059 15351959748cSgd78059 /* initialize the chip */ 15361959748cSgd78059 (void) afe_initialize(afep); 15371959748cSgd78059 15381959748cSgd78059 /* now we can enable interrupts */ 15391959748cSgd78059 afe_enableinterrupts(afep); 15401959748cSgd78059 15411959748cSgd78059 /* start up the mac */ 15421959748cSgd78059 afe_startmac(afep); 15431959748cSgd78059 } 15441959748cSgd78059 15451959748cSgd78059 void 15461959748cSgd78059 afe_resetall(afe_t *afep) 15471959748cSgd78059 { 15481959748cSgd78059 afe_stopall(afep); 15491959748cSgd78059 afe_startall(afep); 15501959748cSgd78059 } 15511959748cSgd78059 15521959748cSgd78059 afe_txbuf_t * 15531959748cSgd78059 afe_alloctxbuf(afe_t *afep) 15541959748cSgd78059 { 15551959748cSgd78059 ddi_dma_cookie_t dmac; 15561959748cSgd78059 unsigned ncookies; 15571959748cSgd78059 afe_txbuf_t *txb; 15581959748cSgd78059 size_t len; 15591959748cSgd78059 15601959748cSgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP); 15611959748cSgd78059 15621959748cSgd78059 if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_txattr, 15631959748cSgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) { 15641959748cSgd78059 return (NULL); 15651959748cSgd78059 } 15661959748cSgd78059 15671959748cSgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, AFE_BUFSZ, &afe_bufattr, 15681959748cSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, &len, 15691959748cSgd78059 &txb->txb_acch) != DDI_SUCCESS) { 15701959748cSgd78059 return (NULL); 15711959748cSgd78059 } 15721959748cSgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf, 15731959748cSgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 15741959748cSgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) { 15751959748cSgd78059 return (NULL); 15761959748cSgd78059 } 15771959748cSgd78059 txb->txb_paddr = dmac.dmac_address; 15781959748cSgd78059 15791959748cSgd78059 return (txb); 15801959748cSgd78059 } 15811959748cSgd78059 15821959748cSgd78059 void 15831959748cSgd78059 afe_destroytxbuf(afe_txbuf_t *txb) 15841959748cSgd78059 { 15851959748cSgd78059 if (txb != NULL) { 15861959748cSgd78059 if (txb->txb_paddr) 15871959748cSgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah); 15881959748cSgd78059 if (txb->txb_acch) 15891959748cSgd78059 ddi_dma_mem_free(&txb->txb_acch); 15901959748cSgd78059 if (txb->txb_dmah) 15911959748cSgd78059 ddi_dma_free_handle(&txb->txb_dmah); 15921959748cSgd78059 kmem_free(txb, sizeof (*txb)); 15931959748cSgd78059 } 15941959748cSgd78059 } 15951959748cSgd78059 15961959748cSgd78059 afe_rxbuf_t * 15971959748cSgd78059 afe_allocrxbuf(afe_t *afep) 15981959748cSgd78059 { 15991959748cSgd78059 afe_rxbuf_t *rxb; 16001959748cSgd78059 size_t len; 16011959748cSgd78059 unsigned ccnt; 16021959748cSgd78059 ddi_dma_cookie_t dmac; 16031959748cSgd78059 16041959748cSgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP); 16051959748cSgd78059 16061959748cSgd78059 if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 16071959748cSgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) { 16081959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 16091959748cSgd78059 return (NULL); 16101959748cSgd78059 } 16111959748cSgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, AFE_BUFSZ, &afe_bufattr, 16121959748cSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &rxb->rxb_buf, &len, 16131959748cSgd78059 &rxb->rxb_acch) != DDI_SUCCESS) { 16141959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 16151959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 16161959748cSgd78059 return (NULL); 16171959748cSgd78059 } 16181959748cSgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len, 16191959748cSgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac, 16201959748cSgd78059 &ccnt) != DDI_DMA_MAPPED) { 16211959748cSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 16221959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 16231959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 16241959748cSgd78059 return (NULL); 16251959748cSgd78059 } 16261959748cSgd78059 rxb->rxb_paddr = dmac.dmac_address; 16271959748cSgd78059 16281959748cSgd78059 return (rxb); 16291959748cSgd78059 } 16301959748cSgd78059 16311959748cSgd78059 void 16321959748cSgd78059 afe_destroyrxbuf(afe_rxbuf_t *rxb) 16331959748cSgd78059 { 16341959748cSgd78059 if (rxb) { 16351959748cSgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah); 16361959748cSgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 16371959748cSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 16381959748cSgd78059 kmem_free(rxb, sizeof (*rxb)); 16391959748cSgd78059 } 16401959748cSgd78059 } 16411959748cSgd78059 16421959748cSgd78059 /* 16431959748cSgd78059 * Allocate receive resources. 16441959748cSgd78059 */ 16451959748cSgd78059 int 16461959748cSgd78059 afe_allocrxring(afe_t *afep) 16471959748cSgd78059 { 16481959748cSgd78059 int rval; 16491959748cSgd78059 int i; 16501959748cSgd78059 size_t size; 16511959748cSgd78059 size_t len; 16521959748cSgd78059 ddi_dma_cookie_t dmac; 16531959748cSgd78059 unsigned ncookies; 16541959748cSgd78059 caddr_t kaddr; 16551959748cSgd78059 16561959748cSgd78059 size = AFE_RXRING * sizeof (afe_desc_t); 16571959748cSgd78059 16581959748cSgd78059 rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 16591959748cSgd78059 DDI_DMA_SLEEP, NULL, &afep->afe_rxdesc_dmah); 16601959748cSgd78059 if (rval != DDI_SUCCESS) { 16611959748cSgd78059 afe_error(afep->afe_dip, 16621959748cSgd78059 "unable to allocate DMA handle for rx descriptors"); 16631959748cSgd78059 return (DDI_FAILURE); 16641959748cSgd78059 } 16651959748cSgd78059 16661959748cSgd78059 rval = ddi_dma_mem_alloc(afep->afe_rxdesc_dmah, size, &afe_devattr, 16671959748cSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 16681959748cSgd78059 &afep->afe_rxdesc_acch); 16691959748cSgd78059 if (rval != DDI_SUCCESS) { 16701959748cSgd78059 afe_error(afep->afe_dip, 16711959748cSgd78059 "unable to allocate DMA memory for rx descriptors"); 16721959748cSgd78059 return (DDI_FAILURE); 16731959748cSgd78059 } 16741959748cSgd78059 16751959748cSgd78059 rval = ddi_dma_addr_bind_handle(afep->afe_rxdesc_dmah, NULL, kaddr, 16761959748cSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 16771959748cSgd78059 &dmac, &ncookies); 16781959748cSgd78059 if (rval != DDI_DMA_MAPPED) { 16791959748cSgd78059 afe_error(afep->afe_dip, 16801959748cSgd78059 "unable to bind DMA for rx descriptors"); 16811959748cSgd78059 return (DDI_FAILURE); 16821959748cSgd78059 } 16831959748cSgd78059 16841959748cSgd78059 /* because of afe_dma_attr */ 16851959748cSgd78059 ASSERT(ncookies == 1); 16861959748cSgd78059 16871959748cSgd78059 /* we take the 32-bit physical address out of the cookie */ 16881959748cSgd78059 afep->afe_rxdesc_paddr = dmac.dmac_address; 16891959748cSgd78059 afep->afe_rxdescp = (void *)kaddr; 16901959748cSgd78059 16911959748cSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 16921959748cSgd78059 afep->afe_rxbufs = kmem_zalloc(AFE_RXRING * sizeof (afe_rxbuf_t *), 16931959748cSgd78059 KM_SLEEP); 16941959748cSgd78059 16951959748cSgd78059 /* now allocate rx buffers */ 16961959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 16971959748cSgd78059 afe_rxbuf_t *rxb = afe_allocrxbuf(afep); 16981959748cSgd78059 if (rxb == NULL) 16991959748cSgd78059 return (DDI_FAILURE); 17001959748cSgd78059 afep->afe_rxbufs[i] = rxb; 17011959748cSgd78059 } 17021959748cSgd78059 17031959748cSgd78059 return (DDI_SUCCESS); 17041959748cSgd78059 } 17051959748cSgd78059 17061959748cSgd78059 /* 17071959748cSgd78059 * Allocate transmit resources. 17081959748cSgd78059 */ 17091959748cSgd78059 int 17101959748cSgd78059 afe_alloctxring(afe_t *afep) 17111959748cSgd78059 { 17121959748cSgd78059 int rval; 17131959748cSgd78059 int i; 17141959748cSgd78059 size_t size; 17151959748cSgd78059 size_t len; 17161959748cSgd78059 ddi_dma_cookie_t dmac; 17171959748cSgd78059 unsigned ncookies; 17181959748cSgd78059 caddr_t kaddr; 17191959748cSgd78059 17201959748cSgd78059 size = AFE_TXRING * sizeof (afe_desc_t); 17211959748cSgd78059 17221959748cSgd78059 rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr, 17231959748cSgd78059 DDI_DMA_SLEEP, NULL, &afep->afe_txdesc_dmah); 17241959748cSgd78059 if (rval != DDI_SUCCESS) { 17251959748cSgd78059 afe_error(afep->afe_dip, 17261959748cSgd78059 "unable to allocate DMA handle for tx descriptors"); 17271959748cSgd78059 return (DDI_FAILURE); 17281959748cSgd78059 } 17291959748cSgd78059 17301959748cSgd78059 rval = ddi_dma_mem_alloc(afep->afe_txdesc_dmah, size, &afe_devattr, 17311959748cSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 17321959748cSgd78059 &afep->afe_txdesc_acch); 17331959748cSgd78059 if (rval != DDI_SUCCESS) { 17341959748cSgd78059 afe_error(afep->afe_dip, 17351959748cSgd78059 "unable to allocate DMA memory for tx descriptors"); 17361959748cSgd78059 return (DDI_FAILURE); 17371959748cSgd78059 } 17381959748cSgd78059 17391959748cSgd78059 rval = ddi_dma_addr_bind_handle(afep->afe_txdesc_dmah, NULL, kaddr, 17401959748cSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 17411959748cSgd78059 &dmac, &ncookies); 17421959748cSgd78059 if (rval != DDI_DMA_MAPPED) { 17431959748cSgd78059 afe_error(afep->afe_dip, 17441959748cSgd78059 "unable to bind DMA for tx descriptors"); 17451959748cSgd78059 return (DDI_FAILURE); 17461959748cSgd78059 } 17471959748cSgd78059 17481959748cSgd78059 /* because of afe_dma_attr */ 17491959748cSgd78059 ASSERT(ncookies == 1); 17501959748cSgd78059 17511959748cSgd78059 /* we take the 32-bit physical address out of the cookie */ 17521959748cSgd78059 afep->afe_txdesc_paddr = dmac.dmac_address; 17531959748cSgd78059 afep->afe_txdescp = (void *)kaddr; 17541959748cSgd78059 17551959748cSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 17561959748cSgd78059 afep->afe_txbufs = kmem_zalloc(AFE_TXRING * sizeof (afe_txbuf_t *), 17571959748cSgd78059 KM_SLEEP); 17581959748cSgd78059 17591959748cSgd78059 /* now allocate tx buffers */ 17601959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 17611959748cSgd78059 afe_txbuf_t *txb = afe_alloctxbuf(afep); 17621959748cSgd78059 if (txb == NULL) 17631959748cSgd78059 return (DDI_FAILURE); 17641959748cSgd78059 afep->afe_txbufs[i] = txb; 17651959748cSgd78059 } 17661959748cSgd78059 17671959748cSgd78059 return (DDI_SUCCESS); 17681959748cSgd78059 } 17691959748cSgd78059 17701959748cSgd78059 void 17711959748cSgd78059 afe_freerxring(afe_t *afep) 17721959748cSgd78059 { 17731959748cSgd78059 int i; 17741959748cSgd78059 17751959748cSgd78059 for (i = 0; i < AFE_RXRING; i++) { 17761959748cSgd78059 afe_destroyrxbuf(afep->afe_rxbufs[i]); 17771959748cSgd78059 } 17781959748cSgd78059 17791959748cSgd78059 if (afep->afe_rxbufs) { 17801959748cSgd78059 kmem_free(afep->afe_rxbufs, 17811959748cSgd78059 AFE_RXRING * sizeof (afe_rxbuf_t *)); 17821959748cSgd78059 } 17831959748cSgd78059 17841959748cSgd78059 if (afep->afe_rxdesc_paddr) 17851959748cSgd78059 (void) ddi_dma_unbind_handle(afep->afe_rxdesc_dmah); 17861959748cSgd78059 if (afep->afe_rxdesc_acch) 17871959748cSgd78059 ddi_dma_mem_free(&afep->afe_rxdesc_acch); 17881959748cSgd78059 if (afep->afe_rxdesc_dmah) 17891959748cSgd78059 ddi_dma_free_handle(&afep->afe_rxdesc_dmah); 17901959748cSgd78059 } 17911959748cSgd78059 17921959748cSgd78059 void 17931959748cSgd78059 afe_freetxring(afe_t *afep) 17941959748cSgd78059 { 17951959748cSgd78059 int i; 17961959748cSgd78059 17971959748cSgd78059 for (i = 0; i < AFE_TXRING; i++) { 17981959748cSgd78059 afe_destroytxbuf(afep->afe_txbufs[i]); 17991959748cSgd78059 } 18001959748cSgd78059 18011959748cSgd78059 if (afep->afe_txbufs) { 18021959748cSgd78059 kmem_free(afep->afe_txbufs, 18031959748cSgd78059 AFE_TXRING * sizeof (afe_txbuf_t *)); 18041959748cSgd78059 } 18051959748cSgd78059 if (afep->afe_txdesc_paddr) 18061959748cSgd78059 (void) ddi_dma_unbind_handle(afep->afe_txdesc_dmah); 18071959748cSgd78059 if (afep->afe_txdesc_acch) 18081959748cSgd78059 ddi_dma_mem_free(&afep->afe_txdesc_acch); 18091959748cSgd78059 if (afep->afe_txdesc_dmah) 18101959748cSgd78059 ddi_dma_free_handle(&afep->afe_txdesc_dmah); 18111959748cSgd78059 } 18121959748cSgd78059 18131959748cSgd78059 /* 18141959748cSgd78059 * Interrupt service routine. 18151959748cSgd78059 */ 18161959748cSgd78059 unsigned 18171959748cSgd78059 afe_intr(caddr_t arg) 18181959748cSgd78059 { 18191959748cSgd78059 afe_t *afep = (void *)arg; 18201959748cSgd78059 uint32_t status; 18211959748cSgd78059 mblk_t *mp = NULL; 1822bdb9230aSGarrett D'Amore boolean_t doreset = B_FALSE; 18231959748cSgd78059 18241959748cSgd78059 mutex_enter(&afep->afe_intrlock); 18251959748cSgd78059 18261959748cSgd78059 if (afep->afe_flags & AFE_SUSPENDED) { 18271959748cSgd78059 /* we cannot receive interrupts! */ 18281959748cSgd78059 mutex_exit(&afep->afe_intrlock); 18291959748cSgd78059 return (DDI_INTR_UNCLAIMED); 18301959748cSgd78059 } 18311959748cSgd78059 18321959748cSgd78059 /* check interrupt status bits, did we interrupt? */ 18331959748cSgd78059 status = GETCSR(afep, CSR_SR2) & INT_ALL; 18341959748cSgd78059 18351959748cSgd78059 if (status == 0) { 18361959748cSgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 18371959748cSgd78059 mutex_exit(&afep->afe_intrlock); 18381959748cSgd78059 return (DDI_INTR_UNCLAIMED); 18391959748cSgd78059 } 18401959748cSgd78059 /* ack the interrupt */ 18411959748cSgd78059 PUTCSR(afep, CSR_SR2, status); 18421959748cSgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++; 18431959748cSgd78059 18441959748cSgd78059 if (!(afep->afe_flags & AFE_RUNNING)) { 18451959748cSgd78059 /* not running, don't touch anything */ 18461959748cSgd78059 mutex_exit(&afep->afe_intrlock); 18471959748cSgd78059 return (DDI_INTR_CLAIMED); 18481959748cSgd78059 } 18491959748cSgd78059 18501959748cSgd78059 if (status & (INT_RXOK|INT_RXNOBUF)) { 18511959748cSgd78059 /* receive packets */ 18521959748cSgd78059 mp = afe_receive(afep); 18531959748cSgd78059 if (status & INT_RXNOBUF) 18541959748cSgd78059 PUTCSR(afep, CSR_RDR, 0); /* wake up chip */ 18551959748cSgd78059 } 18561959748cSgd78059 18571959748cSgd78059 if (status & INT_TXOK) { 18581959748cSgd78059 /* transmit completed */ 18591959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 18601959748cSgd78059 afe_reclaim(afep); 18611959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 18621959748cSgd78059 } 18631959748cSgd78059 1864bdb9230aSGarrett D'Amore if ((status & INT_TIMER) && (afe_watchdog(afep) != DDI_SUCCESS)) { 1865bdb9230aSGarrett D'Amore doreset = B_TRUE; 18661959748cSgd78059 } 18671959748cSgd78059 18681959748cSgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED| 18691959748cSgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) { 18701959748cSgd78059 18711959748cSgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) { 18721959748cSgd78059 afep->afe_jabber++; 18731959748cSgd78059 } 1874bdb9230aSGarrett D'Amore doreset = B_TRUE; 18751959748cSgd78059 } 18761959748cSgd78059 18771959748cSgd78059 if (status & INT_BUSERR) { 18781959748cSgd78059 switch (GETCSR(afep, CSR_SR) & SR_BERR_TYPE) { 18791959748cSgd78059 case SR_BERR_PARITY: 18801959748cSgd78059 afe_error(afep->afe_dip, "PCI parity error"); 18811959748cSgd78059 break; 18821959748cSgd78059 case SR_BERR_TARGET_ABORT: 18831959748cSgd78059 afe_error(afep->afe_dip, "PCI target abort"); 18841959748cSgd78059 break; 18851959748cSgd78059 case SR_BERR_MASTER_ABORT: 18861959748cSgd78059 afe_error(afep->afe_dip, "PCI master abort"); 18871959748cSgd78059 break; 18881959748cSgd78059 default: 18891959748cSgd78059 afe_error(afep->afe_dip, "Unknown PCI error"); 18901959748cSgd78059 break; 18911959748cSgd78059 } 18921959748cSgd78059 18931959748cSgd78059 /* reset the chip in an attempt to fix things */ 1894bdb9230aSGarrett D'Amore doreset = B_TRUE; 1895bdb9230aSGarrett D'Amore } 1896bdb9230aSGarrett D'Amore 1897bdb9230aSGarrett D'Amore 1898bdb9230aSGarrett D'Amore if (doreset) { 18991959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 19001959748cSgd78059 afe_resetall(afep); 19011959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 1902bdb9230aSGarrett D'Amore mutex_exit(&afep->afe_intrlock); 1903bdb9230aSGarrett D'Amore 1904bdb9230aSGarrett D'Amore mii_reset(afep->afe_mii); 1905bdb9230aSGarrett D'Amore } else { 1906bdb9230aSGarrett D'Amore mutex_exit(&afep->afe_intrlock); 19071959748cSgd78059 } 19081959748cSgd78059 1909bdb9230aSGarrett D'Amore if (status & INT_LINKCHG) { 1910bdb9230aSGarrett D'Amore mii_check(afep->afe_mii); 1911bdb9230aSGarrett D'Amore } 19121959748cSgd78059 19131959748cSgd78059 /* 19141959748cSgd78059 * Send up packets. We do this outside of the intrlock. 19151959748cSgd78059 */ 19161959748cSgd78059 if (mp) { 19171959748cSgd78059 mac_rx(afep->afe_mh, NULL, mp); 19181959748cSgd78059 } 19191959748cSgd78059 19201959748cSgd78059 return (DDI_INTR_CLAIMED); 19211959748cSgd78059 } 19221959748cSgd78059 19231959748cSgd78059 void 19241959748cSgd78059 afe_enableinterrupts(afe_t *afep) 19251959748cSgd78059 { 19261959748cSgd78059 unsigned mask = INT_WANTED; 19271959748cSgd78059 19281959748cSgd78059 if (afep->afe_wantw) 19291959748cSgd78059 mask |= INT_TXOK; 19301959748cSgd78059 19311959748cSgd78059 PUTCSR(afep, CSR_IER2, mask); 19321959748cSgd78059 19331959748cSgd78059 if (AFE_MODEL(afep) == MODEL_COMET) { 19341959748cSgd78059 /* 19351959748cSgd78059 * On the Comet, this is the internal transceiver 19361959748cSgd78059 * interrupt. We program the Comet's built-in PHY to 19371959748cSgd78059 * enable certain interrupts. 19381959748cSgd78059 */ 19391959748cSgd78059 PUTCSR16(afep, CSR_XIE, XIE_LDE | XIE_ANCE); 19401959748cSgd78059 } 19411959748cSgd78059 } 19421959748cSgd78059 19431959748cSgd78059 void 19441959748cSgd78059 afe_disableinterrupts(afe_t *afep) 19451959748cSgd78059 { 19461959748cSgd78059 /* disable further interrupts */ 19471959748cSgd78059 PUTCSR(afep, CSR_IER2, INT_NONE); 19481959748cSgd78059 19491959748cSgd78059 /* clear any pending interrupts */ 19501959748cSgd78059 PUTCSR(afep, CSR_SR2, INT_ALL); 19511959748cSgd78059 } 19521959748cSgd78059 19531959748cSgd78059 boolean_t 19541959748cSgd78059 afe_send(afe_t *afep, mblk_t *mp) 19551959748cSgd78059 { 19561959748cSgd78059 size_t len; 19571959748cSgd78059 afe_txbuf_t *txb; 19581959748cSgd78059 afe_desc_t *tmd; 19591959748cSgd78059 uint32_t control; 19601959748cSgd78059 int txsend; 19611959748cSgd78059 19621959748cSgd78059 ASSERT(mutex_owned(&afep->afe_xmtlock)); 19631959748cSgd78059 ASSERT(mp != NULL); 19641959748cSgd78059 19651959748cSgd78059 len = msgsize(mp); 19661959748cSgd78059 if (len > ETHERVLANMTU) { 19671959748cSgd78059 afep->afe_macxmt_errors++; 19681959748cSgd78059 freemsg(mp); 19691959748cSgd78059 return (B_TRUE); 19701959748cSgd78059 } 19711959748cSgd78059 19721959748cSgd78059 if (afep->afe_txavail < AFE_TXRECLAIM) 19731959748cSgd78059 afe_reclaim(afep); 19741959748cSgd78059 19751959748cSgd78059 if (afep->afe_txavail == 0) { 19761959748cSgd78059 /* no more tmds */ 19771959748cSgd78059 afep->afe_wantw = B_TRUE; 19781959748cSgd78059 /* enable TX interrupt */ 19791959748cSgd78059 afe_enableinterrupts(afep); 19801959748cSgd78059 return (B_FALSE); 19811959748cSgd78059 } 19821959748cSgd78059 19831959748cSgd78059 txsend = afep->afe_txsend; 19841959748cSgd78059 19851959748cSgd78059 /* 19861959748cSgd78059 * For simplicity, we just do a copy into a preallocated 19871959748cSgd78059 * DMA buffer. 19881959748cSgd78059 */ 19891959748cSgd78059 19901959748cSgd78059 txb = afep->afe_txbufs[txsend]; 19911959748cSgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */ 19921959748cSgd78059 19931959748cSgd78059 /* 19941959748cSgd78059 * Statistics. 19951959748cSgd78059 */ 19961959748cSgd78059 afep->afe_opackets++; 19971959748cSgd78059 afep->afe_obytes += len; 19981959748cSgd78059 if (txb->txb_buf[0] & 0x1) { 19991959748cSgd78059 if (bcmp(txb->txb_buf, afe_broadcast, ETHERADDRL) != 0) 20001959748cSgd78059 afep->afe_multixmt++; 20011959748cSgd78059 else 20021959748cSgd78059 afep->afe_brdcstxmt++; 20031959748cSgd78059 } 20041959748cSgd78059 20051959748cSgd78059 /* note len is already known to be a small unsigned */ 20061959748cSgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE; 20071959748cSgd78059 20081959748cSgd78059 if (txsend == (AFE_TXRING - 1)) 20091959748cSgd78059 control |= TXCTL_ENDRING; 20101959748cSgd78059 20111959748cSgd78059 tmd = &afep->afe_txdescp[txsend]; 20121959748cSgd78059 20131959748cSgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV); 20141959748cSgd78059 PUTTXDESC(afep, tmd->desc_control, control); 20151959748cSgd78059 PUTTXDESC(afep, tmd->desc_buffer1, txb->txb_paddr); 20161959748cSgd78059 PUTTXDESC(afep, tmd->desc_buffer2, 0); 20171959748cSgd78059 PUTTXDESC(afep, tmd->desc_status, TXSTAT_OWN); 20181959748cSgd78059 /* sync the descriptor out to the device */ 20191959748cSgd78059 SYNCTXDESC(afep, txsend, DDI_DMA_SYNC_FORDEV); 20201959748cSgd78059 20211959748cSgd78059 /* 20221959748cSgd78059 * Note the new values of txavail and txsend. 20231959748cSgd78059 */ 20241959748cSgd78059 afep->afe_txavail--; 20251959748cSgd78059 afep->afe_txsend = (txsend + 1) % AFE_TXRING; 20261959748cSgd78059 20271959748cSgd78059 /* 20281959748cSgd78059 * It should never, ever take more than 5 seconds to drain 20291959748cSgd78059 * the ring. If it happens, then we are stuck! 20301959748cSgd78059 */ 20311959748cSgd78059 afep->afe_txstall_time = gethrtime() + (5 * 1000000000ULL); 20321959748cSgd78059 20331959748cSgd78059 /* 20341959748cSgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 20351959748cSgd78059 * etc. 20361959748cSgd78059 */ 20371959748cSgd78059 PUTCSR(afep, CSR_TDR, 0); 20381959748cSgd78059 20391959748cSgd78059 return (B_TRUE); 20401959748cSgd78059 } 20411959748cSgd78059 20421959748cSgd78059 /* 20431959748cSgd78059 * Reclaim buffers that have completed transmission. 20441959748cSgd78059 */ 20451959748cSgd78059 void 20461959748cSgd78059 afe_reclaim(afe_t *afep) 20471959748cSgd78059 { 20481959748cSgd78059 afe_desc_t *tmdp; 20491959748cSgd78059 20501959748cSgd78059 while (afep->afe_txavail != AFE_TXRING) { 20511959748cSgd78059 uint32_t status; 20521959748cSgd78059 uint32_t control; 20531959748cSgd78059 int index = afep->afe_txreclaim; 20541959748cSgd78059 20551959748cSgd78059 tmdp = &afep->afe_txdescp[index]; 20561959748cSgd78059 20571959748cSgd78059 /* sync it before we read it */ 20581959748cSgd78059 SYNCTXDESC(afep, index, DDI_DMA_SYNC_FORKERNEL); 20591959748cSgd78059 20601959748cSgd78059 control = GETTXDESC(afep, tmdp->desc_control); 20611959748cSgd78059 status = GETTXDESC(afep, tmdp->desc_status); 20621959748cSgd78059 20631959748cSgd78059 if (status & TXSTAT_OWN) { 20641959748cSgd78059 /* chip is still working on it, we're done */ 20651959748cSgd78059 break; 20661959748cSgd78059 } 20671959748cSgd78059 20681959748cSgd78059 afep->afe_txavail++; 20691959748cSgd78059 afep->afe_txreclaim = (index + 1) % AFE_TXRING; 20701959748cSgd78059 20711959748cSgd78059 /* in the most common successful case, all bits are clear */ 20721959748cSgd78059 if (status == 0) 20731959748cSgd78059 continue; 20741959748cSgd78059 20751959748cSgd78059 if ((control & TXCTL_LAST) == 0) 20761959748cSgd78059 continue; 20771959748cSgd78059 20781959748cSgd78059 if (status & TXSTAT_TXERR) { 20791959748cSgd78059 afep->afe_errxmt++; 20801959748cSgd78059 20811959748cSgd78059 if (status & TXSTAT_JABBER) { 20821959748cSgd78059 /* transmit jabber timeout */ 20831959748cSgd78059 afep->afe_macxmt_errors++; 20841959748cSgd78059 } 20851959748cSgd78059 if (status & 20861959748cSgd78059 (TXSTAT_CARRLOST | TXSTAT_NOCARR)) { 20871959748cSgd78059 afep->afe_carrier_errors++; 20881959748cSgd78059 } 20891959748cSgd78059 if (status & TXSTAT_UFLOW) { 20901959748cSgd78059 afep->afe_underflow++; 20911959748cSgd78059 } 20921959748cSgd78059 if (status & TXSTAT_LATECOL) { 20931959748cSgd78059 afep->afe_tx_late_collisions++; 20941959748cSgd78059 } 20951959748cSgd78059 if (status & TXSTAT_EXCOLL) { 20961959748cSgd78059 afep->afe_ex_collisions++; 20971959748cSgd78059 afep->afe_collisions += 16; 20981959748cSgd78059 } 20991959748cSgd78059 } 21001959748cSgd78059 21011959748cSgd78059 if (status & TXSTAT_DEFER) { 21021959748cSgd78059 afep->afe_defer_xmts++; 21031959748cSgd78059 } 21041959748cSgd78059 21051959748cSgd78059 /* collision counting */ 21061959748cSgd78059 if (TXCOLLCNT(status) == 1) { 21071959748cSgd78059 afep->afe_collisions++; 21081959748cSgd78059 afep->afe_first_collisions++; 21091959748cSgd78059 } else if (TXCOLLCNT(status)) { 21101959748cSgd78059 afep->afe_collisions += TXCOLLCNT(status); 21111959748cSgd78059 afep->afe_multi_collisions += TXCOLLCNT(status); 21121959748cSgd78059 } 21131959748cSgd78059 } 21141959748cSgd78059 21151959748cSgd78059 if (afep->afe_txavail >= AFE_TXRESCHED) { 21161959748cSgd78059 if (afep->afe_wantw) { 21171959748cSgd78059 /* 21181959748cSgd78059 * we were able to reclaim some packets, so 21191959748cSgd78059 * disable tx interrupts 21201959748cSgd78059 */ 21211959748cSgd78059 afep->afe_wantw = B_FALSE; 21221959748cSgd78059 afe_enableinterrupts(afep); 21231959748cSgd78059 mac_tx_update(afep->afe_mh); 21241959748cSgd78059 } 21251959748cSgd78059 } 21261959748cSgd78059 } 21271959748cSgd78059 21281959748cSgd78059 mblk_t * 21291959748cSgd78059 afe_receive(afe_t *afep) 21301959748cSgd78059 { 21311959748cSgd78059 unsigned len; 21321959748cSgd78059 afe_rxbuf_t *rxb; 21331959748cSgd78059 afe_desc_t *rmd; 21341959748cSgd78059 uint32_t status; 21351959748cSgd78059 mblk_t *mpchain, **mpp, *mp; 21361959748cSgd78059 int head, cnt; 21371959748cSgd78059 21381959748cSgd78059 mpchain = NULL; 21391959748cSgd78059 mpp = &mpchain; 21401959748cSgd78059 head = afep->afe_rxhead; 21411959748cSgd78059 21421959748cSgd78059 /* limit the number of packets we process to a half ring size */ 21431959748cSgd78059 for (cnt = 0; cnt < AFE_RXRING / 2; cnt++) { 21441959748cSgd78059 21451959748cSgd78059 rmd = &afep->afe_rxdescp[head]; 21461959748cSgd78059 rxb = afep->afe_rxbufs[head]; 21471959748cSgd78059 21481959748cSgd78059 SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORKERNEL); 21491959748cSgd78059 status = GETRXDESC(afep, rmd->desc_status); 21501959748cSgd78059 if (status & RXSTAT_OWN) { 21511959748cSgd78059 /* chip is still chewing on it */ 21521959748cSgd78059 break; 21531959748cSgd78059 } 21541959748cSgd78059 21551959748cSgd78059 /* discard the ethernet frame checksum */ 21561959748cSgd78059 len = RXLENGTH(status) - ETHERFCSL; 21571959748cSgd78059 21581959748cSgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) != 21591959748cSgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) { 21601959748cSgd78059 21611959748cSgd78059 afep->afe_errrcv++; 21621959748cSgd78059 21631959748cSgd78059 /* 21641959748cSgd78059 * Abnormal status bits detected, analyze further. 21651959748cSgd78059 */ 21661959748cSgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) != 21671959748cSgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) { 2168bdb9230aSGarrett D'Amore 21691959748cSgd78059 if (status & RXSTAT_FIRST) { 21701959748cSgd78059 afep->afe_toolong_errors++; 21711959748cSgd78059 } 21721959748cSgd78059 } else if (status & RXSTAT_DESCERR) { 21731959748cSgd78059 afep->afe_macrcv_errors++; 21741959748cSgd78059 21751959748cSgd78059 } else if (status & RXSTAT_RUNT) { 21761959748cSgd78059 afep->afe_runt++; 21771959748cSgd78059 21781959748cSgd78059 } else if (status & RXSTAT_COLLSEEN) { 21791959748cSgd78059 /* this should really be rx_late_collisions */ 21801959748cSgd78059 afep->afe_macrcv_errors++; 21811959748cSgd78059 21821959748cSgd78059 } else if (status & RXSTAT_DRIBBLE) { 21831959748cSgd78059 afep->afe_align_errors++; 21841959748cSgd78059 21851959748cSgd78059 } else if (status & RXSTAT_CRCERR) { 21861959748cSgd78059 afep->afe_fcs_errors++; 21871959748cSgd78059 21881959748cSgd78059 } else if (status & RXSTAT_OFLOW) { 21891959748cSgd78059 afep->afe_overflow++; 21901959748cSgd78059 } 21911959748cSgd78059 } 21921959748cSgd78059 21931959748cSgd78059 else if (len > ETHERVLANMTU) { 21941959748cSgd78059 afep->afe_errrcv++; 21951959748cSgd78059 afep->afe_toolong_errors++; 21961959748cSgd78059 } 21971959748cSgd78059 21981959748cSgd78059 /* 21991959748cSgd78059 * At this point, the chip thinks the packet is OK. 22001959748cSgd78059 */ 22011959748cSgd78059 else { 22021959748cSgd78059 mp = allocb(len + AFE_HEADROOM, 0); 22031959748cSgd78059 if (mp == NULL) { 22041959748cSgd78059 afep->afe_errrcv++; 22051959748cSgd78059 afep->afe_norcvbuf++; 22061959748cSgd78059 goto skip; 22071959748cSgd78059 } 22081959748cSgd78059 22091959748cSgd78059 /* sync the buffer before we look at it */ 22101959748cSgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL); 22111959748cSgd78059 mp->b_rptr += AFE_HEADROOM; 22121959748cSgd78059 mp->b_wptr = mp->b_rptr + len; 22131959748cSgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len); 22141959748cSgd78059 22151959748cSgd78059 afep->afe_ipackets++; 22161959748cSgd78059 afep->afe_rbytes += len; 22171959748cSgd78059 if (status & RXSTAT_GROUP) { 22181959748cSgd78059 if (bcmp(mp->b_rptr, afe_broadcast, 22191959748cSgd78059 ETHERADDRL) == 0) 22201959748cSgd78059 afep->afe_brdcstrcv++; 22211959748cSgd78059 else 22221959748cSgd78059 afep->afe_multircv++; 22231959748cSgd78059 } 22241959748cSgd78059 *mpp = mp; 22251959748cSgd78059 mpp = &mp->b_next; 22261959748cSgd78059 } 22271959748cSgd78059 22281959748cSgd78059 skip: 22291959748cSgd78059 /* return ring entry to the hardware */ 22301959748cSgd78059 PUTRXDESC(afep, rmd->desc_status, RXSTAT_OWN); 22311959748cSgd78059 SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORDEV); 22321959748cSgd78059 22331959748cSgd78059 /* advance to next RMD */ 22341959748cSgd78059 head = (head + 1) % AFE_RXRING; 22351959748cSgd78059 } 22361959748cSgd78059 22371959748cSgd78059 afep->afe_rxhead = head; 22381959748cSgd78059 22391959748cSgd78059 return (mpchain); 22401959748cSgd78059 } 22411959748cSgd78059 22421959748cSgd78059 int 22431959748cSgd78059 afe_m_stat(void *arg, uint_t stat, uint64_t *val) 22441959748cSgd78059 { 22451959748cSgd78059 afe_t *afep = arg; 22461959748cSgd78059 22471959748cSgd78059 mutex_enter(&afep->afe_xmtlock); 22481959748cSgd78059 if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == AFE_RUNNING) 22491959748cSgd78059 afe_reclaim(afep); 22501959748cSgd78059 mutex_exit(&afep->afe_xmtlock); 22511959748cSgd78059 2252bdb9230aSGarrett D'Amore if (mii_m_getstat(afep->afe_mii, stat, val) == 0) { 2253bdb9230aSGarrett D'Amore return (0); 2254bdb9230aSGarrett D'Amore } 22551959748cSgd78059 switch (stat) { 22561959748cSgd78059 case MAC_STAT_MULTIRCV: 22571959748cSgd78059 *val = afep->afe_multircv; 22581959748cSgd78059 break; 22591959748cSgd78059 22601959748cSgd78059 case MAC_STAT_BRDCSTRCV: 22611959748cSgd78059 *val = afep->afe_brdcstrcv; 22621959748cSgd78059 break; 22631959748cSgd78059 22641959748cSgd78059 case MAC_STAT_MULTIXMT: 22651959748cSgd78059 *val = afep->afe_multixmt; 22661959748cSgd78059 break; 22671959748cSgd78059 22681959748cSgd78059 case MAC_STAT_BRDCSTXMT: 22691959748cSgd78059 *val = afep->afe_brdcstxmt; 22701959748cSgd78059 break; 22711959748cSgd78059 22721959748cSgd78059 case MAC_STAT_IPACKETS: 22731959748cSgd78059 *val = afep->afe_ipackets; 22741959748cSgd78059 break; 22751959748cSgd78059 22761959748cSgd78059 case MAC_STAT_RBYTES: 22771959748cSgd78059 *val = afep->afe_rbytes; 22781959748cSgd78059 break; 22791959748cSgd78059 22801959748cSgd78059 case MAC_STAT_OPACKETS: 22811959748cSgd78059 *val = afep->afe_opackets; 22821959748cSgd78059 break; 22831959748cSgd78059 22841959748cSgd78059 case MAC_STAT_OBYTES: 22851959748cSgd78059 *val = afep->afe_obytes; 22861959748cSgd78059 break; 22871959748cSgd78059 22881959748cSgd78059 case MAC_STAT_NORCVBUF: 22891959748cSgd78059 *val = afep->afe_norcvbuf; 22901959748cSgd78059 break; 22911959748cSgd78059 22921959748cSgd78059 case MAC_STAT_NOXMTBUF: 22931959748cSgd78059 *val = 0; 22941959748cSgd78059 break; 22951959748cSgd78059 22961959748cSgd78059 case MAC_STAT_COLLISIONS: 22971959748cSgd78059 *val = afep->afe_collisions; 22981959748cSgd78059 break; 22991959748cSgd78059 23001959748cSgd78059 case MAC_STAT_IERRORS: 23011959748cSgd78059 *val = afep->afe_errrcv; 23021959748cSgd78059 break; 23031959748cSgd78059 23041959748cSgd78059 case MAC_STAT_OERRORS: 23051959748cSgd78059 *val = afep->afe_errxmt; 23061959748cSgd78059 break; 23071959748cSgd78059 23081959748cSgd78059 case ETHER_STAT_ALIGN_ERRORS: 23091959748cSgd78059 *val = afep->afe_align_errors; 23101959748cSgd78059 break; 23111959748cSgd78059 23121959748cSgd78059 case ETHER_STAT_FCS_ERRORS: 23131959748cSgd78059 *val = afep->afe_fcs_errors; 23141959748cSgd78059 break; 23151959748cSgd78059 23161959748cSgd78059 case ETHER_STAT_SQE_ERRORS: 23171959748cSgd78059 *val = afep->afe_sqe_errors; 23181959748cSgd78059 break; 23191959748cSgd78059 23201959748cSgd78059 case ETHER_STAT_DEFER_XMTS: 23211959748cSgd78059 *val = afep->afe_defer_xmts; 23221959748cSgd78059 break; 23231959748cSgd78059 23241959748cSgd78059 case ETHER_STAT_FIRST_COLLISIONS: 23251959748cSgd78059 *val = afep->afe_first_collisions; 23261959748cSgd78059 break; 23271959748cSgd78059 23281959748cSgd78059 case ETHER_STAT_MULTI_COLLISIONS: 23291959748cSgd78059 *val = afep->afe_multi_collisions; 23301959748cSgd78059 break; 23311959748cSgd78059 23321959748cSgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 23331959748cSgd78059 *val = afep->afe_tx_late_collisions; 23341959748cSgd78059 break; 23351959748cSgd78059 23361959748cSgd78059 case ETHER_STAT_EX_COLLISIONS: 23371959748cSgd78059 *val = afep->afe_ex_collisions; 23381959748cSgd78059 break; 23391959748cSgd78059 23401959748cSgd78059 case ETHER_STAT_MACXMT_ERRORS: 23411959748cSgd78059 *val = afep->afe_macxmt_errors; 23421959748cSgd78059 break; 23431959748cSgd78059 23441959748cSgd78059 case ETHER_STAT_CARRIER_ERRORS: 23451959748cSgd78059 *val = afep->afe_carrier_errors; 23461959748cSgd78059 break; 23471959748cSgd78059 23481959748cSgd78059 case ETHER_STAT_TOOLONG_ERRORS: 23491959748cSgd78059 *val = afep->afe_toolong_errors; 23501959748cSgd78059 break; 23511959748cSgd78059 23521959748cSgd78059 case ETHER_STAT_MACRCV_ERRORS: 23531959748cSgd78059 *val = afep->afe_macrcv_errors; 23541959748cSgd78059 break; 23551959748cSgd78059 23561959748cSgd78059 case MAC_STAT_OVERFLOWS: 23571959748cSgd78059 *val = afep->afe_overflow; 23581959748cSgd78059 break; 23591959748cSgd78059 23601959748cSgd78059 case MAC_STAT_UNDERFLOWS: 23611959748cSgd78059 *val = afep->afe_underflow; 23621959748cSgd78059 break; 23631959748cSgd78059 23641959748cSgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 23651959748cSgd78059 *val = afep->afe_runt; 23661959748cSgd78059 break; 23671959748cSgd78059 23681959748cSgd78059 case ETHER_STAT_JABBER_ERRORS: 23691959748cSgd78059 *val = afep->afe_jabber; 23701959748cSgd78059 break; 23711959748cSgd78059 23721959748cSgd78059 default: 23731959748cSgd78059 return (ENOTSUP); 23741959748cSgd78059 } 23751959748cSgd78059 return (0); 23761959748cSgd78059 } 23771959748cSgd78059 237896fb08b9Sgd78059 int 2379*0dc2366fSVenugopal Iyer afe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 2380*0dc2366fSVenugopal Iyer void *val) 23811959748cSgd78059 { 238296fb08b9Sgd78059 afe_t *afep = arg; 23831959748cSgd78059 2384*0dc2366fSVenugopal Iyer return (mii_m_getprop(afep->afe_mii, name, num, sz, val)); 23851959748cSgd78059 } 23861959748cSgd78059 23871959748cSgd78059 int 238896fb08b9Sgd78059 afe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 238996fb08b9Sgd78059 const void *val) 23901959748cSgd78059 { 239196fb08b9Sgd78059 afe_t *afep = arg; 23921959748cSgd78059 2393bdb9230aSGarrett D'Amore return (mii_m_setprop(afep->afe_mii, name, num, sz, val)); 23941959748cSgd78059 } 23951959748cSgd78059 2396*0dc2366fSVenugopal Iyer static void 2397*0dc2366fSVenugopal Iyer afe_m_propinfo(void *arg, const char *name, mac_prop_id_t num, 2398*0dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 2399*0dc2366fSVenugopal Iyer { 2400*0dc2366fSVenugopal Iyer afe_t *afep = arg; 2401*0dc2366fSVenugopal Iyer 2402*0dc2366fSVenugopal Iyer mii_m_propinfo(afep->afe_mii, name, num, prh); 2403*0dc2366fSVenugopal Iyer } 2404*0dc2366fSVenugopal Iyer 24051959748cSgd78059 /* 24061959748cSgd78059 * Debugging and error reporting. 24071959748cSgd78059 */ 24081959748cSgd78059 void 24091959748cSgd78059 afe_error(dev_info_t *dip, char *fmt, ...) 24101959748cSgd78059 { 24111959748cSgd78059 va_list ap; 24121959748cSgd78059 char buf[256]; 24131959748cSgd78059 24141959748cSgd78059 va_start(ap, fmt); 24151959748cSgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 24161959748cSgd78059 va_end(ap); 24171959748cSgd78059 24181959748cSgd78059 if (dip) { 24191959748cSgd78059 cmn_err(CE_WARN, "%s%d: %s", 24201959748cSgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf); 24211959748cSgd78059 } else { 24221959748cSgd78059 cmn_err(CE_WARN, "afe: %s", buf); 24231959748cSgd78059 } 24241959748cSgd78059 } 2425