14978Sgd78059 /* 24978Sgd78059 * Solaris driver for ethernet cards based on the Macronix 98715 34978Sgd78059 * 44978Sgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>. 54978Sgd78059 * All rights reserved. 64978Sgd78059 * 74978Sgd78059 * Redistribution and use in source and binary forms, with or without 84978Sgd78059 * modification, are permitted provided that the following conditions 94978Sgd78059 * are met: 104978Sgd78059 * 1. Redistributions of source code must retain the above copyright 114978Sgd78059 * notice, this list of conditions and the following disclaimer. 124978Sgd78059 * 2. Redistributions in binary form must reproduce the above copyright 134978Sgd78059 * notice, this list of conditions and the following disclaimer in the 144978Sgd78059 * documentation and/or other materials provided with the distribution. 154978Sgd78059 * 3. Neither the name of the author nor the names of any co-contributors 164978Sgd78059 * may be used to endorse or promote products derived from this software 174978Sgd78059 * without specific prior written permission. 184978Sgd78059 * 194978Sgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' 204978Sgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 214978Sgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 224978Sgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 234978Sgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 244978Sgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 254978Sgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 264978Sgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 274978Sgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 284978Sgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 294978Sgd78059 * POSSIBILITY OF SUCH DAMAGE. 304978Sgd78059 */ 316684Sgd78059 /* 32*9199Sgdamore@opensolaris.org * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 336684Sgd78059 * Use is subject to license terms. 346684Sgd78059 */ 354978Sgd78059 364978Sgd78059 374978Sgd78059 #include <sys/varargs.h> 384978Sgd78059 #include <sys/types.h> 394978Sgd78059 #include <sys/modctl.h> 404978Sgd78059 #include <sys/conf.h> 414978Sgd78059 #include <sys/devops.h> 424978Sgd78059 #include <sys/stream.h> 434978Sgd78059 #include <sys/strsun.h> 444978Sgd78059 #include <sys/cmn_err.h> 454978Sgd78059 #include <sys/dlpi.h> 464978Sgd78059 #include <sys/ethernet.h> 474978Sgd78059 #include <sys/kmem.h> 484978Sgd78059 #include <sys/time.h> 494978Sgd78059 #include <sys/miiregs.h> 504978Sgd78059 #include <sys/strsun.h> 514978Sgd78059 #include <sys/mac.h> 524978Sgd78059 #include <sys/mac_ether.h> 534978Sgd78059 #include <sys/ddi.h> 544978Sgd78059 #include <sys/sunddi.h> 555895Syz147064 #include <sys/vlan.h> 564978Sgd78059 574978Sgd78059 #include "mxfe.h" 584978Sgd78059 #include "mxfeimpl.h" 594978Sgd78059 604978Sgd78059 /* 614978Sgd78059 * Driver globals. 624978Sgd78059 */ 634978Sgd78059 644978Sgd78059 /* patchable debug flag ... must not be static! */ 654978Sgd78059 #ifdef DEBUG 664978Sgd78059 unsigned mxfe_debug = DWARN; 674978Sgd78059 #endif 684978Sgd78059 694978Sgd78059 /* table of supported devices */ 704978Sgd78059 static mxfe_card_t mxfe_cards[] = { 714978Sgd78059 724978Sgd78059 /* 734978Sgd78059 * Lite-On products 744978Sgd78059 */ 754978Sgd78059 { 0x11ad, 0xc115, 0, 0, "Lite-On LC82C115", MXFE_PNICII }, 764978Sgd78059 774978Sgd78059 /* 784978Sgd78059 * Macronix chips 794978Sgd78059 */ 804978Sgd78059 { 0x10d9, 0x0531, 0x25, 0xff, "Macronix MX98715AEC", MXFE_98715AEC }, 814978Sgd78059 { 0x10d9, 0x0531, 0x20, 0xff, "Macronix MX98715A", MXFE_98715A }, 824978Sgd78059 { 0x10d9, 0x0531, 0x60, 0xff, "Macronix MX98715B", MXFE_98715B }, 834978Sgd78059 { 0x10d9, 0x0531, 0x30, 0xff, "Macronix MX98725", MXFE_98725 }, 844978Sgd78059 { 0x10d9, 0x0531, 0x00, 0xff, "Macronix MX98715", MXFE_98715 }, 854978Sgd78059 { 0x10d9, 0x0512, 0, 0, "Macronix MX98713", MXFE_98713 }, 864978Sgd78059 874978Sgd78059 /* 884978Sgd78059 * Compex (relabeled Macronix products) 894978Sgd78059 */ 904978Sgd78059 { 0x11fc, 0x9881, 0x00, 0x00, "Compex 9881", MXFE_98713 }, 914978Sgd78059 { 0x11fc, 0x9881, 0x10, 0xff, "Compex 9881A", MXFE_98713A }, 924978Sgd78059 /* 934978Sgd78059 * Models listed here 944978Sgd78059 */ 954978Sgd78059 { 0x11ad, 0xc001, 0, 0, "Linksys LNE100TX", MXFE_PNICII }, 964978Sgd78059 { 0x2646, 0x000b, 0, 0, "Kingston KNE111TX", MXFE_PNICII }, 974978Sgd78059 { 0x1154, 0x0308, 0, 0, "Buffalo LGY-PCI-TXL", MXFE_98715AEC }, 984978Sgd78059 }; 994978Sgd78059 1004978Sgd78059 #define ETHERVLANMTU (ETHERMAX + 4) 1014978Sgd78059 1024978Sgd78059 /* 1034978Sgd78059 * Function prototypes 1044978Sgd78059 */ 1054978Sgd78059 static int mxfe_attach(dev_info_t *, ddi_attach_cmd_t); 1064978Sgd78059 static int mxfe_detach(dev_info_t *, ddi_detach_cmd_t); 1074978Sgd78059 static int mxfe_resume(dev_info_t *); 108*9199Sgdamore@opensolaris.org static int mxfe_quiesce(dev_info_t *); 1094978Sgd78059 static int mxfe_m_unicst(void *, const uint8_t *); 1104978Sgd78059 static int mxfe_m_multicst(void *, boolean_t, const uint8_t *); 1114978Sgd78059 static int mxfe_m_promisc(void *, boolean_t); 1124978Sgd78059 static mblk_t *mxfe_m_tx(void *, mblk_t *); 1134978Sgd78059 static int mxfe_m_stat(void *, uint_t, uint64_t *); 1144978Sgd78059 static int mxfe_m_start(void *); 1154978Sgd78059 static void mxfe_m_stop(void *); 1166684Sgd78059 static int mxfe_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 1178118SVasumathi.Sundaram@Sun.COM uint_t, void *, uint_t *); 1186684Sgd78059 static int mxfe_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 1196684Sgd78059 const void *); 1204978Sgd78059 static unsigned mxfe_intr(caddr_t); 1214978Sgd78059 static void mxfe_startmac(mxfe_t *); 1224978Sgd78059 static void mxfe_stopmac(mxfe_t *); 1234978Sgd78059 static void mxfe_resetrings(mxfe_t *); 1244978Sgd78059 static boolean_t mxfe_initialize(mxfe_t *); 1254978Sgd78059 static void mxfe_startall(mxfe_t *); 1264978Sgd78059 static void mxfe_stopall(mxfe_t *); 1274978Sgd78059 static void mxfe_resetall(mxfe_t *); 1284978Sgd78059 static mxfe_txbuf_t *mxfe_alloctxbuf(mxfe_t *); 1294978Sgd78059 static void mxfe_destroytxbuf(mxfe_txbuf_t *); 1304978Sgd78059 static mxfe_rxbuf_t *mxfe_allocrxbuf(mxfe_t *); 1314978Sgd78059 static void mxfe_destroyrxbuf(mxfe_rxbuf_t *); 1324978Sgd78059 static void mxfe_send_setup(mxfe_t *); 1334978Sgd78059 static boolean_t mxfe_send(mxfe_t *, mblk_t *); 1344978Sgd78059 static int mxfe_allocrxring(mxfe_t *); 1354978Sgd78059 static void mxfe_freerxring(mxfe_t *); 1364978Sgd78059 static int mxfe_alloctxring(mxfe_t *); 1374978Sgd78059 static void mxfe_freetxring(mxfe_t *); 1384978Sgd78059 static void mxfe_error(dev_info_t *, char *, ...); 1394978Sgd78059 static uint8_t mxfe_sromwidth(mxfe_t *); 1404978Sgd78059 static uint16_t mxfe_readsromword(mxfe_t *, unsigned); 1414978Sgd78059 static void mxfe_readsrom(mxfe_t *, unsigned, unsigned, void *); 1424978Sgd78059 static void mxfe_getfactaddr(mxfe_t *, uchar_t *); 1436684Sgd78059 static uint8_t mxfe_miireadbit(mxfe_t *); 1446684Sgd78059 static void mxfe_miiwritebit(mxfe_t *, uint8_t); 1454978Sgd78059 static void mxfe_miitristate(mxfe_t *); 1466684Sgd78059 static uint16_t mxfe_miiread(mxfe_t *, int, int); 1474978Sgd78059 static void mxfe_miiwrite(mxfe_t *, int, int, uint16_t); 1486684Sgd78059 static uint16_t mxfe_miireadgeneral(mxfe_t *, int, int); 1494978Sgd78059 static void mxfe_miiwritegeneral(mxfe_t *, int, int, uint16_t); 1506684Sgd78059 static uint16_t mxfe_miiread98713(mxfe_t *, int, int); 1514978Sgd78059 static void mxfe_miiwrite98713(mxfe_t *, int, int, uint16_t); 1524978Sgd78059 static void mxfe_startphy(mxfe_t *); 1534978Sgd78059 static void mxfe_stopphy(mxfe_t *); 1544978Sgd78059 static void mxfe_startphymii(mxfe_t *); 1554978Sgd78059 static void mxfe_startphynway(mxfe_t *); 1564978Sgd78059 static void mxfe_startnway(mxfe_t *); 1574978Sgd78059 static void mxfe_reportlink(mxfe_t *); 1584978Sgd78059 static void mxfe_checklink(mxfe_t *); 1594978Sgd78059 static void mxfe_checklinkmii(mxfe_t *); 1604978Sgd78059 static void mxfe_checklinknway(mxfe_t *); 1614978Sgd78059 static void mxfe_disableinterrupts(mxfe_t *); 1624978Sgd78059 static void mxfe_enableinterrupts(mxfe_t *); 1634978Sgd78059 static void mxfe_reclaim(mxfe_t *); 164*9199Sgdamore@opensolaris.org static boolean_t mxfe_receive(mxfe_t *, mblk_t **); 1654978Sgd78059 1664978Sgd78059 #ifdef DEBUG 1674978Sgd78059 static void mxfe_dprintf(mxfe_t *, const char *, int, char *, ...); 1684978Sgd78059 #endif 1694978Sgd78059 1704978Sgd78059 #define KIOIP KSTAT_INTR_PTR(mxfep->mxfe_intrstat) 1714978Sgd78059 1724978Sgd78059 static mac_callbacks_t mxfe_m_callbacks = { 1736684Sgd78059 MC_SETPROP | MC_GETPROP, 1744978Sgd78059 mxfe_m_stat, 1754978Sgd78059 mxfe_m_start, 1764978Sgd78059 mxfe_m_stop, 1774978Sgd78059 mxfe_m_promisc, 1784978Sgd78059 mxfe_m_multicst, 1794978Sgd78059 mxfe_m_unicst, 1804978Sgd78059 mxfe_m_tx, 1816684Sgd78059 NULL, /* mc_ioctl */ 1826684Sgd78059 NULL, /* mc_getcapab */ 1836684Sgd78059 NULL, /* mc_open */ 1846684Sgd78059 NULL, /* mc_close */ 1856684Sgd78059 mxfe_m_setprop, 1866684Sgd78059 mxfe_m_getprop 1874978Sgd78059 }; 1884978Sgd78059 1894978Sgd78059 /* 1904978Sgd78059 * Stream information 1914978Sgd78059 */ 1924978Sgd78059 DDI_DEFINE_STREAM_OPS(mxfe_devops, nulldev, nulldev, mxfe_attach, mxfe_detach, 193*9199Sgdamore@opensolaris.org nodev, NULL, D_MP, NULL, mxfe_quiesce); 1944978Sgd78059 1954978Sgd78059 /* 1964978Sgd78059 * Module linkage information. 1974978Sgd78059 */ 1984978Sgd78059 1994978Sgd78059 static struct modldrv mxfe_modldrv = { 2004978Sgd78059 &mod_driverops, /* drv_modops */ 2014978Sgd78059 "Macronix Fast Ethernet", /* drv_linkinfo */ 2024978Sgd78059 &mxfe_devops /* drv_dev_ops */ 2034978Sgd78059 }; 2044978Sgd78059 2054978Sgd78059 static struct modlinkage mxfe_modlinkage = { 2064978Sgd78059 MODREV_1, /* ml_rev */ 2074978Sgd78059 { &mxfe_modldrv, NULL } /* ml_linkage */ 2084978Sgd78059 }; 2094978Sgd78059 2104978Sgd78059 /* 2114978Sgd78059 * Device attributes. 2124978Sgd78059 */ 2134978Sgd78059 static ddi_device_acc_attr_t mxfe_devattr = { 2144978Sgd78059 DDI_DEVICE_ATTR_V0, 2154978Sgd78059 DDI_STRUCTURE_LE_ACC, 2164978Sgd78059 DDI_STRICTORDER_ACC 2174978Sgd78059 }; 2184978Sgd78059 2194978Sgd78059 static ddi_device_acc_attr_t mxfe_bufattr = { 2204978Sgd78059 DDI_DEVICE_ATTR_V0, 2214978Sgd78059 DDI_NEVERSWAP_ACC, 2224978Sgd78059 DDI_STRICTORDER_ACC 2234978Sgd78059 }; 2244978Sgd78059 2254978Sgd78059 static ddi_dma_attr_t mxfe_dma_attr = { 2264978Sgd78059 DMA_ATTR_V0, /* dma_attr_version */ 2274978Sgd78059 0, /* dma_attr_addr_lo */ 2284978Sgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 2294978Sgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 2304978Sgd78059 4, /* dma_attr_align */ 2314978Sgd78059 0x3F, /* dma_attr_burstsizes */ 2324978Sgd78059 1, /* dma_attr_minxfer */ 2334978Sgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 2344978Sgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 2354978Sgd78059 1, /* dma_attr_sgllen */ 2364978Sgd78059 1, /* dma_attr_granular */ 2374978Sgd78059 0 /* dma_attr_flags */ 2384978Sgd78059 }; 2394978Sgd78059 2404978Sgd78059 /* 2414978Sgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can 2424978Sgd78059 * cross a page boundary, so we use the two buffer addresses of the 2434978Sgd78059 * chip to provide a two-entry scatter-gather list. 2444978Sgd78059 */ 2454978Sgd78059 static ddi_dma_attr_t mxfe_dma_txattr = { 2464978Sgd78059 DMA_ATTR_V0, /* dma_attr_version */ 2474978Sgd78059 0, /* dma_attr_addr_lo */ 2484978Sgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */ 2494978Sgd78059 0x7FFFFFFFU, /* dma_attr_count_max */ 2504978Sgd78059 1, /* dma_attr_align */ 2514978Sgd78059 0x3F, /* dma_attr_burstsizes */ 2524978Sgd78059 1, /* dma_attr_minxfer */ 2534978Sgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */ 2544978Sgd78059 0xFFFFFFFFU, /* dma_attr_seg */ 2554978Sgd78059 2, /* dma_attr_sgllen */ 2564978Sgd78059 1, /* dma_attr_granular */ 2574978Sgd78059 0 /* dma_attr_flags */ 2584978Sgd78059 }; 2594978Sgd78059 2604978Sgd78059 /* 2614978Sgd78059 * Ethernet addresses. 2624978Sgd78059 */ 2634978Sgd78059 static uchar_t mxfe_broadcast[ETHERADDRL] = { 2644978Sgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2654978Sgd78059 }; 2664978Sgd78059 2674978Sgd78059 /* 2684978Sgd78059 * DDI entry points. 2694978Sgd78059 */ 2704978Sgd78059 int 2714978Sgd78059 _init(void) 2724978Sgd78059 { 2734978Sgd78059 int rv; 2744978Sgd78059 mac_init_ops(&mxfe_devops, "mxfe"); 2754978Sgd78059 if ((rv = mod_install(&mxfe_modlinkage)) != DDI_SUCCESS) { 2764978Sgd78059 mac_fini_ops(&mxfe_devops); 2774978Sgd78059 } 2784978Sgd78059 return (rv); 2794978Sgd78059 } 2804978Sgd78059 2814978Sgd78059 int 2824978Sgd78059 _fini(void) 2834978Sgd78059 { 2844978Sgd78059 int rv; 2854978Sgd78059 if ((rv = mod_remove(&mxfe_modlinkage)) == DDI_SUCCESS) { 2864978Sgd78059 mac_fini_ops(&mxfe_devops); 2874978Sgd78059 } 2884978Sgd78059 return (rv); 2894978Sgd78059 } 2904978Sgd78059 2914978Sgd78059 int 2924978Sgd78059 _info(struct modinfo *modinfop) 2934978Sgd78059 { 2944978Sgd78059 return (mod_info(&mxfe_modlinkage, modinfop)); 2954978Sgd78059 } 2964978Sgd78059 2974978Sgd78059 int 2984978Sgd78059 mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2994978Sgd78059 { 3004978Sgd78059 mxfe_t *mxfep; 3014978Sgd78059 mac_register_t *macp; 3024978Sgd78059 int inst = ddi_get_instance(dip); 3034978Sgd78059 ddi_acc_handle_t pci; 3044978Sgd78059 uint16_t venid; 3054978Sgd78059 uint16_t devid; 3064978Sgd78059 uint16_t revid; 3074978Sgd78059 uint16_t svid; 3084978Sgd78059 uint16_t ssid; 3094978Sgd78059 uint16_t cachesize; 3104978Sgd78059 mxfe_card_t *cardp; 3114978Sgd78059 int i; 3124978Sgd78059 3134978Sgd78059 switch (cmd) { 3144978Sgd78059 case DDI_RESUME: 3154978Sgd78059 return (mxfe_resume(dip)); 3164978Sgd78059 3174978Sgd78059 case DDI_ATTACH: 3184978Sgd78059 break; 3194978Sgd78059 3204978Sgd78059 default: 3214978Sgd78059 return (DDI_FAILURE); 3224978Sgd78059 } 3234978Sgd78059 3244978Sgd78059 /* this card is a bus master, reject any slave-only slot */ 3254978Sgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) { 3264978Sgd78059 mxfe_error(dip, "slot does not support PCI bus-master"); 3274978Sgd78059 return (DDI_FAILURE); 3284978Sgd78059 } 3294978Sgd78059 /* PCI devices shouldn't generate hilevel interrupts */ 3304978Sgd78059 if (ddi_intr_hilevel(dip, 0) != 0) { 3314978Sgd78059 mxfe_error(dip, "hilevel interrupts not supported"); 3324978Sgd78059 return (DDI_FAILURE); 3334978Sgd78059 } 3344978Sgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 3354978Sgd78059 mxfe_error(dip, "unable to setup PCI config handle"); 3364978Sgd78059 return (DDI_FAILURE); 3374978Sgd78059 } 3384978Sgd78059 3394978Sgd78059 venid = pci_config_get16(pci, PCI_VID); 3404978Sgd78059 devid = pci_config_get16(pci, PCI_DID); 3414978Sgd78059 revid = pci_config_get16(pci, PCI_RID); 3424978Sgd78059 svid = pci_config_get16(pci, PCI_SVID); 3434978Sgd78059 ssid = pci_config_get16(pci, PCI_SSID); 3444978Sgd78059 3454978Sgd78059 /* 3464978Sgd78059 * the last entry in the card table matches every possible 3474978Sgd78059 * card, so the for-loop always terminates properly. 3484978Sgd78059 */ 3494978Sgd78059 cardp = NULL; 3504978Sgd78059 for (i = 0; i < (sizeof (mxfe_cards) / sizeof (mxfe_card_t)); i++) { 3514978Sgd78059 if ((venid == mxfe_cards[i].card_venid) && 3524978Sgd78059 (devid == mxfe_cards[i].card_devid) && 3534978Sgd78059 ((revid & mxfe_cards[i].card_revmask) == 3544978Sgd78059 mxfe_cards[i].card_revid)) { 3554978Sgd78059 cardp = &mxfe_cards[i]; 3564978Sgd78059 } 3574978Sgd78059 if ((svid == mxfe_cards[i].card_venid) && 3584978Sgd78059 (ssid == mxfe_cards[i].card_devid) && 3594978Sgd78059 ((revid & mxfe_cards[i].card_revmask) == 3604978Sgd78059 mxfe_cards[i].card_revid)) { 3614978Sgd78059 cardp = &mxfe_cards[i]; 3624978Sgd78059 break; 3634978Sgd78059 } 3644978Sgd78059 } 3654978Sgd78059 3664978Sgd78059 if (cardp == NULL) { 3674978Sgd78059 pci_config_teardown(&pci); 3684978Sgd78059 mxfe_error(dip, "Unable to identify PCI card"); 3694978Sgd78059 return (DDI_FAILURE); 3704978Sgd78059 } 3714978Sgd78059 3724978Sgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model", 3734978Sgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) { 3744978Sgd78059 pci_config_teardown(&pci); 3754978Sgd78059 mxfe_error(dip, "Unable to create model property"); 3764978Sgd78059 return (DDI_FAILURE); 3774978Sgd78059 } 3784978Sgd78059 3794978Sgd78059 /* 3804978Sgd78059 * Grab the PCI cachesize -- we use this to program the 3814978Sgd78059 * cache-optimization bus access bits. 3824978Sgd78059 */ 3834978Sgd78059 cachesize = pci_config_get8(pci, PCI_CLS); 3844978Sgd78059 3854978Sgd78059 /* this cannot fail */ 3864978Sgd78059 mxfep = kmem_zalloc(sizeof (mxfe_t), KM_SLEEP); 3874978Sgd78059 ddi_set_driver_private(dip, mxfep); 3884978Sgd78059 3894978Sgd78059 /* get the interrupt block cookie */ 3904978Sgd78059 if (ddi_get_iblock_cookie(dip, 0, &mxfep->mxfe_icookie) 3914978Sgd78059 != DDI_SUCCESS) { 3924978Sgd78059 mxfe_error(dip, "ddi_get_iblock_cookie failed"); 3934978Sgd78059 pci_config_teardown(&pci); 3944978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 3954978Sgd78059 return (DDI_FAILURE); 3964978Sgd78059 } 3974978Sgd78059 3984978Sgd78059 mxfep->mxfe_dip = dip; 3994978Sgd78059 mxfep->mxfe_cardp = cardp; 4004978Sgd78059 mxfep->mxfe_phyaddr = -1; 4014978Sgd78059 mxfep->mxfe_cachesize = cachesize; 4024978Sgd78059 4034978Sgd78059 /* default properties */ 4044978Sgd78059 mxfep->mxfe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4054978Sgd78059 "adv_autoneg_cap", 1); 4064978Sgd78059 mxfep->mxfe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4074978Sgd78059 "adv_100T4_cap", 1); 4084978Sgd78059 mxfep->mxfe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4094978Sgd78059 "adv_100fdx_cap", 1); 4104978Sgd78059 mxfep->mxfe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4114978Sgd78059 "adv_100hdx_cap", 1); 4124978Sgd78059 mxfep->mxfe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4134978Sgd78059 "adv_10fdx_cap", 1); 4144978Sgd78059 mxfep->mxfe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4154978Sgd78059 "adv_10hdx_cap", 1); 4164978Sgd78059 4174978Sgd78059 DBG(DPCI, "PCI vendor id = %x", venid); 4184978Sgd78059 DBG(DPCI, "PCI device id = %x", devid); 4194978Sgd78059 DBG(DPCI, "PCI revision id = %x", revid); 4204978Sgd78059 DBG(DPCI, "PCI cachesize = %d", cachesize); 4214978Sgd78059 DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD)); 4224978Sgd78059 DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT)); 4234978Sgd78059 4244978Sgd78059 mutex_init(&mxfep->mxfe_xmtlock, NULL, MUTEX_DRIVER, 4254978Sgd78059 mxfep->mxfe_icookie); 4264978Sgd78059 mutex_init(&mxfep->mxfe_intrlock, NULL, MUTEX_DRIVER, 4274978Sgd78059 mxfep->mxfe_icookie); 4284978Sgd78059 4294978Sgd78059 /* 4304978Sgd78059 * Enable bus master, IO space, and memory space accesses. 4314978Sgd78059 */ 4324978Sgd78059 pci_config_put16(pci, PCI_CMD, 4334978Sgd78059 pci_config_get16(pci, PCI_CMD) | 4344978Sgd78059 PCI_CMD_BME | PCI_CMD_MAE | PCI_CMD_MWIE); 4354978Sgd78059 4364978Sgd78059 /* we're done with this now, drop it */ 4374978Sgd78059 pci_config_teardown(&pci); 4384978Sgd78059 4394978Sgd78059 /* 4404978Sgd78059 * Initialize interrupt kstat. This should not normally fail, since 4414978Sgd78059 * we don't use a persistent stat. We do it this way to avoid having 4424978Sgd78059 * to test for it at run time on the hot path. 4434978Sgd78059 */ 4444978Sgd78059 mxfep->mxfe_intrstat = kstat_create("mxfe", inst, "intr", "controller", 4454978Sgd78059 KSTAT_TYPE_INTR, 1, 0); 4464978Sgd78059 if (mxfep->mxfe_intrstat == NULL) { 4474978Sgd78059 mxfe_error(dip, "kstat_create failed"); 4484978Sgd78059 goto failed; 4494978Sgd78059 } 4504978Sgd78059 kstat_install(mxfep->mxfe_intrstat); 4514978Sgd78059 4524978Sgd78059 /* 4534978Sgd78059 * Map in the device registers. 4544978Sgd78059 */ 4554978Sgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mxfep->mxfe_regs, 4564978Sgd78059 0, 0, &mxfe_devattr, &mxfep->mxfe_regshandle)) { 4574978Sgd78059 mxfe_error(dip, "ddi_regs_map_setup failed"); 4584978Sgd78059 goto failed; 4594978Sgd78059 } 4604978Sgd78059 4614978Sgd78059 /* 4624978Sgd78059 * Allocate DMA resources (descriptor rings and buffers). 4634978Sgd78059 */ 4644978Sgd78059 if ((mxfe_allocrxring(mxfep) != DDI_SUCCESS) || 4654978Sgd78059 (mxfe_alloctxring(mxfep) != DDI_SUCCESS)) { 4664978Sgd78059 mxfe_error(dip, "unable to allocate DMA resources"); 4674978Sgd78059 goto failed; 4684978Sgd78059 } 4694978Sgd78059 4704978Sgd78059 /* Initialize the chip. */ 4714978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 4724978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 4734978Sgd78059 if (!mxfe_initialize(mxfep)) { 4744978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 4754978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 4764978Sgd78059 goto failed; 4774978Sgd78059 } 4784978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 4794978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 4804978Sgd78059 4814978Sgd78059 /* Determine the number of address bits to our EEPROM. */ 4824978Sgd78059 mxfep->mxfe_sromwidth = mxfe_sromwidth(mxfep); 4834978Sgd78059 4844978Sgd78059 /* 4854978Sgd78059 * Get the factory ethernet address. This becomes the current 4864978Sgd78059 * ethernet address (it can be overridden later via ifconfig). 4874978Sgd78059 */ 4884978Sgd78059 mxfe_getfactaddr(mxfep, mxfep->mxfe_curraddr); 4894978Sgd78059 mxfep->mxfe_promisc = B_FALSE; 4904978Sgd78059 4914978Sgd78059 /* 4924978Sgd78059 * Establish interrupt handler. 4934978Sgd78059 */ 4944978Sgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, mxfe_intr, (caddr_t)mxfep) != 4954978Sgd78059 DDI_SUCCESS) { 4964978Sgd78059 mxfe_error(dip, "unable to add interrupt"); 4974978Sgd78059 goto failed; 4984978Sgd78059 } 4994978Sgd78059 5004978Sgd78059 /* TODO: do the power management stuff */ 5014978Sgd78059 5024978Sgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 5034978Sgd78059 mxfe_error(dip, "mac_alloc failed"); 5044978Sgd78059 goto failed; 5054978Sgd78059 } 5064978Sgd78059 5074978Sgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 5084978Sgd78059 macp->m_driver = mxfep; 5094978Sgd78059 macp->m_dip = dip; 5104978Sgd78059 macp->m_src_addr = mxfep->mxfe_curraddr; 5114978Sgd78059 macp->m_callbacks = &mxfe_m_callbacks; 5124978Sgd78059 macp->m_min_sdu = 0; 5134978Sgd78059 macp->m_max_sdu = ETHERMTU; 5145895Syz147064 macp->m_margin = VLAN_TAGSZ; 5154978Sgd78059 5164978Sgd78059 if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) { 5174978Sgd78059 mac_free(macp); 5184978Sgd78059 return (DDI_SUCCESS); 5194978Sgd78059 } 5204978Sgd78059 5214978Sgd78059 /* failed to register with MAC */ 5224978Sgd78059 mac_free(macp); 5234978Sgd78059 failed: 5244978Sgd78059 if (mxfep->mxfe_icookie != NULL) { 5254978Sgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie); 5264978Sgd78059 } 5274978Sgd78059 if (mxfep->mxfe_intrstat) { 5284978Sgd78059 kstat_delete(mxfep->mxfe_intrstat); 5294978Sgd78059 } 5304978Sgd78059 mutex_destroy(&mxfep->mxfe_intrlock); 5314978Sgd78059 mutex_destroy(&mxfep->mxfe_xmtlock); 5324978Sgd78059 5334978Sgd78059 mxfe_freerxring(mxfep); 5344978Sgd78059 mxfe_freetxring(mxfep); 5354978Sgd78059 5364978Sgd78059 if (mxfep->mxfe_regshandle != NULL) { 5374978Sgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle); 5384978Sgd78059 } 5394978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 5404978Sgd78059 return (DDI_FAILURE); 5414978Sgd78059 } 5424978Sgd78059 5434978Sgd78059 int 5444978Sgd78059 mxfe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5454978Sgd78059 { 5464978Sgd78059 mxfe_t *mxfep; 5474978Sgd78059 5484978Sgd78059 mxfep = ddi_get_driver_private(dip); 5494978Sgd78059 if (mxfep == NULL) { 5504978Sgd78059 mxfe_error(dip, "no soft state in detach!"); 5514978Sgd78059 return (DDI_FAILURE); 5524978Sgd78059 } 5534978Sgd78059 5544978Sgd78059 switch (cmd) { 5554978Sgd78059 case DDI_DETACH: 5564978Sgd78059 5574978Sgd78059 if (mac_unregister(mxfep->mxfe_mh) != 0) { 5584978Sgd78059 return (DDI_FAILURE); 5594978Sgd78059 } 5604978Sgd78059 5614978Sgd78059 /* make sure hardware is quiesced */ 5624978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 5634978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 5644978Sgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING; 5654978Sgd78059 mxfe_stopall(mxfep); 5664978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 5674978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 5684978Sgd78059 5694978Sgd78059 /* clean up and shut down device */ 5704978Sgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie); 5714978Sgd78059 5724978Sgd78059 /* clean up kstats */ 5734978Sgd78059 kstat_delete(mxfep->mxfe_intrstat); 5744978Sgd78059 5754978Sgd78059 ddi_prop_remove_all(dip); 5764978Sgd78059 5774978Sgd78059 /* free up any left over buffers or DMA resources */ 5784978Sgd78059 mxfe_freerxring(mxfep); 5794978Sgd78059 mxfe_freetxring(mxfep); 5804978Sgd78059 5814978Sgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle); 5824978Sgd78059 mutex_destroy(&mxfep->mxfe_intrlock); 5834978Sgd78059 mutex_destroy(&mxfep->mxfe_xmtlock); 5844978Sgd78059 5854978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t)); 5864978Sgd78059 return (DDI_SUCCESS); 5874978Sgd78059 5884978Sgd78059 case DDI_SUSPEND: 5894978Sgd78059 /* quiesce the hardware */ 5904978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 5914978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 5924978Sgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED; 5934978Sgd78059 mxfe_stopall(mxfep); 5944978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 5954978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 5964978Sgd78059 return (DDI_SUCCESS); 5974978Sgd78059 default: 5984978Sgd78059 return (DDI_FAILURE); 5994978Sgd78059 } 6004978Sgd78059 } 6014978Sgd78059 6024978Sgd78059 int 6034978Sgd78059 mxfe_resume(dev_info_t *dip) 6044978Sgd78059 { 6054978Sgd78059 mxfe_t *mxfep; 6064978Sgd78059 6074978Sgd78059 if ((mxfep = ddi_get_driver_private(dip)) == NULL) { 6084978Sgd78059 return (DDI_FAILURE); 6094978Sgd78059 } 6104978Sgd78059 6114978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 6124978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 6134978Sgd78059 6144978Sgd78059 mxfep->mxfe_flags &= ~MXFE_SUSPENDED; 6154978Sgd78059 6164978Sgd78059 /* re-initialize chip */ 6174978Sgd78059 if (!mxfe_initialize(mxfep)) { 6184978Sgd78059 mxfe_error(mxfep->mxfe_dip, "unable to resume chip!"); 6194978Sgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED; 6204978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 6214978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 6224978Sgd78059 return (DDI_SUCCESS); 6234978Sgd78059 } 6244978Sgd78059 6254978Sgd78059 /* start the chip */ 6264978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) { 6274978Sgd78059 mxfe_startall(mxfep); 6284978Sgd78059 } 6294978Sgd78059 6304978Sgd78059 /* drop locks */ 6314978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 6324978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 6334978Sgd78059 6344978Sgd78059 return (DDI_SUCCESS); 6354978Sgd78059 } 6364978Sgd78059 637*9199Sgdamore@opensolaris.org int 638*9199Sgdamore@opensolaris.org mxfe_quiesce(dev_info_t *dip) 639*9199Sgdamore@opensolaris.org { 640*9199Sgdamore@opensolaris.org mxfe_t *mxfep; 641*9199Sgdamore@opensolaris.org 642*9199Sgdamore@opensolaris.org if ((mxfep = ddi_get_driver_private(dip)) == NULL) { 643*9199Sgdamore@opensolaris.org return (DDI_FAILURE); 644*9199Sgdamore@opensolaris.org } 645*9199Sgdamore@opensolaris.org 646*9199Sgdamore@opensolaris.org /* just do a hard reset of everything */ 647*9199Sgdamore@opensolaris.org SETBIT(mxfep, CSR_PAR, PAR_RESET); 648*9199Sgdamore@opensolaris.org 649*9199Sgdamore@opensolaris.org return (DDI_SUCCESS); 650*9199Sgdamore@opensolaris.org } 651*9199Sgdamore@opensolaris.org 6524978Sgd78059 /*ARGSUSED*/ 6534978Sgd78059 int 6544978Sgd78059 mxfe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 6554978Sgd78059 { 6564978Sgd78059 /* we already receive all multicast frames */ 6574978Sgd78059 return (0); 6584978Sgd78059 } 6594978Sgd78059 6604978Sgd78059 int 6614978Sgd78059 mxfe_m_promisc(void *arg, boolean_t on) 6624978Sgd78059 { 6634978Sgd78059 mxfe_t *mxfep = arg; 6644978Sgd78059 6654978Sgd78059 /* exclusive access to the card while we reprogram it */ 6664978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 6674978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 6684978Sgd78059 /* save current promiscuous mode state for replay in resume */ 6694978Sgd78059 mxfep->mxfe_promisc = on; 6704978Sgd78059 6714978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == 6724978Sgd78059 MXFE_RUNNING) { 6734978Sgd78059 if (on) 6744978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 6754978Sgd78059 else 6764978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 6774978Sgd78059 } 6784978Sgd78059 6794978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 6804978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 6814978Sgd78059 6824978Sgd78059 return (0); 6834978Sgd78059 } 6844978Sgd78059 6854978Sgd78059 int 6864978Sgd78059 mxfe_m_unicst(void *arg, const uint8_t *macaddr) 6874978Sgd78059 { 6884978Sgd78059 mxfe_t *mxfep = arg; 6894978Sgd78059 6904978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 6914978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 6924978Sgd78059 bcopy(macaddr, mxfep->mxfe_curraddr, ETHERADDRL); 6934978Sgd78059 6944978Sgd78059 mxfe_resetall(mxfep); 6954978Sgd78059 6964978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 6974978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 6984978Sgd78059 6994978Sgd78059 return (0); 7004978Sgd78059 } 7014978Sgd78059 7024978Sgd78059 mblk_t * 7034978Sgd78059 mxfe_m_tx(void *arg, mblk_t *mp) 7044978Sgd78059 { 7054978Sgd78059 mxfe_t *mxfep = arg; 7064978Sgd78059 mblk_t *nmp; 7074978Sgd78059 7084978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 7094978Sgd78059 7104978Sgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) { 7114978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 7124978Sgd78059 return (mp); 7134978Sgd78059 } 7144978Sgd78059 7154978Sgd78059 while (mp != NULL) { 7164978Sgd78059 nmp = mp->b_next; 7174978Sgd78059 mp->b_next = NULL; 7184978Sgd78059 7194978Sgd78059 if (!mxfe_send(mxfep, mp)) { 7204978Sgd78059 mp->b_next = nmp; 7214978Sgd78059 break; 7224978Sgd78059 } 7234978Sgd78059 mp = nmp; 7244978Sgd78059 } 7254978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 7264978Sgd78059 7274978Sgd78059 return (mp); 7284978Sgd78059 } 7294978Sgd78059 7304978Sgd78059 /* 7314978Sgd78059 * Hardware management. 7324978Sgd78059 */ 7334978Sgd78059 boolean_t 7344978Sgd78059 mxfe_initialize(mxfe_t *mxfep) 7354978Sgd78059 { 7364978Sgd78059 int i; 7374978Sgd78059 unsigned val; 7384978Sgd78059 uint32_t par, nar; 7394978Sgd78059 7404978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 7414978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 7424978Sgd78059 7434978Sgd78059 DBG(DCHATTY, "resetting!"); 7444978Sgd78059 SETBIT(mxfep, CSR_PAR, PAR_RESET); 7454978Sgd78059 for (i = 1; i < 10; i++) { 7464978Sgd78059 drv_usecwait(5); 7474978Sgd78059 val = GETCSR(mxfep, CSR_PAR); 7484978Sgd78059 if (!(val & PAR_RESET)) { 7494978Sgd78059 break; 7504978Sgd78059 } 7514978Sgd78059 } 7524978Sgd78059 if (i == 10) { 7534978Sgd78059 mxfe_error(mxfep->mxfe_dip, "timed out waiting for reset!"); 7544978Sgd78059 return (B_FALSE); 7554978Sgd78059 } 7564978Sgd78059 7574978Sgd78059 /* initialize busctl register */ 7584978Sgd78059 par = PAR_BAR | PAR_MRME | PAR_MRLE | PAR_MWIE; 7594978Sgd78059 7604978Sgd78059 /* set the cache alignment if its supported */ 7614978Sgd78059 switch (mxfep->mxfe_cachesize) { 7624978Sgd78059 case 8: 7634978Sgd78059 par |= PAR_CALIGN_8; 7644978Sgd78059 break; 7654978Sgd78059 case 16: 7664978Sgd78059 par |= PAR_CALIGN_16; 7674978Sgd78059 break; 7684978Sgd78059 case 32: 7694978Sgd78059 par |= PAR_CALIGN_32; 7704978Sgd78059 break; 7714978Sgd78059 default: 7724978Sgd78059 par &= ~(PAR_MWIE | PAR_MRME | PAR_MRLE); 7734978Sgd78059 } 7744978Sgd78059 7754978Sgd78059 /* leave the burst length at zero, indicating infinite burst */ 7764978Sgd78059 PUTCSR(mxfep, CSR_PAR, par); 7774978Sgd78059 7784978Sgd78059 mxfe_resetrings(mxfep); 7794978Sgd78059 7804978Sgd78059 /* clear the lost packet counter (cleared on read) */ 7814978Sgd78059 (void) GETCSR(mxfep, CSR_LPC); 7824978Sgd78059 7834978Sgd78059 /* a few other NAR bits */ 7844978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 7854978Sgd78059 nar &= ~NAR_RX_HO; /* disable hash only filtering */ 7864978Sgd78059 nar |= NAR_RX_HP; /* hash perfect forwarding */ 7874978Sgd78059 nar |= NAR_RX_MULTI; /* receive all multicast */ 7884978Sgd78059 nar |= NAR_SF; /* store-and-forward */ 7894978Sgd78059 7904978Sgd78059 if (mxfep->mxfe_promisc) { 7914978Sgd78059 nar |= NAR_RX_PROMISC; 7924978Sgd78059 } else { 7934978Sgd78059 nar &= ~NAR_RX_PROMISC; 7944978Sgd78059 } 7954978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 7964978Sgd78059 7974978Sgd78059 mxfe_send_setup(mxfep); 7984978Sgd78059 7994978Sgd78059 return (B_TRUE); 8004978Sgd78059 } 8014978Sgd78059 8024978Sgd78059 /* 8034978Sgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation. 8044978Sgd78059 */ 8054978Sgd78059 8064978Sgd78059 uint8_t 8074978Sgd78059 mxfe_sromwidth(mxfe_t *mxfep) 8084978Sgd78059 { 8094978Sgd78059 int i; 8104978Sgd78059 int eeread; 8114978Sgd78059 uint8_t addrlen = 8; 8124978Sgd78059 8134978Sgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 8144978Sgd78059 8154978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 8164978Sgd78059 drv_usecwait(1); 8174978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8184978Sgd78059 8194978Sgd78059 /* command bits first */ 8204978Sgd78059 for (i = 4; i != 0; i >>= 1) { 8214978Sgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0; 8224978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val); 8234978Sgd78059 drv_usecwait(1); 8244978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 8254978Sgd78059 drv_usecwait(1); 8264978Sgd78059 } 8274978Sgd78059 8284978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8294978Sgd78059 8304978Sgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) { 8314978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK); 8324978Sgd78059 drv_usecwait(1); 8334978Sgd78059 if (!(GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT)) { 8344978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8354978Sgd78059 drv_usecwait(1); 8364978Sgd78059 break; 8374978Sgd78059 } 8384978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8394978Sgd78059 drv_usecwait(1); 8404978Sgd78059 } 8414978Sgd78059 8424978Sgd78059 /* turn off accesses to the EEPROM */ 8434978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 8444978Sgd78059 8454978Sgd78059 DBG(DSROM, "detected srom width = %d bits", addrlen); 8464978Sgd78059 8474978Sgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen); 8484978Sgd78059 } 8494978Sgd78059 8504978Sgd78059 /* 8514978Sgd78059 * The words in EEPROM are stored in little endian order. We 8524978Sgd78059 * shift bits out in big endian order, though. This requires 8534978Sgd78059 * a byte swap on some platforms. 8544978Sgd78059 */ 8554978Sgd78059 uint16_t 8564978Sgd78059 mxfe_readsromword(mxfe_t *mxfep, unsigned romaddr) 8574978Sgd78059 { 8584978Sgd78059 int i; 8594978Sgd78059 uint16_t word = 0; 8604978Sgd78059 uint16_t retval; 8614978Sgd78059 int eeread; 8624978Sgd78059 uint8_t addrlen; 8634978Sgd78059 int readcmd; 8644978Sgd78059 uchar_t *ptr; 8654978Sgd78059 8664978Sgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP; 8674978Sgd78059 addrlen = mxfep->mxfe_sromwidth; 8684978Sgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr; 8694978Sgd78059 8704978Sgd78059 if (romaddr >= (1 << addrlen)) { 8714978Sgd78059 /* too big to fit! */ 8724978Sgd78059 return (0); 8734978Sgd78059 } 8744978Sgd78059 8754978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP); 8764978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8774978Sgd78059 8784978Sgd78059 /* command and address bits */ 8794978Sgd78059 for (i = 4 + addrlen; i >= 0; i--) { 8804978Sgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0; 8814978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val); 8824978Sgd78059 drv_usecwait(1); 8834978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK); 8844978Sgd78059 drv_usecwait(1); 8854978Sgd78059 } 8864978Sgd78059 8874978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8884978Sgd78059 8894978Sgd78059 for (i = 0; i < 16; i++) { 8904978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK); 8914978Sgd78059 drv_usecwait(1); 8924978Sgd78059 word <<= 1; 8934978Sgd78059 if (GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT) { 8944978Sgd78059 word |= 1; 8954978Sgd78059 } 8964978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread); 8974978Sgd78059 drv_usecwait(1); 8984978Sgd78059 } 8994978Sgd78059 9004978Sgd78059 /* turn off accesses to the EEPROM */ 9014978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP); 9024978Sgd78059 9034978Sgd78059 /* 9044978Sgd78059 * Fix up the endianness thing. Note that the values 9054978Sgd78059 * are stored in little endian format on the SROM. 9064978Sgd78059 */ 9074978Sgd78059 DBG(DSROM, "got value %d from SROM (before swap)", word); 9084978Sgd78059 ptr = (uchar_t *)&word; 9094978Sgd78059 retval = (ptr[1] << 8) | ptr[0]; 9104978Sgd78059 return (retval); 9114978Sgd78059 } 9124978Sgd78059 9134978Sgd78059 void 9144978Sgd78059 mxfe_readsrom(mxfe_t *mxfep, unsigned romaddr, unsigned len, void *dest) 9154978Sgd78059 { 9164978Sgd78059 char *ptr = dest; 9174978Sgd78059 int i; 9184978Sgd78059 uint16_t word; 9194978Sgd78059 9204978Sgd78059 for (i = 0; i < len; i++) { 9214978Sgd78059 word = mxfe_readsromword(mxfep, romaddr + i); 9224978Sgd78059 bcopy(&word, ptr, 2); 9234978Sgd78059 ptr += 2; 9244978Sgd78059 DBG(DSROM, "word at %d is 0x%x", romaddr + i, word); 9254978Sgd78059 } 9264978Sgd78059 } 9274978Sgd78059 9284978Sgd78059 void 9294978Sgd78059 mxfe_getfactaddr(mxfe_t *mxfep, uchar_t *eaddr) 9304978Sgd78059 { 9314978Sgd78059 uint16_t word; 9324978Sgd78059 uchar_t *ptr; 9334978Sgd78059 9344978Sgd78059 /* first read to get the location of mac address in srom */ 9354978Sgd78059 word = mxfe_readsromword(mxfep, SROM_ENADDR / 2); 9364978Sgd78059 ptr = (uchar_t *)&word; 9374978Sgd78059 word = (ptr[1] << 8) | ptr[0]; 9384978Sgd78059 9394978Sgd78059 /* then read the actual mac address */ 9404978Sgd78059 mxfe_readsrom(mxfep, word / 2, ETHERADDRL / 2, eaddr); 9414978Sgd78059 DBG(DMACID, 9424978Sgd78059 "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x", 9434978Sgd78059 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 9444978Sgd78059 } 9454978Sgd78059 9464978Sgd78059 void 9474978Sgd78059 mxfe_startphy(mxfe_t *mxfep) 9484978Sgd78059 { 9494978Sgd78059 switch (MXFE_MODEL(mxfep)) { 9504978Sgd78059 case MXFE_98713A: 9514978Sgd78059 mxfe_startphymii(mxfep); 9524978Sgd78059 break; 9534978Sgd78059 default: 9544978Sgd78059 mxfe_startphynway(mxfep); 9554978Sgd78059 break; 9564978Sgd78059 } 9574978Sgd78059 } 9584978Sgd78059 9594978Sgd78059 void 9604978Sgd78059 mxfe_stopphy(mxfe_t *mxfep) 9614978Sgd78059 { 9624978Sgd78059 uint32_t nar; 9634978Sgd78059 int i; 9644978Sgd78059 9654978Sgd78059 /* stop the phy timer */ 9664978Sgd78059 PUTCSR(mxfep, CSR_TIMER, 0); 9674978Sgd78059 9684978Sgd78059 switch (MXFE_MODEL(mxfep)) { 9694978Sgd78059 case MXFE_98713A: 9704978Sgd78059 for (i = 0; i < 32; i++) { 9714978Sgd78059 mxfe_miiwrite(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL, 9724978Sgd78059 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE); 9734978Sgd78059 } 9744978Sgd78059 break; 9754978Sgd78059 default: 9764978Sgd78059 DBG(DPHY, "resetting SIA"); 9774978Sgd78059 PUTCSR(mxfep, CSR_SIA, SIA_RESET); 9784978Sgd78059 drv_usecwait(500); 9794978Sgd78059 CLRBIT(mxfep, CSR_TCTL, TCTL_PWR | TCTL_ANE); 9804978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 9814978Sgd78059 nar &= ~(NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX); 9824978Sgd78059 nar |= NAR_SPEED; 9834978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 9844978Sgd78059 break; 9854978Sgd78059 } 9864978Sgd78059 9874978Sgd78059 /* 9884978Sgd78059 * mark the link state unknown 9894978Sgd78059 */ 9904978Sgd78059 if (!mxfep->mxfe_resetting) { 9914978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UNKNOWN; 9924978Sgd78059 mxfep->mxfe_ifspeed = 0; 9934978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 9944978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 9954978Sgd78059 mxfe_reportlink(mxfep); 9964978Sgd78059 } 9974978Sgd78059 } 9984978Sgd78059 9994978Sgd78059 /* 10004978Sgd78059 * NWay support. 10014978Sgd78059 */ 10024978Sgd78059 void 10034978Sgd78059 mxfe_startnway(mxfe_t *mxfep) 10044978Sgd78059 { 10054978Sgd78059 unsigned nar; 10064978Sgd78059 unsigned tctl; 10074978Sgd78059 unsigned restart; 10084978Sgd78059 10094978Sgd78059 /* this should not happen in a healthy system */ 10106684Sgd78059 if (mxfep->mxfe_nwaystate != MXFE_NOLINK) { 10114978Sgd78059 DBG(DWARN, "link start called out of state (%x)", 10126684Sgd78059 mxfep->mxfe_nwaystate); 10134978Sgd78059 return; 10144978Sgd78059 } 10154978Sgd78059 10164978Sgd78059 if (mxfep->mxfe_adv_aneg == 0) { 10174978Sgd78059 /* not done for forced mode */ 10184978Sgd78059 return; 10194978Sgd78059 } 10204978Sgd78059 10214978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 10224978Sgd78059 restart = nar & (NAR_TX_ENABLE | NAR_RX_ENABLE); 10234978Sgd78059 nar &= ~restart; 10244978Sgd78059 10254978Sgd78059 if (restart != 0) 10264978Sgd78059 mxfe_stopmac(mxfep); 10274978Sgd78059 10284978Sgd78059 nar |= NAR_SCR | NAR_PCS | NAR_HBD; 10294978Sgd78059 nar &= ~(NAR_FDX); 10304978Sgd78059 10314978Sgd78059 tctl = GETCSR(mxfep, CSR_TCTL); 10324978Sgd78059 tctl &= ~(TCTL_100FDX | TCTL_100HDX | TCTL_HDX); 10334978Sgd78059 10344978Sgd78059 if (mxfep->mxfe_adv_100fdx) { 10354978Sgd78059 tctl |= TCTL_100FDX; 10364978Sgd78059 } 10374978Sgd78059 if (mxfep->mxfe_adv_100hdx) { 10384978Sgd78059 tctl |= TCTL_100HDX; 10394978Sgd78059 } 10404978Sgd78059 if (mxfep->mxfe_adv_10fdx) { 10414978Sgd78059 nar |= NAR_FDX; 10424978Sgd78059 } 10434978Sgd78059 if (mxfep->mxfe_adv_10hdx) { 10444978Sgd78059 tctl |= TCTL_HDX; 10454978Sgd78059 } 10464978Sgd78059 tctl |= TCTL_PWR | TCTL_ANE | TCTL_LTE | TCTL_RSQ; 10474978Sgd78059 10484978Sgd78059 /* possibly we should add in support for PAUSE frames */ 10494978Sgd78059 DBG(DPHY, "writing nar = 0x%x", nar); 10504978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 10514978Sgd78059 10524978Sgd78059 DBG(DPHY, "writing tctl = 0x%x", tctl); 10534978Sgd78059 PUTCSR(mxfep, CSR_TCTL, tctl); 10544978Sgd78059 10554978Sgd78059 /* restart autonegotation */ 10564978Sgd78059 DBG(DPHY, "writing tstat = 0x%x", TSTAT_ANS_START); 10574978Sgd78059 PUTCSR(mxfep, CSR_TSTAT, TSTAT_ANS_START); 10584978Sgd78059 10594978Sgd78059 /* restart tx/rx processes... */ 10604978Sgd78059 if (restart != 0) 10614978Sgd78059 mxfe_startmac(mxfep); 10624978Sgd78059 10634978Sgd78059 /* Macronix initializations from Bolo Tsai */ 10644978Sgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000); 10654978Sgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000); 10664978Sgd78059 10676684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NWAYCHECK; 10684978Sgd78059 } 10694978Sgd78059 10704978Sgd78059 void 10714978Sgd78059 mxfe_checklinknway(mxfe_t *mxfep) 10724978Sgd78059 { 10736684Sgd78059 unsigned tstat; 10746684Sgd78059 uint16_t lpar; 10756684Sgd78059 10766684Sgd78059 DBG(DPHY, "NWay check, state %x", mxfep->mxfe_nwaystate); 10774978Sgd78059 tstat = GETCSR(mxfep, CSR_TSTAT); 10784978Sgd78059 lpar = TSTAT_LPAR(tstat); 10794978Sgd78059 10804978Sgd78059 mxfep->mxfe_anlpar = lpar; 10814978Sgd78059 if (tstat & TSTAT_LPN) { 10824978Sgd78059 mxfep->mxfe_aner |= MII_AN_EXP_LPCANAN; 10834978Sgd78059 } else { 10844978Sgd78059 mxfep->mxfe_aner &= ~(MII_AN_EXP_LPCANAN); 10854978Sgd78059 } 10864978Sgd78059 10874978Sgd78059 DBG(DPHY, "tstat(CSR12) = 0x%x", tstat); 10884978Sgd78059 DBG(DPHY, "ANEG state = 0x%x", (tstat & TSTAT_ANS) >> 12); 10894978Sgd78059 10904978Sgd78059 if ((tstat & TSTAT_ANS) != TSTAT_ANS_OK) { 10914978Sgd78059 /* autoneg did not complete */ 10924978Sgd78059 mxfep->mxfe_bmsr &= ~MII_STATUS_ANDONE; 10934978Sgd78059 } else { 10944978Sgd78059 mxfep->mxfe_bmsr |= ~MII_STATUS_ANDONE; 10954978Sgd78059 } 10964978Sgd78059 10974978Sgd78059 if ((tstat & TSTAT_100F) && (tstat & TSTAT_10F)) { 10984978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 10994978Sgd78059 mxfep->mxfe_ifspeed = 0; 11004978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 11016684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK; 11024978Sgd78059 mxfe_reportlink(mxfep); 11034978Sgd78059 mxfe_startnway(mxfep); 11044978Sgd78059 return; 11054978Sgd78059 } 11064978Sgd78059 11074978Sgd78059 /* 11084978Sgd78059 * if the link is newly up, then we might need to set various 11094978Sgd78059 * mode bits, or negotiate for parameters, etc. 11104978Sgd78059 */ 11114978Sgd78059 if (mxfep->mxfe_adv_aneg) { 11124978Sgd78059 11134978Sgd78059 uint16_t anlpar; 11144978Sgd78059 11154978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 11164978Sgd78059 anlpar = mxfep->mxfe_anlpar; 11174978Sgd78059 11184978Sgd78059 if (tstat & TSTAT_LPN) { 11194978Sgd78059 /* partner has NWay */ 11204978Sgd78059 11214978Sgd78059 if ((anlpar & MII_ABILITY_100BASE_TX_FD) && 11224978Sgd78059 mxfep->mxfe_adv_100fdx) { 11234978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 11244978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 11254978Sgd78059 } else if ((anlpar & MII_ABILITY_100BASE_TX) && 11264978Sgd78059 mxfep->mxfe_adv_100hdx) { 11274978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 11284978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 11294978Sgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T_FD) && 11304978Sgd78059 mxfep->mxfe_adv_10fdx) { 11314978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 11324978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 11334978Sgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T) && 11344978Sgd78059 mxfep->mxfe_adv_10hdx) { 11354978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 11364978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 11374978Sgd78059 } else { 11384978Sgd78059 mxfep->mxfe_ifspeed = 0; 11394978Sgd78059 } 11404978Sgd78059 } else { 11414978Sgd78059 /* link partner does not have NWay */ 11424978Sgd78059 /* just assume half duplex, since we can't detect */ 11434978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 11444978Sgd78059 if (!(tstat & TSTAT_100F)) { 11454978Sgd78059 DBG(DPHY, "Partner doesn't have NWAY"); 11464978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 11474978Sgd78059 } else { 11484978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 11494978Sgd78059 } 11504978Sgd78059 } 11514978Sgd78059 } else { 11524978Sgd78059 /* forced modes */ 11534978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 11544978Sgd78059 if (mxfep->mxfe_adv_100fdx) { 11554978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 11564978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 11574978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) { 11584978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 11594978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 11604978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) { 11614978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 11624978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 11634978Sgd78059 } else if (mxfep->mxfe_adv_10hdx) { 11644978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 11654978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 11664978Sgd78059 } else { 11674978Sgd78059 mxfep->mxfe_ifspeed = 0; 11684978Sgd78059 } 11694978Sgd78059 } 11704978Sgd78059 mxfe_reportlink(mxfep); 11716684Sgd78059 mxfep->mxfe_nwaystate = MXFE_GOODLINK; 11724978Sgd78059 } 11734978Sgd78059 11744978Sgd78059 void 11754978Sgd78059 mxfe_startphynway(mxfe_t *mxfep) 11764978Sgd78059 { 11774978Sgd78059 /* take NWay and PHY out of reset */ 11784978Sgd78059 PUTCSR(mxfep, CSR_SIA, SIA_NRESET); 11794978Sgd78059 drv_usecwait(500); 11804978Sgd78059 11816684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK; 11824978Sgd78059 mxfep->mxfe_bmsr = MII_STATUS_CANAUTONEG | 11834978Sgd78059 MII_STATUS_100_BASEX_FD | MII_STATUS_100_BASEX | 11844978Sgd78059 MII_STATUS_10_FD | MII_STATUS_10; 11856684Sgd78059 mxfep->mxfe_cap_aneg = 11866684Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx = 11876684Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1; 11884978Sgd78059 11894978Sgd78059 /* lie about the transceiver... its not really 802.3u compliant */ 11904978Sgd78059 mxfep->mxfe_phyaddr = 0; 11914978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100X; 11924978Sgd78059 mxfep->mxfe_phyid = 0; 11934978Sgd78059 11944978Sgd78059 /* 100-T4 not supported with NWay */ 11954978Sgd78059 mxfep->mxfe_adv_100T4 = 0; 11966684Sgd78059 mxfep->mxfe_cap_100T4 = 0; 11974978Sgd78059 11984978Sgd78059 /* make sure at least one valid mode is selected */ 11994978Sgd78059 if ((!mxfep->mxfe_adv_100fdx) && 12004978Sgd78059 (!mxfep->mxfe_adv_100hdx) && 12014978Sgd78059 (!mxfep->mxfe_adv_10fdx) && 12024978Sgd78059 (!mxfep->mxfe_adv_10hdx)) { 12034978Sgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected."); 12044978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY."); 12054978Sgd78059 mxfe_stopphy(mxfep); 12064978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 12074978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 12084978Sgd78059 mxfe_reportlink(mxfep); 12094978Sgd78059 return; 12104978Sgd78059 } 12114978Sgd78059 12124978Sgd78059 if (mxfep->mxfe_adv_aneg == 0) { 12134978Sgd78059 /* forced mode */ 12144978Sgd78059 unsigned nar; 12154978Sgd78059 unsigned tctl; 12164978Sgd78059 12174978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 12184978Sgd78059 tctl = GETCSR(mxfep, CSR_TCTL); 12194978Sgd78059 12204978Sgd78059 ASSERT((nar & (NAR_TX_ENABLE | NAR_RX_ENABLE)) == 0); 12214978Sgd78059 12224978Sgd78059 nar &= ~(NAR_FDX | NAR_PORTSEL | NAR_SCR | NAR_SPEED); 12234978Sgd78059 tctl &= ~TCTL_ANE; 12244978Sgd78059 if (mxfep->mxfe_adv_100fdx) { 12254978Sgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX; 12264978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) { 12274978Sgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR; 12284978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) { 12294978Sgd78059 nar |= NAR_FDX | NAR_SPEED; 12304978Sgd78059 } else { /* mxfep->mxfe_adv_10hdx */ 12314978Sgd78059 nar |= NAR_SPEED; 12324978Sgd78059 } 12334978Sgd78059 12344978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 12354978Sgd78059 PUTCSR(mxfep, CSR_TCTL, tctl); 12364978Sgd78059 12374978Sgd78059 /* Macronix initializations from Bolo Tsai */ 12384978Sgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000); 12394978Sgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000); 12404978Sgd78059 } else { 12414978Sgd78059 mxfe_startnway(mxfep); 12424978Sgd78059 } 12434978Sgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP | 12444978Sgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC)); 12454978Sgd78059 } 12464978Sgd78059 12474978Sgd78059 /* 12484978Sgd78059 * MII management. 12494978Sgd78059 */ 12504978Sgd78059 void 12514978Sgd78059 mxfe_startphymii(mxfe_t *mxfep) 12524978Sgd78059 { 12534978Sgd78059 unsigned phyaddr; 12544978Sgd78059 unsigned bmcr; 12554978Sgd78059 unsigned bmsr; 12564978Sgd78059 unsigned anar; 12574978Sgd78059 unsigned phyidr1; 12584978Sgd78059 unsigned phyidr2; 12594978Sgd78059 int retries; 12604978Sgd78059 int cnt; 12614978Sgd78059 12624978Sgd78059 mxfep->mxfe_phyaddr = -1; 12634978Sgd78059 12644978Sgd78059 /* search for first PHY we can find */ 12654978Sgd78059 for (phyaddr = 0; phyaddr < 32; phyaddr++) { 12664978Sgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS); 12674978Sgd78059 if ((bmsr != 0) && (bmsr != 0xffff)) { 12684978Sgd78059 mxfep->mxfe_phyaddr = phyaddr; 12694978Sgd78059 break; 12704978Sgd78059 } 12714978Sgd78059 } 12724978Sgd78059 12734978Sgd78059 phyidr1 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDH); 12744978Sgd78059 phyidr2 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDL); 12754978Sgd78059 mxfep->mxfe_phyid = (phyidr1 << 16) | (phyidr2); 12764978Sgd78059 12774978Sgd78059 /* 12784978Sgd78059 * Generally, all Macronix based devices use an internal 12794978Sgd78059 * 100BASE-TX internal transceiver. If we ever run into a 12804978Sgd78059 * variation on this, then the following logic will need to be 12814978Sgd78059 * enhanced. 12824978Sgd78059 * 12834978Sgd78059 * One could question the value of the XCVR_INUSE field in the 12844978Sgd78059 * MII statistics. 12854978Sgd78059 */ 12864978Sgd78059 if (bmsr & MII_STATUS_100_BASE_T4) { 12874978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100T4; 12884978Sgd78059 } else { 12894978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100X; 12904978Sgd78059 } 12914978Sgd78059 12926684Sgd78059 /* assume we support everything to start */ 12936684Sgd78059 mxfep->mxfe_cap_aneg = mxfep->mxfe_cap_100T4 = 12946684Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx = 12956684Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1; 12966684Sgd78059 12974978Sgd78059 DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2); 12984978Sgd78059 DBG(DPHY, "bmsr = %x", mxfe_miiread(mxfep, 12994978Sgd78059 mxfep->mxfe_phyaddr, MII_STATUS)); 13004978Sgd78059 DBG(DPHY, "anar = %x", mxfe_miiread(mxfep, 13014978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_ADVERT)); 13024978Sgd78059 DBG(DPHY, "anlpar = %x", mxfe_miiread(mxfep, 13034978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_LPABLE)); 13044978Sgd78059 DBG(DPHY, "aner = %x", mxfe_miiread(mxfep, 13054978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_EXPANSION)); 13064978Sgd78059 13074978Sgd78059 DBG(DPHY, "resetting phy"); 13084978Sgd78059 13094978Sgd78059 /* we reset the phy block */ 13104978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, MII_CONTROL_RESET); 13114978Sgd78059 /* 13124978Sgd78059 * wait for it to complete -- 500usec is still to short to 13134978Sgd78059 * bother getting the system clock involved. 13144978Sgd78059 */ 13154978Sgd78059 drv_usecwait(500); 13164978Sgd78059 for (retries = 0; retries < 10; retries++) { 13174978Sgd78059 if (mxfe_miiread(mxfep, phyaddr, MII_CONTROL) & 13184978Sgd78059 MII_CONTROL_RESET) { 13194978Sgd78059 drv_usecwait(500); 13204978Sgd78059 continue; 13214978Sgd78059 } 13224978Sgd78059 break; 13234978Sgd78059 } 13244978Sgd78059 if (retries == 100) { 13254978Sgd78059 mxfe_error(mxfep->mxfe_dip, "timeout waiting on phy to reset"); 13264978Sgd78059 return; 13274978Sgd78059 } 13284978Sgd78059 13294978Sgd78059 DBG(DPHY, "phy reset complete"); 13304978Sgd78059 13314978Sgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS); 13324978Sgd78059 bmcr = mxfe_miiread(mxfep, phyaddr, MII_CONTROL); 13334978Sgd78059 anar = mxfe_miiread(mxfep, phyaddr, MII_AN_ADVERT); 13344978Sgd78059 13354978Sgd78059 anar &= ~(MII_ABILITY_100BASE_T4 | 13364978Sgd78059 MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX | 13374978Sgd78059 MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T); 13384978Sgd78059 13394978Sgd78059 /* disable modes not supported in hardware */ 13404978Sgd78059 if (!(bmsr & MII_STATUS_100_BASE_T4)) { 13414978Sgd78059 mxfep->mxfe_adv_100T4 = 0; 13426684Sgd78059 mxfep->mxfe_cap_100T4 = 0; 13434978Sgd78059 } 13444978Sgd78059 if (!(bmsr & MII_STATUS_100_BASEX_FD)) { 13454978Sgd78059 mxfep->mxfe_adv_100fdx = 0; 13466684Sgd78059 mxfep->mxfe_cap_100fdx = 0; 13474978Sgd78059 } 13484978Sgd78059 if (!(bmsr & MII_STATUS_100_BASEX)) { 13494978Sgd78059 mxfep->mxfe_adv_100hdx = 0; 13506684Sgd78059 mxfep->mxfe_cap_100hdx = 0; 13514978Sgd78059 } 13524978Sgd78059 if (!(bmsr & MII_STATUS_10_FD)) { 13534978Sgd78059 mxfep->mxfe_adv_10fdx = 0; 13546684Sgd78059 mxfep->mxfe_cap_10fdx = 0; 13554978Sgd78059 } 13564978Sgd78059 if (!(bmsr & MII_STATUS_10)) { 13574978Sgd78059 mxfep->mxfe_adv_10hdx = 0; 13586684Sgd78059 mxfep->mxfe_cap_10hdx = 0; 13594978Sgd78059 } 13604978Sgd78059 if (!(bmsr & MII_STATUS_CANAUTONEG)) { 13614978Sgd78059 mxfep->mxfe_adv_aneg = 0; 13626684Sgd78059 mxfep->mxfe_cap_aneg = 0; 13634978Sgd78059 } 13644978Sgd78059 13654978Sgd78059 cnt = 0; 13664978Sgd78059 if (mxfep->mxfe_adv_100T4) { 13674978Sgd78059 anar |= MII_ABILITY_100BASE_T4; 13684978Sgd78059 cnt++; 13694978Sgd78059 } 13704978Sgd78059 if (mxfep->mxfe_adv_100fdx) { 13714978Sgd78059 anar |= MII_ABILITY_100BASE_TX_FD; 13724978Sgd78059 cnt++; 13734978Sgd78059 } 13744978Sgd78059 if (mxfep->mxfe_adv_100hdx) { 13754978Sgd78059 anar |= MII_ABILITY_100BASE_TX; 13764978Sgd78059 cnt++; 13774978Sgd78059 } 13784978Sgd78059 if (mxfep->mxfe_adv_10fdx) { 13794978Sgd78059 anar |= MII_ABILITY_10BASE_T_FD; 13804978Sgd78059 cnt++; 13814978Sgd78059 } 13824978Sgd78059 if (mxfep->mxfe_adv_10hdx) { 13834978Sgd78059 anar |= MII_ABILITY_10BASE_T; 13844978Sgd78059 cnt++; 13854978Sgd78059 } 13864978Sgd78059 13874978Sgd78059 /* 13884978Sgd78059 * Make certain at least one valid link mode is selected. 13894978Sgd78059 */ 13904978Sgd78059 if (!cnt) { 13914978Sgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected."); 13924978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY."); 13934978Sgd78059 mxfe_stopphy(mxfep); 13944978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 13954978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 13964978Sgd78059 mxfe_reportlink(mxfep); 13974978Sgd78059 return; 13984978Sgd78059 } 13994978Sgd78059 14004978Sgd78059 if ((mxfep->mxfe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) { 14014978Sgd78059 DBG(DPHY, "using autoneg mode"); 14024978Sgd78059 bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN); 14034978Sgd78059 } else { 14044978Sgd78059 DBG(DPHY, "using forced mode"); 14054978Sgd78059 if (mxfep->mxfe_adv_100fdx) { 14064978Sgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 14074978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) { 14084978Sgd78059 bmcr = MII_CONTROL_100MB; 14094978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) { 14104978Sgd78059 bmcr = MII_CONTROL_FDUPLEX; 14114978Sgd78059 } else { 14124978Sgd78059 /* 10HDX */ 14134978Sgd78059 bmcr = 0; 14144978Sgd78059 } 14154978Sgd78059 } 14164978Sgd78059 14174978Sgd78059 DBG(DPHY, "programming anar to 0x%x", anar); 14184978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_AN_ADVERT, anar); 14194978Sgd78059 DBG(DPHY, "programming bmcr to 0x%x", bmcr); 14204978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, bmcr); 14214978Sgd78059 14224978Sgd78059 /* 14234978Sgd78059 * schedule a query of the link status 14244978Sgd78059 */ 14254978Sgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP | 14264978Sgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC)); 14274978Sgd78059 } 14284978Sgd78059 14294978Sgd78059 void 14304978Sgd78059 mxfe_reportlink(mxfe_t *mxfep) 14314978Sgd78059 { 14324978Sgd78059 int changed = 0; 14334978Sgd78059 14344978Sgd78059 if (mxfep->mxfe_ifspeed != mxfep->mxfe_lastifspeed) { 14354978Sgd78059 mxfep->mxfe_lastifspeed = mxfep->mxfe_ifspeed; 14364978Sgd78059 changed++; 14374978Sgd78059 } 14384978Sgd78059 if (mxfep->mxfe_duplex != mxfep->mxfe_lastduplex) { 14394978Sgd78059 mxfep->mxfe_lastduplex = mxfep->mxfe_duplex; 14404978Sgd78059 changed++; 14414978Sgd78059 } 14424978Sgd78059 if (mxfep->mxfe_linkup != mxfep->mxfe_lastlinkup) { 14434978Sgd78059 mxfep->mxfe_lastlinkup = mxfep->mxfe_linkup; 14444978Sgd78059 changed++; 14454978Sgd78059 } 14464978Sgd78059 if (changed) 14474978Sgd78059 mac_link_update(mxfep->mxfe_mh, mxfep->mxfe_linkup); 14484978Sgd78059 } 14494978Sgd78059 14504978Sgd78059 void 14514978Sgd78059 mxfe_checklink(mxfe_t *mxfep) 14524978Sgd78059 { 14534978Sgd78059 if ((mxfep->mxfe_flags & MXFE_RUNNING) == 0) 14544978Sgd78059 return; 14554978Sgd78059 14564978Sgd78059 if ((mxfep->mxfe_txstall_time != 0) && 14574978Sgd78059 (gethrtime() > mxfep->mxfe_txstall_time) && 14584978Sgd78059 (mxfep->mxfe_txavail != MXFE_TXRING)) { 14594978Sgd78059 mxfep->mxfe_txstall_time = 0; 14604978Sgd78059 mxfe_error(mxfep->mxfe_dip, "TX stall detected!"); 14614978Sgd78059 mxfe_resetall(mxfep); 14624978Sgd78059 return; 14634978Sgd78059 } 14644978Sgd78059 14654978Sgd78059 switch (MXFE_MODEL(mxfep)) { 14664978Sgd78059 case MXFE_98713A: 14674978Sgd78059 mxfe_checklinkmii(mxfep); 14684978Sgd78059 break; 14694978Sgd78059 default: 14704978Sgd78059 mxfe_checklinknway(mxfep); 14714978Sgd78059 } 14724978Sgd78059 } 14734978Sgd78059 14744978Sgd78059 void 14754978Sgd78059 mxfe_checklinkmii(mxfe_t *mxfep) 14764978Sgd78059 { 14774978Sgd78059 /* read MII state registers */ 14784978Sgd78059 uint16_t bmsr; 14794978Sgd78059 uint16_t bmcr; 14804978Sgd78059 uint16_t anar; 14814978Sgd78059 uint16_t anlpar; 14824978Sgd78059 uint16_t aner; 14834978Sgd78059 14844978Sgd78059 /* read this twice, to clear latched link state */ 14854978Sgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS); 14864978Sgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS); 14874978Sgd78059 bmcr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL); 14884978Sgd78059 anar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_ADVERT); 14894978Sgd78059 anlpar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_LPABLE); 14904978Sgd78059 aner = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_EXPANSION); 14914978Sgd78059 14924978Sgd78059 mxfep->mxfe_bmsr = bmsr; 14934978Sgd78059 mxfep->mxfe_anlpar = anlpar; 14944978Sgd78059 mxfep->mxfe_aner = aner; 14954978Sgd78059 14964978Sgd78059 if (bmsr & MII_STATUS_REMFAULT) { 14974978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Remote fault detected."); 14984978Sgd78059 } 14994978Sgd78059 if (bmsr & MII_STATUS_JABBERING) { 15004978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Jabber condition detected."); 15014978Sgd78059 } 15024978Sgd78059 if ((bmsr & MII_STATUS_LINKUP) == 0) { 15034978Sgd78059 /* no link */ 15044978Sgd78059 mxfep->mxfe_ifspeed = 0; 15054978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 15064978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN; 15074978Sgd78059 mxfe_reportlink(mxfep); 15084978Sgd78059 return; 15094978Sgd78059 } 15104978Sgd78059 15114978Sgd78059 DBG(DCHATTY, "link up!"); 15124978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP; 15134978Sgd78059 15144978Sgd78059 if (!(bmcr & MII_CONTROL_ANE)) { 15154978Sgd78059 /* forced mode */ 15164978Sgd78059 if (bmcr & MII_CONTROL_100MB) { 15174978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 15184978Sgd78059 } else { 15194978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 15204978Sgd78059 } 15214978Sgd78059 if (bmcr & MII_CONTROL_FDUPLEX) { 15224978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 15234978Sgd78059 } else { 15244978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 15254978Sgd78059 } 15264978Sgd78059 } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) || 15274978Sgd78059 (!(bmsr & MII_STATUS_ANDONE))) { 15284978Sgd78059 mxfep->mxfe_ifspeed = 0; 15294978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 15304978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) { 15314978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 15324978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 15334978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_T4) { 15344978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 15354978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 15364978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX) { 15374978Sgd78059 mxfep->mxfe_ifspeed = 100000000; 15384978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 15394978Sgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) { 15404978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 15414978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL; 15424978Sgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T) { 15434978Sgd78059 mxfep->mxfe_ifspeed = 10000000; 15444978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF; 15454978Sgd78059 } else { 15464978Sgd78059 mxfep->mxfe_ifspeed = 0; 15474978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN; 15484978Sgd78059 } 15494978Sgd78059 15504978Sgd78059 mxfe_reportlink(mxfep); 15514978Sgd78059 } 15524978Sgd78059 15534978Sgd78059 void 15544978Sgd78059 mxfe_miitristate(mxfe_t *mxfep) 15554978Sgd78059 { 15564978Sgd78059 unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL; 15574978Sgd78059 PUTCSR(mxfep, CSR_SPR, val); 15584978Sgd78059 drv_usecwait(1); 15594978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 15604978Sgd78059 drv_usecwait(1); 15614978Sgd78059 } 15624978Sgd78059 15634978Sgd78059 void 15646684Sgd78059 mxfe_miiwritebit(mxfe_t *mxfep, uint8_t bit) 15654978Sgd78059 { 15664978Sgd78059 unsigned val = bit ? SPR_MII_DOUT : 0; 15674978Sgd78059 PUTCSR(mxfep, CSR_SPR, val); 15684978Sgd78059 drv_usecwait(1); 15694978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 15704978Sgd78059 drv_usecwait(1); 15714978Sgd78059 } 15724978Sgd78059 15736684Sgd78059 uint8_t 15744978Sgd78059 mxfe_miireadbit(mxfe_t *mxfep) 15754978Sgd78059 { 15764978Sgd78059 unsigned val = SPR_MII_CTRL | SPR_SROM_READ; 15776684Sgd78059 uint8_t bit; 15784978Sgd78059 PUTCSR(mxfep, CSR_SPR, val); 15794978Sgd78059 drv_usecwait(1); 15804978Sgd78059 bit = (GETCSR(mxfep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0; 15814978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK); 15824978Sgd78059 drv_usecwait(1); 15834978Sgd78059 return (bit); 15844978Sgd78059 } 15854978Sgd78059 15866684Sgd78059 uint16_t 15874978Sgd78059 mxfe_miiread(mxfe_t *mxfep, int phy, int reg) 15884978Sgd78059 { 15894978Sgd78059 switch (MXFE_MODEL(mxfep)) { 15904978Sgd78059 case MXFE_98713A: 15914978Sgd78059 return (mxfe_miiread98713(mxfep, phy, reg)); 15924978Sgd78059 default: 15934978Sgd78059 return (0xffff); 15944978Sgd78059 } 15954978Sgd78059 } 15964978Sgd78059 15976684Sgd78059 uint16_t 15984978Sgd78059 mxfe_miireadgeneral(mxfe_t *mxfep, int phy, int reg) 15994978Sgd78059 { 16006684Sgd78059 uint16_t value = 0; 16014978Sgd78059 int i; 16024978Sgd78059 16034978Sgd78059 /* send the 32 bit preamble */ 16044978Sgd78059 for (i = 0; i < 32; i++) { 16054978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16064978Sgd78059 } 16074978Sgd78059 16084978Sgd78059 /* send the start code - 01b */ 16094978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16104978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16114978Sgd78059 16124978Sgd78059 /* send the opcode for read, - 10b */ 16134978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16144978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16154978Sgd78059 16164978Sgd78059 /* next we send the 5 bit phy address */ 16174978Sgd78059 for (i = 0x10; i > 0; i >>= 1) { 16184978Sgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0); 16194978Sgd78059 } 16204978Sgd78059 16214978Sgd78059 /* the 5 bit register address goes next */ 16224978Sgd78059 for (i = 0x10; i > 0; i >>= 1) { 16234978Sgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0); 16244978Sgd78059 } 16254978Sgd78059 16264978Sgd78059 /* turnaround - tristate followed by logic 0 */ 16274978Sgd78059 mxfe_miitristate(mxfep); 16284978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16294978Sgd78059 16304978Sgd78059 /* read the 16 bit register value */ 16314978Sgd78059 for (i = 0x8000; i > 0; i >>= 1) { 16324978Sgd78059 value <<= 1; 16334978Sgd78059 value |= mxfe_miireadbit(mxfep); 16344978Sgd78059 } 16354978Sgd78059 mxfe_miitristate(mxfep); 16364978Sgd78059 return (value); 16374978Sgd78059 } 16384978Sgd78059 16396684Sgd78059 uint16_t 16404978Sgd78059 mxfe_miiread98713(mxfe_t *mxfep, int phy, int reg) 16414978Sgd78059 { 16424978Sgd78059 unsigned nar; 16436684Sgd78059 uint16_t retval; 16444978Sgd78059 /* 16454978Sgd78059 * like an ordinary MII, but we have to turn off portsel while 16464978Sgd78059 * we read it. 16474978Sgd78059 */ 16484978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 16494978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL); 16504978Sgd78059 retval = mxfe_miireadgeneral(mxfep, phy, reg); 16514978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 16524978Sgd78059 return (retval); 16534978Sgd78059 } 16544978Sgd78059 16554978Sgd78059 void 16564978Sgd78059 mxfe_miiwrite(mxfe_t *mxfep, int phy, int reg, uint16_t val) 16574978Sgd78059 { 16584978Sgd78059 switch (MXFE_MODEL(mxfep)) { 16594978Sgd78059 case MXFE_98713A: 16604978Sgd78059 mxfe_miiwrite98713(mxfep, phy, reg, val); 16614978Sgd78059 break; 16624978Sgd78059 default: 16634978Sgd78059 break; 16644978Sgd78059 } 16654978Sgd78059 } 16664978Sgd78059 16674978Sgd78059 void 16684978Sgd78059 mxfe_miiwritegeneral(mxfe_t *mxfep, int phy, int reg, uint16_t val) 16694978Sgd78059 { 16704978Sgd78059 int i; 16714978Sgd78059 16724978Sgd78059 /* send the 32 bit preamble */ 16734978Sgd78059 for (i = 0; i < 32; i++) { 16744978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16754978Sgd78059 } 16764978Sgd78059 16774978Sgd78059 /* send the start code - 01b */ 16784978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16794978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16804978Sgd78059 16814978Sgd78059 /* send the opcode for write, - 01b */ 16824978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16834978Sgd78059 mxfe_miiwritebit(mxfep, 1); 16844978Sgd78059 16854978Sgd78059 /* next we send the 5 bit phy address */ 16864978Sgd78059 for (i = 0x10; i > 0; i >>= 1) { 16874978Sgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0); 16884978Sgd78059 } 16894978Sgd78059 16904978Sgd78059 /* the 5 bit register address goes next */ 16914978Sgd78059 for (i = 0x10; i > 0; i >>= 1) { 16924978Sgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0); 16934978Sgd78059 } 16944978Sgd78059 16954978Sgd78059 /* turnaround - tristate followed by logic 0 */ 16964978Sgd78059 mxfe_miitristate(mxfep); 16974978Sgd78059 mxfe_miiwritebit(mxfep, 0); 16984978Sgd78059 16994978Sgd78059 /* now write out our data (16 bits) */ 17004978Sgd78059 for (i = 0x8000; i > 0; i >>= 1) { 17014978Sgd78059 mxfe_miiwritebit(mxfep, (val & i) ? 1 : 0); 17024978Sgd78059 } 17034978Sgd78059 17044978Sgd78059 /* idle mode */ 17054978Sgd78059 mxfe_miitristate(mxfep); 17064978Sgd78059 } 17074978Sgd78059 17084978Sgd78059 void 17094978Sgd78059 mxfe_miiwrite98713(mxfe_t *mxfep, int phy, int reg, uint16_t val) 17104978Sgd78059 { 17114978Sgd78059 unsigned nar; 17124978Sgd78059 /* 17134978Sgd78059 * like an ordinary MII, but we have to turn off portsel while 17144978Sgd78059 * we read it. 17154978Sgd78059 */ 17164978Sgd78059 nar = GETCSR(mxfep, CSR_NAR); 17174978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL); 17184978Sgd78059 mxfe_miiwritegeneral(mxfep, phy, reg, val); 17194978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar); 17204978Sgd78059 } 17214978Sgd78059 17224978Sgd78059 int 17234978Sgd78059 mxfe_m_start(void *arg) 17244978Sgd78059 { 17254978Sgd78059 mxfe_t *mxfep = arg; 17264978Sgd78059 17274978Sgd78059 /* grab exclusive access to the card */ 17284978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 17294978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 17304978Sgd78059 17314978Sgd78059 mxfe_startall(mxfep); 17324978Sgd78059 mxfep->mxfe_flags |= MXFE_RUNNING; 17334978Sgd78059 17344978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 17354978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 17364978Sgd78059 return (0); 17374978Sgd78059 } 17384978Sgd78059 17394978Sgd78059 void 17404978Sgd78059 mxfe_m_stop(void *arg) 17414978Sgd78059 { 17424978Sgd78059 mxfe_t *mxfep = arg; 17434978Sgd78059 17444978Sgd78059 /* exclusive access to the hardware! */ 17454978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 17464978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 17474978Sgd78059 17484978Sgd78059 mxfe_stopall(mxfep); 17494978Sgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING; 17504978Sgd78059 17514978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 17524978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 17534978Sgd78059 } 17544978Sgd78059 17554978Sgd78059 void 17564978Sgd78059 mxfe_startmac(mxfe_t *mxfep) 17574978Sgd78059 { 17584978Sgd78059 /* verify exclusive access to the card */ 17594978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 17604978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 17614978Sgd78059 17624978Sgd78059 /* start the card */ 17634978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 17644978Sgd78059 17654978Sgd78059 if (mxfep->mxfe_txavail != MXFE_TXRING) 17664978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0); 17674978Sgd78059 17684978Sgd78059 /* tell the mac that we are ready to go! */ 17694978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) 17704978Sgd78059 mac_tx_update(mxfep->mxfe_mh); 17714978Sgd78059 } 17724978Sgd78059 17734978Sgd78059 void 17744978Sgd78059 mxfe_stopmac(mxfe_t *mxfep) 17754978Sgd78059 { 17764978Sgd78059 int i; 17774978Sgd78059 17784978Sgd78059 /* exclusive access to the hardware! */ 17794978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 17804978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 17814978Sgd78059 17824978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE); 17834978Sgd78059 17844978Sgd78059 /* 17854978Sgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain. 17864978Sgd78059 * We just add up to the nearest msec (2), which should be 17874978Sgd78059 * plenty to complete. 17884978Sgd78059 * 17894978Sgd78059 * Note that some chips never seem to indicate the transition to 17904978Sgd78059 * the stopped state properly. Experience shows that we can safely 17914978Sgd78059 * proceed anyway, after waiting the requisite timeout. 17924978Sgd78059 */ 17934978Sgd78059 for (i = 2000; i != 0; i -= 10) { 17944978Sgd78059 if ((GETCSR(mxfep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0) 17954978Sgd78059 break; 17964978Sgd78059 drv_usecwait(10); 17974978Sgd78059 } 17984978Sgd78059 17994978Sgd78059 /* prevent an interrupt */ 18004978Sgd78059 PUTCSR(mxfep, CSR_SR, INT_RXSTOPPED | INT_TXSTOPPED); 18014978Sgd78059 } 18024978Sgd78059 18034978Sgd78059 void 18044978Sgd78059 mxfe_resetrings(mxfe_t *mxfep) 18054978Sgd78059 { 18064978Sgd78059 int i; 18074978Sgd78059 18084978Sgd78059 /* now we need to reset the pointers... */ 18094978Sgd78059 PUTCSR(mxfep, CSR_RDB, 0); 18104978Sgd78059 PUTCSR(mxfep, CSR_TDB, 0); 18114978Sgd78059 18124978Sgd78059 /* reset the descriptor ring pointers */ 18134978Sgd78059 mxfep->mxfe_rxhead = 0; 18144978Sgd78059 mxfep->mxfe_txreclaim = 0; 18154978Sgd78059 mxfep->mxfe_txsend = 0; 18164978Sgd78059 mxfep->mxfe_txavail = MXFE_TXRING; 18174978Sgd78059 18184978Sgd78059 /* set up transmit descriptor ring */ 18194978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) { 18204978Sgd78059 mxfe_desc_t *tmdp = &mxfep->mxfe_txdescp[i]; 18214978Sgd78059 unsigned control = 0; 18224978Sgd78059 if (i == (MXFE_TXRING - 1)) { 18234978Sgd78059 control |= TXCTL_ENDRING; 18244978Sgd78059 } 18254978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_status, 0); 18264978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_control, control); 18274978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, 0); 18284978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0); 18294978Sgd78059 SYNCTXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV); 18304978Sgd78059 } 18314978Sgd78059 PUTCSR(mxfep, CSR_TDB, mxfep->mxfe_txdesc_paddr); 18324978Sgd78059 18334978Sgd78059 /* make the receive buffers available */ 18344978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) { 18354978Sgd78059 mxfe_rxbuf_t *rxb = mxfep->mxfe_rxbufs[i]; 18364978Sgd78059 mxfe_desc_t *rmdp = &mxfep->mxfe_rxdescp[i]; 18374978Sgd78059 unsigned control; 18384978Sgd78059 18394978Sgd78059 control = MXFE_BUFSZ & RXCTL_BUFLEN1; 18404978Sgd78059 if (i == (MXFE_RXRING - 1)) { 18414978Sgd78059 control |= RXCTL_ENDRING; 18424978Sgd78059 } 18434978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer1, rxb->rxb_paddr); 18444978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer2, 0); 18454978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_control, control); 18464978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_status, RXSTAT_OWN); 18474978Sgd78059 SYNCRXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV); 18484978Sgd78059 } 18494978Sgd78059 PUTCSR(mxfep, CSR_RDB, mxfep->mxfe_rxdesc_paddr); 18504978Sgd78059 } 18514978Sgd78059 18524978Sgd78059 void 18534978Sgd78059 mxfe_stopall(mxfe_t *mxfep) 18544978Sgd78059 { 18554978Sgd78059 mxfe_disableinterrupts(mxfep); 18564978Sgd78059 18574978Sgd78059 mxfe_stopmac(mxfep); 18584978Sgd78059 18594978Sgd78059 /* stop the phy */ 18604978Sgd78059 mxfe_stopphy(mxfep); 18614978Sgd78059 } 18624978Sgd78059 18634978Sgd78059 void 18644978Sgd78059 mxfe_startall(mxfe_t *mxfep) 18654978Sgd78059 { 18664978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock)); 18674978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 18684978Sgd78059 18694978Sgd78059 /* make sure interrupts are disabled to begin */ 18704978Sgd78059 mxfe_disableinterrupts(mxfep); 18714978Sgd78059 18724978Sgd78059 /* initialize the chip */ 18734978Sgd78059 (void) mxfe_initialize(mxfep); 18744978Sgd78059 18754978Sgd78059 /* now we can enable interrupts */ 18764978Sgd78059 mxfe_enableinterrupts(mxfep); 18774978Sgd78059 18784978Sgd78059 /* start up the phy */ 18794978Sgd78059 mxfe_startphy(mxfep); 18804978Sgd78059 18814978Sgd78059 /* start up the mac */ 18824978Sgd78059 mxfe_startmac(mxfep); 18834978Sgd78059 } 18844978Sgd78059 18854978Sgd78059 void 18864978Sgd78059 mxfe_resetall(mxfe_t *mxfep) 18874978Sgd78059 { 18884978Sgd78059 mxfep->mxfe_resetting = B_TRUE; 18894978Sgd78059 mxfe_stopall(mxfep); 18904978Sgd78059 mxfep->mxfe_resetting = B_FALSE; 18914978Sgd78059 mxfe_startall(mxfep); 18924978Sgd78059 } 18934978Sgd78059 18944978Sgd78059 mxfe_txbuf_t * 18954978Sgd78059 mxfe_alloctxbuf(mxfe_t *mxfep) 18964978Sgd78059 { 18974978Sgd78059 ddi_dma_cookie_t dmac; 18984978Sgd78059 unsigned ncookies; 18994978Sgd78059 mxfe_txbuf_t *txb; 19004978Sgd78059 size_t len; 19014978Sgd78059 19024978Sgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP); 19034978Sgd78059 19044978Sgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_txattr, 19054978Sgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) { 19064978Sgd78059 return (NULL); 19074978Sgd78059 } 19084978Sgd78059 19094978Sgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, MXFE_BUFSZ, &mxfe_bufattr, 19104978Sgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, 19114978Sgd78059 &len, &txb->txb_acch) != DDI_SUCCESS) { 19124978Sgd78059 return (NULL); 19134978Sgd78059 } 19144978Sgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf, 19154978Sgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 19164978Sgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) { 19174978Sgd78059 return (NULL); 19184978Sgd78059 } 19194978Sgd78059 txb->txb_paddr = dmac.dmac_address; 19204978Sgd78059 19214978Sgd78059 return (txb); 19224978Sgd78059 } 19234978Sgd78059 19244978Sgd78059 void 19254978Sgd78059 mxfe_destroytxbuf(mxfe_txbuf_t *txb) 19264978Sgd78059 { 19274978Sgd78059 if (txb != NULL) { 19284978Sgd78059 if (txb->txb_paddr) 19294978Sgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah); 19304978Sgd78059 if (txb->txb_acch) 19314978Sgd78059 ddi_dma_mem_free(&txb->txb_acch); 19324978Sgd78059 if (txb->txb_dmah) 19334978Sgd78059 ddi_dma_free_handle(&txb->txb_dmah); 19344978Sgd78059 kmem_free(txb, sizeof (*txb)); 19354978Sgd78059 } 19364978Sgd78059 } 19374978Sgd78059 19384978Sgd78059 mxfe_rxbuf_t * 19394978Sgd78059 mxfe_allocrxbuf(mxfe_t *mxfep) 19404978Sgd78059 { 19414978Sgd78059 mxfe_rxbuf_t *rxb; 19424978Sgd78059 size_t len; 19434978Sgd78059 unsigned ccnt; 19444978Sgd78059 ddi_dma_cookie_t dmac; 19454978Sgd78059 19464978Sgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP); 19474978Sgd78059 19484978Sgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 19494978Sgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) { 19504978Sgd78059 kmem_free(rxb, sizeof (*rxb)); 19514978Sgd78059 return (NULL); 19524978Sgd78059 } 19534978Sgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, MXFE_BUFSZ, &mxfe_bufattr, 19544978Sgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 19554978Sgd78059 &rxb->rxb_buf, &len, &rxb->rxb_acch) != DDI_SUCCESS) { 19564978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 19574978Sgd78059 kmem_free(rxb, sizeof (*rxb)); 19584978Sgd78059 return (NULL); 19594978Sgd78059 } 19604978Sgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len, 19614978Sgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac, 19624978Sgd78059 &ccnt) != DDI_DMA_MAPPED) { 19634978Sgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 19644978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 19654978Sgd78059 kmem_free(rxb, sizeof (*rxb)); 19664978Sgd78059 return (NULL); 19674978Sgd78059 } 19684978Sgd78059 rxb->rxb_paddr = dmac.dmac_address; 19694978Sgd78059 19704978Sgd78059 return (rxb); 19714978Sgd78059 } 19724978Sgd78059 19734978Sgd78059 void 19744978Sgd78059 mxfe_destroyrxbuf(mxfe_rxbuf_t *rxb) 19754978Sgd78059 { 19764978Sgd78059 if (rxb != NULL) { 19774978Sgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah); 19784978Sgd78059 ddi_dma_mem_free(&rxb->rxb_acch); 19794978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah); 19804978Sgd78059 kmem_free(rxb, sizeof (*rxb)); 19814978Sgd78059 } 19824978Sgd78059 } 19834978Sgd78059 19844978Sgd78059 /* 19854978Sgd78059 * Allocate receive resources. 19864978Sgd78059 */ 19874978Sgd78059 int 19884978Sgd78059 mxfe_allocrxring(mxfe_t *mxfep) 19894978Sgd78059 { 19904978Sgd78059 int rval; 19914978Sgd78059 int i; 19924978Sgd78059 size_t size; 19934978Sgd78059 size_t len; 19944978Sgd78059 ddi_dma_cookie_t dmac; 19954978Sgd78059 unsigned ncookies; 19964978Sgd78059 caddr_t kaddr; 19974978Sgd78059 19984978Sgd78059 size = MXFE_RXRING * sizeof (mxfe_desc_t); 19994978Sgd78059 20004978Sgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 20014978Sgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_rxdesc_dmah); 20024978Sgd78059 if (rval != DDI_SUCCESS) { 20034978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20044978Sgd78059 "unable to allocate DMA handle for rx descriptors"); 20054978Sgd78059 return (DDI_FAILURE); 20064978Sgd78059 } 20074978Sgd78059 20084978Sgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_rxdesc_dmah, size, &mxfe_devattr, 20094978Sgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 20104978Sgd78059 &mxfep->mxfe_rxdesc_acch); 20114978Sgd78059 if (rval != DDI_SUCCESS) { 20124978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20134978Sgd78059 "unable to allocate DMA memory for rx descriptors"); 20144978Sgd78059 return (DDI_FAILURE); 20154978Sgd78059 } 20164978Sgd78059 20174978Sgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_rxdesc_dmah, NULL, kaddr, 20184978Sgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 20194978Sgd78059 &dmac, &ncookies); 20204978Sgd78059 if (rval != DDI_DMA_MAPPED) { 20214978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20224978Sgd78059 "unable to bind DMA for rx descriptors"); 20234978Sgd78059 return (DDI_FAILURE); 20244978Sgd78059 } 20254978Sgd78059 20264978Sgd78059 /* because of mxfe_dma_attr */ 20274978Sgd78059 ASSERT(ncookies == 1); 20284978Sgd78059 20294978Sgd78059 /* we take the 32-bit physical address out of the cookie */ 20304978Sgd78059 mxfep->mxfe_rxdesc_paddr = dmac.dmac_address; 20314978Sgd78059 mxfep->mxfe_rxdescp = (void *)kaddr; 20324978Sgd78059 20334978Sgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 20344978Sgd78059 mxfep->mxfe_rxbufs = kmem_zalloc(MXFE_RXRING * sizeof (mxfe_rxbuf_t *), 20354978Sgd78059 KM_SLEEP); 20364978Sgd78059 20374978Sgd78059 /* now allocate rx buffers */ 20384978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) { 20394978Sgd78059 mxfe_rxbuf_t *rxb = mxfe_allocrxbuf(mxfep); 20404978Sgd78059 if (rxb == NULL) 20414978Sgd78059 return (DDI_FAILURE); 20424978Sgd78059 mxfep->mxfe_rxbufs[i] = rxb; 20434978Sgd78059 } 20444978Sgd78059 20454978Sgd78059 return (DDI_SUCCESS); 20464978Sgd78059 } 20474978Sgd78059 20484978Sgd78059 /* 20494978Sgd78059 * Allocate transmit resources. 20504978Sgd78059 */ 20514978Sgd78059 int 20524978Sgd78059 mxfe_alloctxring(mxfe_t *mxfep) 20534978Sgd78059 { 20544978Sgd78059 int rval; 20554978Sgd78059 int i; 20564978Sgd78059 size_t size; 20574978Sgd78059 size_t len; 20584978Sgd78059 ddi_dma_cookie_t dmac; 20594978Sgd78059 unsigned ncookies; 20604978Sgd78059 caddr_t kaddr; 20614978Sgd78059 20624978Sgd78059 size = MXFE_TXRING * sizeof (mxfe_desc_t); 20634978Sgd78059 20644978Sgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr, 20654978Sgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_txdesc_dmah); 20664978Sgd78059 if (rval != DDI_SUCCESS) { 20674978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20684978Sgd78059 "unable to allocate DMA handle for tx descriptors"); 20694978Sgd78059 return (DDI_FAILURE); 20704978Sgd78059 } 20714978Sgd78059 20724978Sgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_txdesc_dmah, size, &mxfe_devattr, 20734978Sgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len, 20744978Sgd78059 &mxfep->mxfe_txdesc_acch); 20754978Sgd78059 if (rval != DDI_SUCCESS) { 20764978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20774978Sgd78059 "unable to allocate DMA memory for tx descriptors"); 20784978Sgd78059 return (DDI_FAILURE); 20794978Sgd78059 } 20804978Sgd78059 20814978Sgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_txdesc_dmah, NULL, kaddr, 20824978Sgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 20834978Sgd78059 &dmac, &ncookies); 20844978Sgd78059 if (rval != DDI_DMA_MAPPED) { 20854978Sgd78059 mxfe_error(mxfep->mxfe_dip, 20864978Sgd78059 "unable to bind DMA for tx descriptors"); 20874978Sgd78059 return (DDI_FAILURE); 20884978Sgd78059 } 20894978Sgd78059 20904978Sgd78059 /* because of mxfe_dma_attr */ 20914978Sgd78059 ASSERT(ncookies == 1); 20924978Sgd78059 20934978Sgd78059 /* we take the 32-bit physical address out of the cookie */ 20944978Sgd78059 mxfep->mxfe_txdesc_paddr = dmac.dmac_address; 20954978Sgd78059 mxfep->mxfe_txdescp = (void *)kaddr; 20964978Sgd78059 20974978Sgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */ 20984978Sgd78059 mxfep->mxfe_txbufs = kmem_zalloc(MXFE_TXRING * sizeof (mxfe_txbuf_t *), 20994978Sgd78059 KM_SLEEP); 21004978Sgd78059 21014978Sgd78059 /* now allocate tx buffers */ 21024978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) { 21034978Sgd78059 mxfe_txbuf_t *txb = mxfe_alloctxbuf(mxfep); 21044978Sgd78059 if (txb == NULL) 21054978Sgd78059 return (DDI_FAILURE); 21064978Sgd78059 /* stick it in the stack */ 21074978Sgd78059 mxfep->mxfe_txbufs[i] = txb; 21084978Sgd78059 } 21094978Sgd78059 21104978Sgd78059 return (DDI_SUCCESS); 21114978Sgd78059 } 21124978Sgd78059 21134978Sgd78059 void 21144978Sgd78059 mxfe_freerxring(mxfe_t *mxfep) 21154978Sgd78059 { 21164978Sgd78059 int i; 21174978Sgd78059 21184978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) { 21194978Sgd78059 mxfe_destroyrxbuf(mxfep->mxfe_rxbufs[i]); 21204978Sgd78059 } 21214978Sgd78059 21224978Sgd78059 if (mxfep->mxfe_rxbufs) { 21234978Sgd78059 kmem_free(mxfep->mxfe_rxbufs, 21244978Sgd78059 MXFE_RXRING * sizeof (mxfe_rxbuf_t *)); 21254978Sgd78059 } 21264978Sgd78059 21274978Sgd78059 if (mxfep->mxfe_rxdesc_paddr) 21284978Sgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_rxdesc_dmah); 21294978Sgd78059 if (mxfep->mxfe_rxdesc_acch) 21304978Sgd78059 ddi_dma_mem_free(&mxfep->mxfe_rxdesc_acch); 21314978Sgd78059 if (mxfep->mxfe_rxdesc_dmah) 21324978Sgd78059 ddi_dma_free_handle(&mxfep->mxfe_rxdesc_dmah); 21334978Sgd78059 } 21344978Sgd78059 21354978Sgd78059 void 21364978Sgd78059 mxfe_freetxring(mxfe_t *mxfep) 21374978Sgd78059 { 21384978Sgd78059 int i; 21394978Sgd78059 21404978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) { 21414978Sgd78059 mxfe_destroytxbuf(mxfep->mxfe_txbufs[i]); 21424978Sgd78059 } 21434978Sgd78059 21444978Sgd78059 if (mxfep->mxfe_txbufs) { 21454978Sgd78059 kmem_free(mxfep->mxfe_txbufs, 21464978Sgd78059 MXFE_TXRING * sizeof (mxfe_txbuf_t *)); 21474978Sgd78059 } 21484978Sgd78059 if (mxfep->mxfe_txdesc_paddr) 21494978Sgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_txdesc_dmah); 21504978Sgd78059 if (mxfep->mxfe_txdesc_acch) 21514978Sgd78059 ddi_dma_mem_free(&mxfep->mxfe_txdesc_acch); 21524978Sgd78059 if (mxfep->mxfe_txdesc_dmah) 21534978Sgd78059 ddi_dma_free_handle(&mxfep->mxfe_txdesc_dmah); 21544978Sgd78059 } 21554978Sgd78059 21564978Sgd78059 /* 21574978Sgd78059 * Interrupt service routine. 21584978Sgd78059 */ 21594978Sgd78059 unsigned 21604978Sgd78059 mxfe_intr(caddr_t arg) 21614978Sgd78059 { 21624978Sgd78059 mxfe_t *mxfep = (void *)arg; 21634978Sgd78059 uint32_t status; 21644978Sgd78059 mblk_t *mp = NULL; 2165*9199Sgdamore@opensolaris.org boolean_t error = B_FALSE; 21664978Sgd78059 21674978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 21684978Sgd78059 21694978Sgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) { 21704978Sgd78059 /* we cannot receive interrupts! */ 21714978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 21724978Sgd78059 return (DDI_INTR_UNCLAIMED); 21734978Sgd78059 } 21744978Sgd78059 21754978Sgd78059 /* check interrupt status bits, did we interrupt? */ 21764978Sgd78059 status = GETCSR(mxfep, CSR_SR) & INT_ALL; 21774978Sgd78059 21784978Sgd78059 if (status == 0) { 21794978Sgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 21804978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 21814978Sgd78059 return (DDI_INTR_UNCLAIMED); 21824978Sgd78059 } 21834978Sgd78059 /* ack the interrupt */ 21844978Sgd78059 PUTCSR(mxfep, CSR_SR, status); 21854978Sgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++; 21864978Sgd78059 21874978Sgd78059 if (!(mxfep->mxfe_flags & MXFE_RUNNING)) { 21884978Sgd78059 /* not running, don't touch anything */ 21894978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 21904978Sgd78059 return (DDI_INTR_CLAIMED); 21914978Sgd78059 } 21924978Sgd78059 21934978Sgd78059 if (status & INT_RXOK) { 21944978Sgd78059 /* receive packets */ 2195*9199Sgdamore@opensolaris.org if (mxfe_receive(mxfep, &mp)) { 2196*9199Sgdamore@opensolaris.org error = B_TRUE; 2197*9199Sgdamore@opensolaris.org } 21984978Sgd78059 } 21994978Sgd78059 22004978Sgd78059 if (status & INT_TXOK) { 22014978Sgd78059 /* transmit completed */ 22024978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 22034978Sgd78059 mxfe_reclaim(mxfep); 22044978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 22054978Sgd78059 } 22064978Sgd78059 22074978Sgd78059 if (((status & (INT_TIMER|INT_ANEG)) != 0) || 22084978Sgd78059 ((mxfep->mxfe_linkup == LINK_STATE_UP) && 22094978Sgd78059 ((status & (INT_10LINK|INT_100LINK)) != 0))) { 22104978Sgd78059 /* rescan the link */ 22114978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 22124978Sgd78059 mxfe_checklink(mxfep); 22134978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 22144978Sgd78059 } 22154978Sgd78059 22164978Sgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED|INT_RXNOBUF| 22174978Sgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) { 22184978Sgd78059 22194978Sgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) { 22204978Sgd78059 mxfep->mxfe_jabber++; 22214978Sgd78059 } 2222*9199Sgdamore@opensolaris.org DBG(DWARN, "error interrupt: status %x", status); 2223*9199Sgdamore@opensolaris.org error = B_TRUE; 22244978Sgd78059 } 22254978Sgd78059 22264978Sgd78059 if (status & INT_BUSERR) { 22274978Sgd78059 switch (status & SR_BERR_TYPE) { 22284978Sgd78059 case SR_BERR_PARITY: 22294978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI parity error"); 22304978Sgd78059 break; 22314978Sgd78059 case SR_BERR_TARGET_ABORT: 22324978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI target abort"); 22334978Sgd78059 break; 22344978Sgd78059 case SR_BERR_MASTER_ABORT: 22354978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI master abort"); 22364978Sgd78059 break; 22374978Sgd78059 default: 22384978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Unknown PCI error"); 22394978Sgd78059 break; 22404978Sgd78059 } 22414978Sgd78059 2242*9199Sgdamore@opensolaris.org error = B_TRUE; 2243*9199Sgdamore@opensolaris.org } 2244*9199Sgdamore@opensolaris.org 2245*9199Sgdamore@opensolaris.org if (error) { 22464978Sgd78059 /* reset the chip in an attempt to fix things */ 22474978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 22484978Sgd78059 mxfe_resetall(mxfep); 22494978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 22504978Sgd78059 } 22514978Sgd78059 22524978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 22534978Sgd78059 22544978Sgd78059 /* 22554978Sgd78059 * Send up packets. We do this outside of the intrlock. 22564978Sgd78059 */ 22574978Sgd78059 if (mp) { 22584978Sgd78059 mac_rx(mxfep->mxfe_mh, NULL, mp); 22594978Sgd78059 } 22604978Sgd78059 22614978Sgd78059 return (DDI_INTR_CLAIMED); 22624978Sgd78059 } 22634978Sgd78059 22644978Sgd78059 void 22654978Sgd78059 mxfe_enableinterrupts(mxfe_t *mxfep) 22664978Sgd78059 { 22674978Sgd78059 unsigned mask = INT_WANTED; 22684978Sgd78059 22694978Sgd78059 if (mxfep->mxfe_wantw) 22704978Sgd78059 mask |= INT_TXOK; 22714978Sgd78059 22724978Sgd78059 if (MXFE_MODEL(mxfep) != MXFE_98713A) 22734978Sgd78059 mask |= INT_LINKSTATUS; 22744978Sgd78059 22754978Sgd78059 DBG(DINTR, "setting int mask to 0x%x", mask); 22764978Sgd78059 PUTCSR(mxfep, CSR_IER, mask); 22774978Sgd78059 } 22784978Sgd78059 22794978Sgd78059 void 22804978Sgd78059 mxfe_disableinterrupts(mxfe_t *mxfep) 22814978Sgd78059 { 22824978Sgd78059 /* disable further interrupts */ 22834978Sgd78059 PUTCSR(mxfep, CSR_IER, 0); 22844978Sgd78059 22854978Sgd78059 /* clear any pending interrupts */ 22864978Sgd78059 PUTCSR(mxfep, CSR_SR, INT_ALL); 22874978Sgd78059 } 22884978Sgd78059 22894978Sgd78059 void 22904978Sgd78059 mxfe_send_setup(mxfe_t *mxfep) 22914978Sgd78059 { 22924978Sgd78059 mxfe_txbuf_t *txb; 22934978Sgd78059 mxfe_desc_t *tmdp; 22944978Sgd78059 22954978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 22964978Sgd78059 22974978Sgd78059 /* setup frame -- must be at head of list -- guaranteed by caller! */ 22984978Sgd78059 ASSERT(mxfep->mxfe_txsend == 0); 22994978Sgd78059 23004978Sgd78059 txb = mxfep->mxfe_txbufs[0]; 23014978Sgd78059 tmdp = &mxfep->mxfe_txdescp[0]; 23024978Sgd78059 23034978Sgd78059 bzero(txb->txb_buf, MXFE_SETUP_LEN); 23044978Sgd78059 23054978Sgd78059 /* program the unicast address */ 23064978Sgd78059 txb->txb_buf[156] = mxfep->mxfe_curraddr[0]; 23074978Sgd78059 txb->txb_buf[157] = mxfep->mxfe_curraddr[1]; 23084978Sgd78059 txb->txb_buf[160] = mxfep->mxfe_curraddr[2]; 23094978Sgd78059 txb->txb_buf[161] = mxfep->mxfe_curraddr[3]; 23104978Sgd78059 txb->txb_buf[164] = mxfep->mxfe_curraddr[4]; 23114978Sgd78059 txb->txb_buf[165] = mxfep->mxfe_curraddr[5]; 23124978Sgd78059 23134978Sgd78059 /* make sure that the hardware can see it */ 23144978Sgd78059 SYNCTXBUF(txb, MXFE_SETUP_LEN, DDI_DMA_SYNC_FORDEV); 23154978Sgd78059 23164978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_control, 23174978Sgd78059 TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE | TXCTL_HASHPERF | 23184978Sgd78059 TXCTL_SETUP | MXFE_SETUP_LEN); 23194978Sgd78059 23204978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, txb->txb_paddr); 23214978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0); 23224978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_status, TXSTAT_OWN); 23234978Sgd78059 23244978Sgd78059 /* sync the descriptor out to the device */ 23254978Sgd78059 SYNCTXDESC(mxfep, 0, DDI_DMA_SYNC_FORDEV); 23264978Sgd78059 23274978Sgd78059 /* 23284978Sgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 23294978Sgd78059 * etc. 23304978Sgd78059 */ 23314978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0); 23324978Sgd78059 mxfep->mxfe_txsend++; 23334978Sgd78059 mxfep->mxfe_txavail--; 23344978Sgd78059 23354978Sgd78059 /* 23364978Sgd78059 * Program promiscuous mode. 23374978Sgd78059 */ 23384978Sgd78059 if (mxfep->mxfe_promisc) { 23394978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 23404978Sgd78059 } else { 23414978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC); 23424978Sgd78059 } 23434978Sgd78059 } 23444978Sgd78059 23454978Sgd78059 boolean_t 23464978Sgd78059 mxfe_send(mxfe_t *mxfep, mblk_t *mp) 23474978Sgd78059 { 23484978Sgd78059 size_t len; 23494978Sgd78059 mxfe_txbuf_t *txb; 23504978Sgd78059 mxfe_desc_t *tmd; 23514978Sgd78059 uint32_t control; 23524978Sgd78059 int txsend; 23534978Sgd78059 23544978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock)); 23554978Sgd78059 ASSERT(mp != NULL); 23564978Sgd78059 23574978Sgd78059 len = msgsize(mp); 23584978Sgd78059 if (len > ETHERVLANMTU) { 23594978Sgd78059 DBG(DXMIT, "frame too long: %d", len); 23604978Sgd78059 mxfep->mxfe_macxmt_errors++; 23614978Sgd78059 freemsg(mp); 23624978Sgd78059 return (B_TRUE); 23634978Sgd78059 } 23644978Sgd78059 23654978Sgd78059 if (mxfep->mxfe_txavail < MXFE_TXRECLAIM) 23664978Sgd78059 mxfe_reclaim(mxfep); 23674978Sgd78059 23684978Sgd78059 if (mxfep->mxfe_txavail == 0) { 23694978Sgd78059 /* no more tmds */ 23704978Sgd78059 mxfep->mxfe_wantw = B_TRUE; 23714978Sgd78059 /* enable TX interrupt */ 23724978Sgd78059 mxfe_enableinterrupts(mxfep); 23734978Sgd78059 return (B_FALSE); 23744978Sgd78059 } 23754978Sgd78059 23764978Sgd78059 txsend = mxfep->mxfe_txsend; 23774978Sgd78059 23784978Sgd78059 /* 23794978Sgd78059 * For simplicity, we just do a copy into a preallocated 23804978Sgd78059 * DMA buffer. 23814978Sgd78059 */ 23824978Sgd78059 23834978Sgd78059 txb = mxfep->mxfe_txbufs[txsend]; 23844978Sgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */ 23854978Sgd78059 23864978Sgd78059 /* 23874978Sgd78059 * Statistics. 23884978Sgd78059 */ 23894978Sgd78059 mxfep->mxfe_opackets++; 23904978Sgd78059 mxfep->mxfe_obytes += len; 23914978Sgd78059 if (txb->txb_buf[0] & 0x1) { 23924978Sgd78059 if (bcmp(txb->txb_buf, mxfe_broadcast, ETHERADDRL) != 0) 23934978Sgd78059 mxfep->mxfe_multixmt++; 23944978Sgd78059 else 23954978Sgd78059 mxfep->mxfe_brdcstxmt++; 23964978Sgd78059 } 23974978Sgd78059 23984978Sgd78059 /* note len is already known to be a small unsigned */ 23994978Sgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE; 24004978Sgd78059 24014978Sgd78059 if (txsend == (MXFE_TXRING - 1)) 24024978Sgd78059 control |= TXCTL_ENDRING; 24034978Sgd78059 24044978Sgd78059 tmd = &mxfep->mxfe_txdescp[txsend]; 24054978Sgd78059 24064978Sgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV); 24074978Sgd78059 PUTTXDESC(mxfep, tmd->desc_control, control); 24084978Sgd78059 PUTTXDESC(mxfep, tmd->desc_buffer1, txb->txb_paddr); 24094978Sgd78059 PUTTXDESC(mxfep, tmd->desc_buffer2, 0); 24104978Sgd78059 PUTTXDESC(mxfep, tmd->desc_status, TXSTAT_OWN); 24114978Sgd78059 /* sync the descriptor out to the device */ 24124978Sgd78059 SYNCTXDESC(mxfep, txsend, DDI_DMA_SYNC_FORDEV); 24134978Sgd78059 24144978Sgd78059 /* 24154978Sgd78059 * Note the new values of txavail and txsend. 24164978Sgd78059 */ 24174978Sgd78059 mxfep->mxfe_txavail--; 24184978Sgd78059 mxfep->mxfe_txsend = (txsend + 1) % MXFE_TXRING; 24194978Sgd78059 24204978Sgd78059 /* 24214978Sgd78059 * It should never, ever take more than 5 seconds to drain 24224978Sgd78059 * the ring. If it happens, then we are stuck! 24234978Sgd78059 */ 24244978Sgd78059 mxfep->mxfe_txstall_time = gethrtime() + (5 * 1000000000ULL); 24254978Sgd78059 24264978Sgd78059 /* 24274978Sgd78059 * wake up the chip ... inside the lock to protect against DR suspend, 24284978Sgd78059 * etc. 24294978Sgd78059 */ 24304978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0); 24314978Sgd78059 24324978Sgd78059 return (B_TRUE); 24334978Sgd78059 } 24344978Sgd78059 24354978Sgd78059 /* 24364978Sgd78059 * Reclaim buffers that have completed transmission. 24374978Sgd78059 */ 24384978Sgd78059 void 24394978Sgd78059 mxfe_reclaim(mxfe_t *mxfep) 24404978Sgd78059 { 24414978Sgd78059 mxfe_desc_t *tmdp; 24424978Sgd78059 24434978Sgd78059 while (mxfep->mxfe_txavail != MXFE_TXRING) { 24444978Sgd78059 uint32_t status; 24454978Sgd78059 uint32_t control; 24464978Sgd78059 int index = mxfep->mxfe_txreclaim; 24474978Sgd78059 24484978Sgd78059 tmdp = &mxfep->mxfe_txdescp[index]; 24494978Sgd78059 24504978Sgd78059 /* sync it before we read it */ 24514978Sgd78059 SYNCTXDESC(mxfep, index, DDI_DMA_SYNC_FORKERNEL); 24524978Sgd78059 24534978Sgd78059 control = GETTXDESC(mxfep, tmdp->desc_control); 24544978Sgd78059 status = GETTXDESC(mxfep, tmdp->desc_status); 24554978Sgd78059 24564978Sgd78059 if (status & TXSTAT_OWN) { 24574978Sgd78059 /* chip is still working on it, we're done */ 24584978Sgd78059 break; 24594978Sgd78059 } 24604978Sgd78059 24614978Sgd78059 mxfep->mxfe_txavail++; 24624978Sgd78059 mxfep->mxfe_txreclaim = (index + 1) % MXFE_TXRING; 24634978Sgd78059 24644978Sgd78059 /* in the most common successful case, all bits are clear */ 24654978Sgd78059 if (status == 0) 24664978Sgd78059 continue; 24674978Sgd78059 24684978Sgd78059 if (((control & TXCTL_SETUP) != 0) || 24694978Sgd78059 ((control & TXCTL_LAST) == 0)) { 24704978Sgd78059 /* no interesting statistics here */ 24714978Sgd78059 continue; 24724978Sgd78059 } 24734978Sgd78059 24744978Sgd78059 if (status & TXSTAT_TXERR) { 24754978Sgd78059 mxfep->mxfe_errxmt++; 24764978Sgd78059 24774978Sgd78059 if (status & TXSTAT_JABBER) { 24784978Sgd78059 /* transmit jabber timeout */ 24794978Sgd78059 mxfep->mxfe_macxmt_errors++; 24804978Sgd78059 } 24814978Sgd78059 if (status & (TXSTAT_CARRLOST | TXSTAT_NOCARR)) { 24824978Sgd78059 mxfep->mxfe_carrier_errors++; 24834978Sgd78059 } 24844978Sgd78059 if (status & TXSTAT_UFLOW) { 24854978Sgd78059 mxfep->mxfe_underflow++; 24864978Sgd78059 } 24874978Sgd78059 if (status & TXSTAT_LATECOL) { 24884978Sgd78059 mxfep->mxfe_tx_late_collisions++; 24894978Sgd78059 } 24904978Sgd78059 if (status & TXSTAT_EXCOLL) { 24914978Sgd78059 mxfep->mxfe_ex_collisions++; 24924978Sgd78059 mxfep->mxfe_collisions += 16; 24934978Sgd78059 } 24944978Sgd78059 } 24954978Sgd78059 24964978Sgd78059 if (status & TXSTAT_DEFER) { 24974978Sgd78059 mxfep->mxfe_defer_xmts++; 24984978Sgd78059 } 24994978Sgd78059 25004978Sgd78059 /* collision counting */ 25014978Sgd78059 if (TXCOLLCNT(status) == 1) { 25024978Sgd78059 mxfep->mxfe_collisions++; 25034978Sgd78059 mxfep->mxfe_first_collisions++; 25044978Sgd78059 } else if (TXCOLLCNT(status)) { 25054978Sgd78059 mxfep->mxfe_collisions += TXCOLLCNT(status); 25064978Sgd78059 mxfep->mxfe_multi_collisions += TXCOLLCNT(status); 25074978Sgd78059 } 25084978Sgd78059 } 25094978Sgd78059 25104978Sgd78059 if (mxfep->mxfe_txavail >= MXFE_TXRESCHED) { 25114978Sgd78059 if (mxfep->mxfe_wantw) { 25124978Sgd78059 /* 25134978Sgd78059 * we were able to reclaim some packets, so 25144978Sgd78059 * disable tx interrupts 25154978Sgd78059 */ 25164978Sgd78059 mxfep->mxfe_wantw = B_FALSE; 25174978Sgd78059 mxfe_enableinterrupts(mxfep); 25184978Sgd78059 mac_tx_update(mxfep->mxfe_mh); 25194978Sgd78059 } 25204978Sgd78059 } 25214978Sgd78059 } 25224978Sgd78059 2523*9199Sgdamore@opensolaris.org boolean_t 2524*9199Sgdamore@opensolaris.org mxfe_receive(mxfe_t *mxfep, mblk_t **rxchain) 25254978Sgd78059 { 25264978Sgd78059 unsigned len; 25274978Sgd78059 mxfe_rxbuf_t *rxb; 25284978Sgd78059 mxfe_desc_t *rmd; 25294978Sgd78059 uint32_t status; 25304978Sgd78059 mblk_t *mpchain, **mpp, *mp; 25314978Sgd78059 int head, cnt; 2532*9199Sgdamore@opensolaris.org boolean_t error = B_FALSE; 25334978Sgd78059 25344978Sgd78059 mpchain = NULL; 25354978Sgd78059 mpp = &mpchain; 25364978Sgd78059 head = mxfep->mxfe_rxhead; 25374978Sgd78059 25384978Sgd78059 /* limit the number of packets we process to a ring size */ 25394978Sgd78059 for (cnt = 0; cnt < MXFE_RXRING; cnt++) { 25404978Sgd78059 25414978Sgd78059 DBG(DRECV, "receive at index %d", head); 25424978Sgd78059 25434978Sgd78059 rmd = &mxfep->mxfe_rxdescp[head]; 25444978Sgd78059 rxb = mxfep->mxfe_rxbufs[head]; 25454978Sgd78059 25464978Sgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORKERNEL); 25474978Sgd78059 status = GETRXDESC(mxfep, rmd->desc_status); 25484978Sgd78059 if (status & RXSTAT_OWN) { 25494978Sgd78059 /* chip is still chewing on it */ 25504978Sgd78059 break; 25514978Sgd78059 } 25524978Sgd78059 25534978Sgd78059 /* discard the ethernet frame checksum */ 25544978Sgd78059 len = RXLENGTH(status) - ETHERFCSL; 25554978Sgd78059 25564978Sgd78059 DBG(DRECV, "recv length %d, status %x", len, status); 25574978Sgd78059 25584978Sgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) != 25594978Sgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) { 25604978Sgd78059 25614978Sgd78059 mxfep->mxfe_errrcv++; 25624978Sgd78059 25634978Sgd78059 /* 25644978Sgd78059 * Abnormal status bits detected, analyze further. 25654978Sgd78059 */ 25664978Sgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) != 25674978Sgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) { 2568*9199Sgdamore@opensolaris.org /* someone trying to send jumbo frames? */ 25694978Sgd78059 DBG(DRECV, "rx packet overspill"); 25704978Sgd78059 if (status & RXSTAT_FIRST) { 25714978Sgd78059 mxfep->mxfe_toolong_errors++; 25724978Sgd78059 } 25734978Sgd78059 } else if (status & RXSTAT_DESCERR) { 2574*9199Sgdamore@opensolaris.org /* this should never occur! */ 25754978Sgd78059 mxfep->mxfe_macrcv_errors++; 2576*9199Sgdamore@opensolaris.org error = B_TRUE; 25774978Sgd78059 25784978Sgd78059 } else if (status & RXSTAT_RUNT) { 25794978Sgd78059 mxfep->mxfe_runt++; 25804978Sgd78059 25814978Sgd78059 } else if (status & RXSTAT_COLLSEEN) { 25824978Sgd78059 /* this should really be rx_late_collisions */ 25834978Sgd78059 mxfep->mxfe_macrcv_errors++; 25844978Sgd78059 25854978Sgd78059 } else if (status & RXSTAT_DRIBBLE) { 25864978Sgd78059 mxfep->mxfe_align_errors++; 25874978Sgd78059 25884978Sgd78059 } else if (status & RXSTAT_CRCERR) { 25894978Sgd78059 mxfep->mxfe_fcs_errors++; 25904978Sgd78059 25914978Sgd78059 } else if (status & RXSTAT_OFLOW) { 2592*9199Sgdamore@opensolaris.org /* this is a MAC FIFO error, need to reset */ 25934978Sgd78059 mxfep->mxfe_overflow++; 2594*9199Sgdamore@opensolaris.org error = B_TRUE; 25954978Sgd78059 } 25964978Sgd78059 } 25974978Sgd78059 25984978Sgd78059 else if (len > ETHERVLANMTU) { 25994978Sgd78059 mxfep->mxfe_errrcv++; 26004978Sgd78059 mxfep->mxfe_toolong_errors++; 26014978Sgd78059 } 26024978Sgd78059 26034978Sgd78059 /* 26044978Sgd78059 * At this point, the chip thinks the packet is OK. 26054978Sgd78059 */ 26064978Sgd78059 else { 26074978Sgd78059 mp = allocb(len + MXFE_HEADROOM, 0); 26084978Sgd78059 if (mp == NULL) { 26094978Sgd78059 mxfep->mxfe_errrcv++; 26104978Sgd78059 mxfep->mxfe_norcvbuf++; 26114978Sgd78059 goto skip; 26124978Sgd78059 } 26134978Sgd78059 26144978Sgd78059 /* sync the buffer before we look at it */ 26154978Sgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL); 26164978Sgd78059 mp->b_rptr += MXFE_HEADROOM; 26174978Sgd78059 mp->b_wptr = mp->b_rptr + len; 26184978Sgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len); 26194978Sgd78059 26204978Sgd78059 mxfep->mxfe_ipackets++; 26214978Sgd78059 mxfep->mxfe_rbytes += len; 26224978Sgd78059 if (status & RXSTAT_GROUP) { 26234978Sgd78059 if (bcmp(mp->b_rptr, mxfe_broadcast, 26244978Sgd78059 ETHERADDRL) == 0) 26254978Sgd78059 mxfep->mxfe_brdcstrcv++; 26264978Sgd78059 else 26274978Sgd78059 mxfep->mxfe_multircv++; 26284978Sgd78059 } 26294978Sgd78059 *mpp = mp; 26304978Sgd78059 mpp = &mp->b_next; 26314978Sgd78059 } 26324978Sgd78059 26334978Sgd78059 skip: 26344978Sgd78059 /* return ring entry to the hardware */ 26354978Sgd78059 PUTRXDESC(mxfep, rmd->desc_status, RXSTAT_OWN); 26364978Sgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORDEV); 26374978Sgd78059 26384978Sgd78059 /* advance to next RMD */ 26394978Sgd78059 head = (head + 1) % MXFE_RXRING; 26404978Sgd78059 } 26414978Sgd78059 26424978Sgd78059 mxfep->mxfe_rxhead = head; 26434978Sgd78059 2644*9199Sgdamore@opensolaris.org *rxchain = mpchain; 2645*9199Sgdamore@opensolaris.org return (error); 26464978Sgd78059 } 26474978Sgd78059 26484978Sgd78059 int 26494978Sgd78059 mxfe_m_stat(void *arg, uint_t stat, uint64_t *val) 26504978Sgd78059 { 26514978Sgd78059 mxfe_t *mxfep = arg; 26524978Sgd78059 26534978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 26544978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == MXFE_RUNNING) 26554978Sgd78059 mxfe_reclaim(mxfep); 26564978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 26574978Sgd78059 26584978Sgd78059 switch (stat) { 26594978Sgd78059 case MAC_STAT_IFSPEED: 26604978Sgd78059 *val = mxfep->mxfe_ifspeed; 26614978Sgd78059 break; 26624978Sgd78059 26634978Sgd78059 case MAC_STAT_MULTIRCV: 26644978Sgd78059 *val = mxfep->mxfe_multircv; 26654978Sgd78059 break; 26664978Sgd78059 26674978Sgd78059 case MAC_STAT_BRDCSTRCV: 26684978Sgd78059 *val = mxfep->mxfe_brdcstrcv; 26694978Sgd78059 break; 26704978Sgd78059 26714978Sgd78059 case MAC_STAT_MULTIXMT: 26724978Sgd78059 *val = mxfep->mxfe_multixmt; 26734978Sgd78059 break; 26744978Sgd78059 26754978Sgd78059 case MAC_STAT_BRDCSTXMT: 26764978Sgd78059 *val = mxfep->mxfe_brdcstxmt; 26774978Sgd78059 break; 26784978Sgd78059 26794978Sgd78059 case MAC_STAT_IPACKETS: 26804978Sgd78059 *val = mxfep->mxfe_ipackets; 26814978Sgd78059 break; 26824978Sgd78059 26834978Sgd78059 case MAC_STAT_RBYTES: 26844978Sgd78059 *val = mxfep->mxfe_rbytes; 26854978Sgd78059 break; 26864978Sgd78059 26874978Sgd78059 case MAC_STAT_OPACKETS: 26884978Sgd78059 *val = mxfep->mxfe_opackets; 26894978Sgd78059 break; 26904978Sgd78059 26914978Sgd78059 case MAC_STAT_OBYTES: 26924978Sgd78059 *val = mxfep->mxfe_obytes; 26934978Sgd78059 break; 26944978Sgd78059 26954978Sgd78059 case MAC_STAT_NORCVBUF: 26964978Sgd78059 *val = mxfep->mxfe_norcvbuf; 26974978Sgd78059 break; 26984978Sgd78059 26994978Sgd78059 case MAC_STAT_NOXMTBUF: 27004978Sgd78059 *val = mxfep->mxfe_noxmtbuf; 27014978Sgd78059 break; 27024978Sgd78059 27034978Sgd78059 case MAC_STAT_COLLISIONS: 27044978Sgd78059 *val = mxfep->mxfe_collisions; 27054978Sgd78059 break; 27064978Sgd78059 27074978Sgd78059 case MAC_STAT_IERRORS: 27084978Sgd78059 *val = mxfep->mxfe_errrcv; 27094978Sgd78059 break; 27104978Sgd78059 27114978Sgd78059 case MAC_STAT_OERRORS: 27124978Sgd78059 *val = mxfep->mxfe_errxmt; 27134978Sgd78059 break; 27144978Sgd78059 27154978Sgd78059 case ETHER_STAT_LINK_DUPLEX: 27164978Sgd78059 *val = mxfep->mxfe_duplex; 27174978Sgd78059 break; 27184978Sgd78059 27194978Sgd78059 case ETHER_STAT_ALIGN_ERRORS: 27204978Sgd78059 *val = mxfep->mxfe_align_errors; 27214978Sgd78059 break; 27224978Sgd78059 27234978Sgd78059 case ETHER_STAT_FCS_ERRORS: 27244978Sgd78059 *val = mxfep->mxfe_fcs_errors; 27254978Sgd78059 break; 27264978Sgd78059 27274978Sgd78059 case ETHER_STAT_SQE_ERRORS: 27284978Sgd78059 *val = mxfep->mxfe_sqe_errors; 27294978Sgd78059 break; 27304978Sgd78059 27314978Sgd78059 case ETHER_STAT_DEFER_XMTS: 27324978Sgd78059 *val = mxfep->mxfe_defer_xmts; 27334978Sgd78059 break; 27344978Sgd78059 27354978Sgd78059 case ETHER_STAT_FIRST_COLLISIONS: 27364978Sgd78059 *val = mxfep->mxfe_first_collisions; 27374978Sgd78059 break; 27384978Sgd78059 27394978Sgd78059 case ETHER_STAT_MULTI_COLLISIONS: 27404978Sgd78059 *val = mxfep->mxfe_multi_collisions; 27414978Sgd78059 break; 27424978Sgd78059 27434978Sgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 27444978Sgd78059 *val = mxfep->mxfe_tx_late_collisions; 27454978Sgd78059 break; 27464978Sgd78059 27474978Sgd78059 case ETHER_STAT_EX_COLLISIONS: 27484978Sgd78059 *val = mxfep->mxfe_ex_collisions; 27494978Sgd78059 break; 27504978Sgd78059 27514978Sgd78059 case ETHER_STAT_MACXMT_ERRORS: 27524978Sgd78059 *val = mxfep->mxfe_macxmt_errors; 27534978Sgd78059 break; 27544978Sgd78059 27554978Sgd78059 case ETHER_STAT_CARRIER_ERRORS: 27564978Sgd78059 *val = mxfep->mxfe_carrier_errors; 27574978Sgd78059 break; 27584978Sgd78059 27594978Sgd78059 case ETHER_STAT_TOOLONG_ERRORS: 27604978Sgd78059 *val = mxfep->mxfe_toolong_errors; 27614978Sgd78059 break; 27624978Sgd78059 27634978Sgd78059 case ETHER_STAT_MACRCV_ERRORS: 27644978Sgd78059 *val = mxfep->mxfe_macrcv_errors; 27654978Sgd78059 break; 27664978Sgd78059 27674978Sgd78059 case MAC_STAT_OVERFLOWS: 27684978Sgd78059 *val = mxfep->mxfe_overflow; 27694978Sgd78059 break; 27704978Sgd78059 27714978Sgd78059 case MAC_STAT_UNDERFLOWS: 27724978Sgd78059 *val = mxfep->mxfe_underflow; 27734978Sgd78059 break; 27744978Sgd78059 27754978Sgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 27764978Sgd78059 *val = mxfep->mxfe_runt; 27774978Sgd78059 break; 27784978Sgd78059 27794978Sgd78059 case ETHER_STAT_JABBER_ERRORS: 27804978Sgd78059 *val = mxfep->mxfe_jabber; 27814978Sgd78059 break; 27824978Sgd78059 27834978Sgd78059 case ETHER_STAT_ADV_CAP_100T4: 27844978Sgd78059 *val = mxfep->mxfe_adv_100T4; 27854978Sgd78059 break; 27864978Sgd78059 27874978Sgd78059 case ETHER_STAT_LP_CAP_100T4: 27884978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_T4) ? 1 : 0; 27894978Sgd78059 break; 27904978Sgd78059 27916684Sgd78059 case ETHER_STAT_CAP_100T4: 27926684Sgd78059 *val = mxfep->mxfe_cap_100T4; 27936684Sgd78059 break; 27946684Sgd78059 27954978Sgd78059 case ETHER_STAT_CAP_100FDX: 27966684Sgd78059 *val = mxfep->mxfe_cap_100fdx; 27974978Sgd78059 break; 27984978Sgd78059 27994978Sgd78059 case ETHER_STAT_CAP_100HDX: 28006684Sgd78059 *val = mxfep->mxfe_cap_100hdx; 28014978Sgd78059 break; 28024978Sgd78059 28034978Sgd78059 case ETHER_STAT_CAP_10FDX: 28046684Sgd78059 *val = mxfep->mxfe_cap_10fdx; 28054978Sgd78059 break; 28064978Sgd78059 28074978Sgd78059 case ETHER_STAT_CAP_10HDX: 28086684Sgd78059 *val = mxfep->mxfe_cap_10hdx; 28094978Sgd78059 break; 28104978Sgd78059 28114978Sgd78059 case ETHER_STAT_CAP_AUTONEG: 28126684Sgd78059 *val = mxfep->mxfe_cap_aneg; 28134978Sgd78059 break; 28144978Sgd78059 28154978Sgd78059 case ETHER_STAT_LINK_AUTONEG: 28164978Sgd78059 *val = ((mxfep->mxfe_adv_aneg != 0) && 28174978Sgd78059 ((mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) != 0)); 28184978Sgd78059 break; 28194978Sgd78059 28204978Sgd78059 case ETHER_STAT_ADV_CAP_100FDX: 28214978Sgd78059 *val = mxfep->mxfe_adv_100fdx; 28224978Sgd78059 break; 28234978Sgd78059 28244978Sgd78059 case ETHER_STAT_ADV_CAP_100HDX: 28254978Sgd78059 *val = mxfep->mxfe_adv_100hdx; 28264978Sgd78059 break; 28274978Sgd78059 28284978Sgd78059 case ETHER_STAT_ADV_CAP_10FDX: 28294978Sgd78059 *val = mxfep->mxfe_adv_10fdx; 28304978Sgd78059 break; 28314978Sgd78059 28324978Sgd78059 case ETHER_STAT_ADV_CAP_10HDX: 28334978Sgd78059 *val = mxfep->mxfe_adv_10hdx; 28344978Sgd78059 break; 28354978Sgd78059 28364978Sgd78059 case ETHER_STAT_ADV_CAP_AUTONEG: 28374978Sgd78059 *val = mxfep->mxfe_adv_aneg; 28384978Sgd78059 break; 28394978Sgd78059 28404978Sgd78059 case ETHER_STAT_LP_CAP_100FDX: 28414978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX_FD) ? 1 : 0; 28424978Sgd78059 break; 28434978Sgd78059 28444978Sgd78059 case ETHER_STAT_LP_CAP_100HDX: 28454978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX) ? 1 : 0; 28464978Sgd78059 break; 28474978Sgd78059 28484978Sgd78059 case ETHER_STAT_LP_CAP_10FDX: 28494978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T_FD) ? 1 : 0; 28504978Sgd78059 break; 28514978Sgd78059 28524978Sgd78059 case ETHER_STAT_LP_CAP_10HDX: 28534978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T) ? 1 : 0; 28544978Sgd78059 break; 28554978Sgd78059 28564978Sgd78059 case ETHER_STAT_LP_CAP_AUTONEG: 28574978Sgd78059 *val = (mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) ? 1 : 0; 28584978Sgd78059 break; 28594978Sgd78059 28604978Sgd78059 case ETHER_STAT_XCVR_ADDR: 28614978Sgd78059 *val = mxfep->mxfe_phyaddr; 28624978Sgd78059 break; 28634978Sgd78059 28644978Sgd78059 case ETHER_STAT_XCVR_ID: 28654978Sgd78059 *val = mxfep->mxfe_phyid; 28664978Sgd78059 break; 28674978Sgd78059 28684978Sgd78059 case ETHER_STAT_XCVR_INUSE: 28694978Sgd78059 *val = mxfep->mxfe_phyinuse; 28704978Sgd78059 break; 28714978Sgd78059 28724978Sgd78059 default: 28734978Sgd78059 return (ENOTSUP); 28744978Sgd78059 } 28754978Sgd78059 return (0); 28764978Sgd78059 } 28774978Sgd78059 28786684Sgd78059 /*ARGSUSED*/ 28796684Sgd78059 int 28806684Sgd78059 mxfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 28818118SVasumathi.Sundaram@Sun.COM uint_t sz, void *val, uint_t *perm) 28824978Sgd78059 { 28836684Sgd78059 mxfe_t *mxfep = arg; 28846684Sgd78059 int err = 0; 28856789Sam223141 boolean_t dfl = flags & MAC_PROP_DEFAULT; 28866684Sgd78059 28876684Sgd78059 if (sz == 0) 28886684Sgd78059 return (EINVAL); 28896684Sgd78059 28908118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 28916684Sgd78059 switch (num) { 28926789Sam223141 case MAC_PROP_DUPLEX: 28938118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 28946684Sgd78059 if (sz >= sizeof (link_duplex_t)) { 28956684Sgd78059 bcopy(&mxfep->mxfe_duplex, val, 28966684Sgd78059 sizeof (link_duplex_t)); 28976684Sgd78059 } else { 28986684Sgd78059 err = EINVAL; 28996684Sgd78059 } 29006684Sgd78059 break; 29016684Sgd78059 29026789Sam223141 case MAC_PROP_SPEED: 29038118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29046684Sgd78059 if (sz >= sizeof (uint64_t)) { 29056684Sgd78059 bcopy(&mxfep->mxfe_ifspeed, val, sizeof (uint64_t)); 29066684Sgd78059 } else { 29076684Sgd78059 err = EINVAL; 29086684Sgd78059 } 29096684Sgd78059 break; 29106684Sgd78059 29116789Sam223141 case MAC_PROP_AUTONEG: 29126684Sgd78059 *(uint8_t *)val = 29136684Sgd78059 dfl ? mxfep->mxfe_cap_aneg : mxfep->mxfe_adv_aneg; 29146684Sgd78059 break; 29156684Sgd78059 29166789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 29178118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29188118SVasumathi.Sundaram@Sun.COM *(uint8_t *)val = 29198118SVasumathi.Sundaram@Sun.COM dfl ? mxfep->mxfe_cap_100fdx : mxfep->mxfe_adv_100fdx; 29208118SVasumathi.Sundaram@Sun.COM break; 29216789Sam223141 case MAC_PROP_EN_100FDX_CAP: 29226684Sgd78059 *(uint8_t *)val = 29236684Sgd78059 dfl ? mxfep->mxfe_cap_100fdx : mxfep->mxfe_adv_100fdx; 29246684Sgd78059 break; 29256684Sgd78059 29266789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 29278118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29288118SVasumathi.Sundaram@Sun.COM *(uint8_t *)val = 29298118SVasumathi.Sundaram@Sun.COM dfl ? mxfep->mxfe_cap_100hdx : mxfep->mxfe_adv_100hdx; 29308118SVasumathi.Sundaram@Sun.COM break; 29316789Sam223141 case MAC_PROP_EN_100HDX_CAP: 29326684Sgd78059 *(uint8_t *)val = 29336684Sgd78059 dfl ? mxfep->mxfe_cap_100hdx : mxfep->mxfe_adv_100hdx; 29346684Sgd78059 break; 29356684Sgd78059 29366789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 29378118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29388118SVasumathi.Sundaram@Sun.COM *(uint8_t *)val = 29398118SVasumathi.Sundaram@Sun.COM dfl ? mxfep->mxfe_cap_10fdx : mxfep->mxfe_adv_10fdx; 29408118SVasumathi.Sundaram@Sun.COM break; 29416789Sam223141 case MAC_PROP_EN_10FDX_CAP: 29426684Sgd78059 *(uint8_t *)val = 29436684Sgd78059 dfl ? mxfep->mxfe_cap_10fdx : mxfep->mxfe_adv_10fdx; 29446684Sgd78059 break; 29456684Sgd78059 29466789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 29478118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29488118SVasumathi.Sundaram@Sun.COM *(uint8_t *)val = 29498118SVasumathi.Sundaram@Sun.COM dfl ? mxfep->mxfe_cap_10hdx : mxfep->mxfe_adv_10hdx; 29508118SVasumathi.Sundaram@Sun.COM break; 29516789Sam223141 case MAC_PROP_EN_10HDX_CAP: 29526684Sgd78059 *(uint8_t *)val = 29536684Sgd78059 dfl ? mxfep->mxfe_cap_10hdx : mxfep->mxfe_adv_10hdx; 29546684Sgd78059 break; 29556684Sgd78059 29566789Sam223141 case MAC_PROP_ADV_100T4_CAP: 29578118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 29588118SVasumathi.Sundaram@Sun.COM *(uint8_t *)val = 29598118SVasumathi.Sundaram@Sun.COM dfl ? mxfep->mxfe_cap_100T4 : mxfep->mxfe_adv_100T4; 29608118SVasumathi.Sundaram@Sun.COM break; 29616789Sam223141 case MAC_PROP_EN_100T4_CAP: 29626684Sgd78059 *(uint8_t *)val = 29636684Sgd78059 dfl ? mxfep->mxfe_cap_100T4 : mxfep->mxfe_adv_100T4; 29646684Sgd78059 break; 29656684Sgd78059 29666684Sgd78059 default: 29676684Sgd78059 err = ENOTSUP; 29684978Sgd78059 } 29696684Sgd78059 29706684Sgd78059 return (err); 29714978Sgd78059 } 29724978Sgd78059 29734978Sgd78059 /*ARGSUSED*/ 29744978Sgd78059 int 29756684Sgd78059 mxfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 29766684Sgd78059 const void *val) 29774978Sgd78059 { 29786684Sgd78059 mxfe_t *mxfep = arg; 29796684Sgd78059 uint8_t *advp; 29806684Sgd78059 uint8_t *capp; 29816684Sgd78059 29826684Sgd78059 switch (num) { 29836789Sam223141 case MAC_PROP_EN_100FDX_CAP: 29846684Sgd78059 advp = &mxfep->mxfe_adv_100fdx; 29856684Sgd78059 capp = &mxfep->mxfe_cap_100fdx; 29866684Sgd78059 break; 29876684Sgd78059 29886789Sam223141 case MAC_PROP_EN_100HDX_CAP: 29896684Sgd78059 advp = &mxfep->mxfe_adv_100hdx; 29906684Sgd78059 capp = &mxfep->mxfe_cap_100hdx; 29916684Sgd78059 break; 29926684Sgd78059 29936789Sam223141 case MAC_PROP_EN_10FDX_CAP: 29946684Sgd78059 advp = &mxfep->mxfe_adv_10fdx; 29956684Sgd78059 capp = &mxfep->mxfe_cap_10fdx; 29966684Sgd78059 break; 29976684Sgd78059 29986789Sam223141 case MAC_PROP_EN_10HDX_CAP: 29996684Sgd78059 advp = &mxfep->mxfe_adv_10hdx; 30006684Sgd78059 capp = &mxfep->mxfe_cap_10hdx; 30016684Sgd78059 break; 30026684Sgd78059 30036789Sam223141 case MAC_PROP_EN_100T4_CAP: 30046684Sgd78059 advp = &mxfep->mxfe_adv_100T4; 30056684Sgd78059 capp = &mxfep->mxfe_cap_100T4; 30066684Sgd78059 break; 30076684Sgd78059 30086789Sam223141 case MAC_PROP_AUTONEG: 30096684Sgd78059 advp = &mxfep->mxfe_adv_aneg; 30106684Sgd78059 capp = &mxfep->mxfe_cap_aneg; 30116684Sgd78059 break; 30126684Sgd78059 30136684Sgd78059 default: 30146684Sgd78059 return (ENOTSUP); 30156684Sgd78059 } 30166684Sgd78059 30176684Sgd78059 if (*capp == 0) /* ensure phy can support value */ 30186684Sgd78059 return (ENOTSUP); 30194978Sgd78059 30204978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock); 30214978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock); 30224978Sgd78059 30236684Sgd78059 if (*advp != *(const uint8_t *)val) { 30246684Sgd78059 *advp = *(const uint8_t *)val; 30256684Sgd78059 30264978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == 30274978Sgd78059 MXFE_RUNNING) { 30284978Sgd78059 /* 30294978Sgd78059 * This re-initializes the phy, but it also 30304978Sgd78059 * restarts transmit and receive rings. 30314978Sgd78059 * Needless to say, changing the link 30324978Sgd78059 * parameters is destructive to traffic in 30334978Sgd78059 * progress. 30344978Sgd78059 */ 30354978Sgd78059 mxfe_resetall(mxfep); 30364978Sgd78059 } 30374978Sgd78059 } 30384978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock); 30394978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock); 30404978Sgd78059 30414978Sgd78059 return (0); 30424978Sgd78059 } 30434978Sgd78059 30444978Sgd78059 /* 30454978Sgd78059 * Debugging and error reporting. 30464978Sgd78059 */ 30474978Sgd78059 void 30484978Sgd78059 mxfe_error(dev_info_t *dip, char *fmt, ...) 30494978Sgd78059 { 30504978Sgd78059 va_list ap; 30514978Sgd78059 char buf[256]; 30524978Sgd78059 30534978Sgd78059 va_start(ap, fmt); 30544978Sgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 30554978Sgd78059 va_end(ap); 30564978Sgd78059 30574978Sgd78059 if (dip) { 30584978Sgd78059 cmn_err(CE_WARN, "%s%d: %s", 30594978Sgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf); 30604978Sgd78059 } else { 30614978Sgd78059 cmn_err(CE_WARN, "mxfe: %s", buf); 30624978Sgd78059 } 30634978Sgd78059 } 30644978Sgd78059 30654978Sgd78059 #ifdef DEBUG 30664978Sgd78059 30674978Sgd78059 void 30684978Sgd78059 mxfe_dprintf(mxfe_t *mxfep, const char *func, int level, char *fmt, ...) 30694978Sgd78059 { 30704978Sgd78059 va_list ap; 30714978Sgd78059 30724978Sgd78059 va_start(ap, fmt); 30734978Sgd78059 if (mxfe_debug & level) { 30744978Sgd78059 char tag[64]; 30754978Sgd78059 char buf[256]; 30764978Sgd78059 30774978Sgd78059 if (mxfep && mxfep->mxfe_dip) { 30784978Sgd78059 (void) snprintf(tag, sizeof (tag), 30794978Sgd78059 "%s%d", ddi_driver_name(mxfep->mxfe_dip), 30804978Sgd78059 ddi_get_instance(mxfep->mxfe_dip)); 30814978Sgd78059 } else { 30824978Sgd78059 (void) snprintf(tag, sizeof (tag), "mxfe"); 30834978Sgd78059 } 30844978Sgd78059 30854978Sgd78059 (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", tag, 30864978Sgd78059 func, fmt); 30874978Sgd78059 30884978Sgd78059 vcmn_err(CE_CONT, buf, ap); 30894978Sgd78059 } 30904978Sgd78059 va_end(ap); 30914978Sgd78059 } 30924978Sgd78059 30934978Sgd78059 #endif 3094