1b3697b90SSteven Stallion /* 2b3697b90SSteven Stallion * Copyright (c) 2010 Steven Stallion. All rights reserved. 3b3697b90SSteven Stallion * 4b3697b90SSteven Stallion * Redistribution and use in source and binary forms, with or without 5b3697b90SSteven Stallion * modification, are permitted provided that the following conditions are 6b3697b90SSteven Stallion * met: 7b3697b90SSteven Stallion * 8b3697b90SSteven Stallion * 1. Redistributions of source code must retain the above copyright 9b3697b90SSteven Stallion * notice, this list of conditions and the following disclaimer. 10b3697b90SSteven Stallion * 2. Redistributions in binary form must reproduce the above 11b3697b90SSteven Stallion * copyright notice, this list of conditions and the following 12b3697b90SSteven Stallion * disclaimer in the documentation and/or other materials provided 13b3697b90SSteven Stallion * with the distribution. 14b3697b90SSteven Stallion * 3. Neither the name of the copyright owner nor the names of any 15b3697b90SSteven Stallion * contributors may be used to endorse or promote products derived 16b3697b90SSteven Stallion * from this software without specific prior written permission. 17b3697b90SSteven Stallion * 18b3697b90SSteven Stallion * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND 19b3697b90SSteven Stallion * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20b3697b90SSteven Stallion * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21b3697b90SSteven Stallion * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22b3697b90SSteven Stallion * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23b3697b90SSteven Stallion * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24b3697b90SSteven Stallion * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25b3697b90SSteven Stallion * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26b3697b90SSteven Stallion * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27b3697b90SSteven Stallion * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28b3697b90SSteven Stallion * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29b3697b90SSteven Stallion */ 30b3697b90SSteven Stallion 31b3697b90SSteven Stallion #include <sys/byteorder.h> 32b3697b90SSteven Stallion #include <sys/types.h> 33b3697b90SSteven Stallion #include <sys/errno.h> 34b3697b90SSteven Stallion #include <sys/varargs.h> 35b3697b90SSteven Stallion #include <sys/cmn_err.h> 36b3697b90SSteven Stallion #include <sys/note.h> 37b3697b90SSteven Stallion #include <sys/kmem.h> 38b3697b90SSteven Stallion #include <sys/conf.h> 39b3697b90SSteven Stallion #include <sys/devops.h> 40b3697b90SSteven Stallion #include <sys/modctl.h> 41b3697b90SSteven Stallion #include <sys/sysmacros.h> 42b3697b90SSteven Stallion #include <sys/ddi.h> 43b3697b90SSteven Stallion #include <sys/ddi_intr.h> 44b3697b90SSteven Stallion #include <sys/sunddi.h> 45b3697b90SSteven Stallion #include <sys/stream.h> 46b3697b90SSteven Stallion #include <sys/strsun.h> 47b3697b90SSteven Stallion #include <sys/pci.h> 48b3697b90SSteven Stallion #include <sys/ethernet.h> 49b3697b90SSteven Stallion #include <sys/vlan.h> 50b3697b90SSteven Stallion #include <sys/crc32.h> 51b3697b90SSteven Stallion #include <sys/mii.h> 52b3697b90SSteven Stallion #include <sys/mac.h> 53b3697b90SSteven Stallion #include <sys/mac_ether.h> 54b3697b90SSteven Stallion #include <sys/mac_provider.h> 55b3697b90SSteven Stallion 56b3697b90SSteven Stallion #include "efe.h" 57b3697b90SSteven Stallion 58b3697b90SSteven Stallion /* Autoconfiguration entry points */ 59b3697b90SSteven Stallion static int efe_attach(dev_info_t *, ddi_attach_cmd_t); 60b3697b90SSteven Stallion static int efe_detach(dev_info_t *, ddi_detach_cmd_t); 61b3697b90SSteven Stallion static int efe_quiesce(dev_info_t *); 62b3697b90SSteven Stallion 63b3697b90SSteven Stallion /* MII entry points */ 64b3697b90SSteven Stallion static uint16_t efe_mii_read(void *, uint8_t, uint8_t); 65b3697b90SSteven Stallion static void efe_mii_write(void *, uint8_t, uint8_t, uint16_t); 66b3697b90SSteven Stallion static void efe_mii_notify(void *, link_state_t); 67b3697b90SSteven Stallion 68b3697b90SSteven Stallion /* MAC entry points */ 69b3697b90SSteven Stallion static int efe_m_getstat(void *, uint_t, uint64_t *); 70b3697b90SSteven Stallion static int efe_m_start(void *); 71b3697b90SSteven Stallion static void efe_m_stop(void *); 72b3697b90SSteven Stallion static int efe_m_setpromisc(void *, boolean_t); 73b3697b90SSteven Stallion static int efe_m_multicst(void *, boolean_t, const uint8_t *); 74b3697b90SSteven Stallion static int efe_m_unicst(void *, const uint8_t *); 75b3697b90SSteven Stallion static mblk_t *efe_m_tx(void *, mblk_t *); 76b3697b90SSteven Stallion static int efe_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 77b3697b90SSteven Stallion const void *); 78b3697b90SSteven Stallion static int efe_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 79b3697b90SSteven Stallion void *); 80b3697b90SSteven Stallion static void efe_m_propinfo(void *, const char *, mac_prop_id_t, 81b3697b90SSteven Stallion mac_prop_info_handle_t); 82b3697b90SSteven Stallion 83b3697b90SSteven Stallion /* ISR/periodic callbacks */ 84b3697b90SSteven Stallion static uint_t efe_intr(caddr_t, caddr_t); 85b3697b90SSteven Stallion 86b3697b90SSteven Stallion /* Support functions */ 87b3697b90SSteven Stallion static void efe_init(efe_t *); 88b3697b90SSteven Stallion static void efe_init_rx_ring(efe_t *); 89b3697b90SSteven Stallion static void efe_init_tx_ring(efe_t *); 90b3697b90SSteven Stallion static void efe_reset(efe_t *); 91b3697b90SSteven Stallion static void efe_start(efe_t *); 92b3697b90SSteven Stallion static void efe_stop(efe_t *); 93b3697b90SSteven Stallion static void efe_stop_dma(efe_t *); 94b3697b90SSteven Stallion static inline void efe_restart(efe_t *); 95b3697b90SSteven Stallion static int efe_suspend(efe_t *); 96b3697b90SSteven Stallion static int efe_resume(efe_t *); 97b3697b90SSteven Stallion 98b3697b90SSteven Stallion static efe_ring_t *efe_ring_alloc(dev_info_t *, size_t); 99b3697b90SSteven Stallion static void efe_ring_free(efe_ring_t **); 100b3697b90SSteven Stallion static efe_buf_t *efe_buf_alloc(dev_info_t *, size_t); 101b3697b90SSteven Stallion static void efe_buf_free(efe_buf_t **); 102b3697b90SSteven Stallion 103b3697b90SSteven Stallion static void efe_intr_enable(efe_t *); 104b3697b90SSteven Stallion static void efe_intr_disable(efe_t *); 105b3697b90SSteven Stallion 106b3697b90SSteven Stallion static mblk_t *efe_recv(efe_t *); 107b3697b90SSteven Stallion static mblk_t *efe_recv_pkt(efe_t *, efe_desc_t *); 108b3697b90SSteven Stallion 109b3697b90SSteven Stallion static int efe_send(efe_t *, mblk_t *); 110b3697b90SSteven Stallion static void efe_send_done(efe_t *); 111b3697b90SSteven Stallion 112b3697b90SSteven Stallion static void efe_getaddr(efe_t *, uint8_t *); 113b3697b90SSteven Stallion static void efe_setaddr(efe_t *, uint8_t *); 114b3697b90SSteven Stallion static void efe_setmchash(efe_t *, uint16_t *); 115b3697b90SSteven Stallion 116b3697b90SSteven Stallion static void efe_eeprom_read(efe_t *, uint8_t *, size_t, uint8_t); 117b3697b90SSteven Stallion static uint16_t efe_eeprom_readw(efe_t *, int, uint8_t); 118b3697b90SSteven Stallion static inline int efe_eeprom_readbit(efe_t *); 119b3697b90SSteven Stallion static inline void efe_eeprom_writebit(efe_t *, int); 120b3697b90SSteven Stallion 121b3697b90SSteven Stallion static void efe_dprintf(dev_info_t *, int, const char *, ...); 122b3697b90SSteven Stallion 123b3697b90SSteven Stallion #ifdef DEBUG 124b3697b90SSteven Stallion #define efe_debug(dip, ...) \ 125b3697b90SSteven Stallion efe_dprintf((dip), CE_CONT, __VA_ARGS__) 126b3697b90SSteven Stallion #else 127b3697b90SSteven Stallion #define efe_debug(dip, ...) /*EMPTY*/ 128b3697b90SSteven Stallion #endif 129b3697b90SSteven Stallion 130b3697b90SSteven Stallion #define efe_error(dip, ...) \ 131b3697b90SSteven Stallion efe_dprintf((dip), CE_WARN, __VA_ARGS__) 132b3697b90SSteven Stallion 133b3697b90SSteven Stallion extern struct mod_ops mod_driverops; 134b3697b90SSteven Stallion 135b3697b90SSteven Stallion DDI_DEFINE_STREAM_OPS(efe_dev_ops, nulldev, nulldev, efe_attach, efe_detach, 136b3697b90SSteven Stallion nodev, NULL, D_MP, NULL, efe_quiesce); 137b3697b90SSteven Stallion 138b3697b90SSteven Stallion static struct modldrv modldrv = { 139b3697b90SSteven Stallion &mod_driverops, /* drv_modops */ 140b3697b90SSteven Stallion "EPIC/100 Fast Ethernet", /* drv_linkinfo */ 141b3697b90SSteven Stallion &efe_dev_ops /* drv_dev_ops */ 142b3697b90SSteven Stallion }; 143b3697b90SSteven Stallion 144b3697b90SSteven Stallion static struct modlinkage modlinkage = { 145b3697b90SSteven Stallion MODREV_1, /* ml_rev */ 146b3697b90SSteven Stallion { &modldrv, NULL } /* ml_linkage */ 147b3697b90SSteven Stallion }; 148b3697b90SSteven Stallion 149b3697b90SSteven Stallion static ddi_device_acc_attr_t efe_regs_acc_attr = { 150b3697b90SSteven Stallion DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ 151b3697b90SSteven Stallion DDI_STRUCTURE_LE_ACC, /* devacc_attr_endian_flags */ 152b3697b90SSteven Stallion DDI_STRICTORDER_ACC /* devacc_attr_dataorder */ 153b3697b90SSteven Stallion }; 154b3697b90SSteven Stallion 155b3697b90SSteven Stallion static ddi_device_acc_attr_t efe_buf_acc_attr = { 156b3697b90SSteven Stallion DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ 157b3697b90SSteven Stallion DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */ 158b3697b90SSteven Stallion DDI_STRICTORDER_ACC /* devacc_attr_dataorder */ 159b3697b90SSteven Stallion }; 160b3697b90SSteven Stallion 161b3697b90SSteven Stallion static ddi_dma_attr_t efe_dma_attr = { 162b3697b90SSteven Stallion DMA_ATTR_V0, /* dma_attr_version */ 163b3697b90SSteven Stallion 0, /* dma_attr_addr_lo */ 164b3697b90SSteven Stallion 0xFFFFFFFFUL, /* dma_attr_addr_hi */ 165b3697b90SSteven Stallion 0x7FFFFFFFUL, /* dma_attr_count_max */ 166b3697b90SSteven Stallion 4, /* dma_attr_align */ 167b3697b90SSteven Stallion 0x7F, /* dma_attr_burstsizes */ 168b3697b90SSteven Stallion 1, /* dma_attr_minxfer */ 169b3697b90SSteven Stallion 0xFFFFFFFFUL, /* dma_attr_maxxfer */ 170b3697b90SSteven Stallion 0xFFFFFFFFUL, /* dma_attr_seg */ 171b3697b90SSteven Stallion 1, /* dma_attr_sgllen */ 172b3697b90SSteven Stallion 1, /* dma_attr_granular */ 173b3697b90SSteven Stallion 0 /* dma_attr_flags */ 174b3697b90SSteven Stallion }; 175b3697b90SSteven Stallion 176b3697b90SSteven Stallion static mii_ops_t efe_mii_ops = { 177b3697b90SSteven Stallion MII_OPS_VERSION, /* mii_version */ 178b3697b90SSteven Stallion efe_mii_read, /* mii_read */ 179b3697b90SSteven Stallion efe_mii_write, /* mii_write */ 180b3697b90SSteven Stallion efe_mii_notify /* mii_notify */ 181b3697b90SSteven Stallion }; 182b3697b90SSteven Stallion 183b3697b90SSteven Stallion static mac_callbacks_t efe_m_callbacks = { 184b3697b90SSteven Stallion MC_SETPROP | MC_GETPROP, /* mc_callbacks */ 185b3697b90SSteven Stallion efe_m_getstat, /* mc_getstat */ 186b3697b90SSteven Stallion efe_m_start, /* mc_start */ 187b3697b90SSteven Stallion efe_m_stop, /* mc_stop */ 188b3697b90SSteven Stallion efe_m_setpromisc, /* mc_setpromisc */ 189b3697b90SSteven Stallion efe_m_multicst, /* mc_multicst */ 190b3697b90SSteven Stallion efe_m_unicst, /* mc_unicst */ 191b3697b90SSteven Stallion efe_m_tx, /* mc_tx */ 192b3697b90SSteven Stallion NULL, /* mc_reserved */ 193b3697b90SSteven Stallion NULL, /* mc_ioctl */ 194b3697b90SSteven Stallion NULL, /* mc_getcapab */ 195b3697b90SSteven Stallion NULL, /* mc_open */ 196b3697b90SSteven Stallion NULL, /* mc_close */ 197b3697b90SSteven Stallion efe_m_setprop, /* mc_setprop */ 198b3697b90SSteven Stallion efe_m_getprop, /* mc_getprop */ 199b3697b90SSteven Stallion efe_m_propinfo /* mc_propinfo */ 200b3697b90SSteven Stallion }; 201b3697b90SSteven Stallion 202b3697b90SSteven Stallion static uint8_t efe_broadcast[] = { 203b3697b90SSteven Stallion 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 204b3697b90SSteven Stallion }; 205b3697b90SSteven Stallion 206b3697b90SSteven Stallion static uint16_t efe_mchash_promisc[] = { 207b3697b90SSteven Stallion 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF 208b3697b90SSteven Stallion }; 209b3697b90SSteven Stallion 210b3697b90SSteven Stallion /* 211b3697b90SSteven Stallion * Loadable module entry points. 212b3697b90SSteven Stallion */ 213b3697b90SSteven Stallion int 214b3697b90SSteven Stallion _init(void) 215b3697b90SSteven Stallion { 216b3697b90SSteven Stallion int error; 217b3697b90SSteven Stallion 218b3697b90SSteven Stallion mac_init_ops(&efe_dev_ops, "efe"); 219b3697b90SSteven Stallion if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) { 220b3697b90SSteven Stallion mac_fini_ops(&efe_dev_ops); 221b3697b90SSteven Stallion } 222b3697b90SSteven Stallion 223b3697b90SSteven Stallion return (error); 224b3697b90SSteven Stallion } 225b3697b90SSteven Stallion 226b3697b90SSteven Stallion int 227b3697b90SSteven Stallion _fini(void) 228b3697b90SSteven Stallion { 229b3697b90SSteven Stallion int error; 230b3697b90SSteven Stallion 231b3697b90SSteven Stallion if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) { 232b3697b90SSteven Stallion mac_fini_ops(&efe_dev_ops); 233b3697b90SSteven Stallion } 234b3697b90SSteven Stallion 235b3697b90SSteven Stallion return (error); 236b3697b90SSteven Stallion } 237b3697b90SSteven Stallion 238b3697b90SSteven Stallion int 239b3697b90SSteven Stallion _info(struct modinfo *modinfop) 240b3697b90SSteven Stallion { 241b3697b90SSteven Stallion return (mod_info(&modlinkage, modinfop)); 242b3697b90SSteven Stallion } 243b3697b90SSteven Stallion 244b3697b90SSteven Stallion /* 245b3697b90SSteven Stallion * Autoconfiguration entry points. 246b3697b90SSteven Stallion */ 247b3697b90SSteven Stallion int 248b3697b90SSteven Stallion efe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 249b3697b90SSteven Stallion { 250b3697b90SSteven Stallion ddi_acc_handle_t pci; 251b3697b90SSteven Stallion int types; 252b3697b90SSteven Stallion int count; 253b3697b90SSteven Stallion int actual; 254b3697b90SSteven Stallion uint_t pri; 255b3697b90SSteven Stallion efe_t *efep; 256b3697b90SSteven Stallion mac_register_t *macp; 257b3697b90SSteven Stallion 258b3697b90SSteven Stallion switch (cmd) { 259b3697b90SSteven Stallion case DDI_ATTACH: 260b3697b90SSteven Stallion break; 261b3697b90SSteven Stallion 262b3697b90SSteven Stallion case DDI_RESUME: 263b3697b90SSteven Stallion efep = ddi_get_driver_private(dip); 264b3697b90SSteven Stallion return (efe_resume(efep)); 265b3697b90SSteven Stallion 266b3697b90SSteven Stallion default: 267b3697b90SSteven Stallion return (DDI_FAILURE); 268b3697b90SSteven Stallion } 269b3697b90SSteven Stallion 270b3697b90SSteven Stallion /* 271b3697b90SSteven Stallion * PCI configuration. 272b3697b90SSteven Stallion */ 273b3697b90SSteven Stallion if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { 274b3697b90SSteven Stallion efe_error(dip, "unable to setup PCI configuration!"); 275b3697b90SSteven Stallion return (DDI_FAILURE); 276b3697b90SSteven Stallion } 277b3697b90SSteven Stallion 278b3697b90SSteven Stallion pci_config_put16(pci, PCI_CONF_COMM, 279b3697b90SSteven Stallion pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_MAE | PCI_COMM_ME); 280b3697b90SSteven Stallion 281b3697b90SSteven Stallion pci_config_teardown(&pci); 282b3697b90SSteven Stallion 283b3697b90SSteven Stallion if (ddi_intr_get_supported_types(dip, &types) 284b3697b90SSteven Stallion != DDI_SUCCESS || !(types & DDI_INTR_TYPE_FIXED)) { 285b3697b90SSteven Stallion efe_error(dip, "fixed interrupts not supported!"); 286b3697b90SSteven Stallion return (DDI_FAILURE); 287b3697b90SSteven Stallion } 288b3697b90SSteven Stallion 289b3697b90SSteven Stallion if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count) 290b3697b90SSteven Stallion != DDI_SUCCESS || count != 1) { 291b3697b90SSteven Stallion efe_error(dip, "no fixed interrupts available!"); 292b3697b90SSteven Stallion return (DDI_FAILURE); 293b3697b90SSteven Stallion } 294b3697b90SSteven Stallion 295b3697b90SSteven Stallion /* 296b3697b90SSteven Stallion * Initialize soft state. 297b3697b90SSteven Stallion */ 298b3697b90SSteven Stallion efep = kmem_zalloc(sizeof (efe_t), KM_SLEEP); 299b3697b90SSteven Stallion ddi_set_driver_private(dip, efep); 300b3697b90SSteven Stallion 301b3697b90SSteven Stallion efep->efe_dip = dip; 302b3697b90SSteven Stallion 303b3697b90SSteven Stallion if (ddi_regs_map_setup(dip, 1, (caddr_t *)&efep->efe_regs, 0, 0, 304b3697b90SSteven Stallion &efe_regs_acc_attr, &efep->efe_regs_acch) != DDI_SUCCESS) { 305b3697b90SSteven Stallion efe_error(dip, "unable to setup register mapping!"); 306b3697b90SSteven Stallion goto failure; 307b3697b90SSteven Stallion } 308b3697b90SSteven Stallion 309b3697b90SSteven Stallion efep->efe_rx_ring = efe_ring_alloc(efep->efe_dip, RXDESCL); 310b3697b90SSteven Stallion if (efep->efe_rx_ring == NULL) { 311b3697b90SSteven Stallion efe_error(efep->efe_dip, "unable to allocate rx ring!"); 312b3697b90SSteven Stallion goto failure; 313b3697b90SSteven Stallion } 314b3697b90SSteven Stallion 315b3697b90SSteven Stallion efep->efe_tx_ring = efe_ring_alloc(efep->efe_dip, TXDESCL); 316b3697b90SSteven Stallion if (efep->efe_tx_ring == NULL) { 317b3697b90SSteven Stallion efe_error(efep->efe_dip, "unable to allocate tx ring!"); 318b3697b90SSteven Stallion goto failure; 319b3697b90SSteven Stallion } 320b3697b90SSteven Stallion 321b3697b90SSteven Stallion if (ddi_intr_alloc(dip, &efep->efe_intrh, DDI_INTR_TYPE_FIXED, 0, 322b3697b90SSteven Stallion count, &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS || 323b3697b90SSteven Stallion actual != count) { 324b3697b90SSteven Stallion efe_error(dip, "unable to allocate fixed interrupt!"); 325b3697b90SSteven Stallion goto failure; 326b3697b90SSteven Stallion } 327b3697b90SSteven Stallion 328b3697b90SSteven Stallion if (ddi_intr_get_pri(efep->efe_intrh, &pri) != DDI_SUCCESS || 329b3697b90SSteven Stallion pri >= ddi_intr_get_hilevel_pri()) { 330b3697b90SSteven Stallion efe_error(dip, "unable to get valid interrupt priority!"); 331b3697b90SSteven Stallion goto failure; 332b3697b90SSteven Stallion } 333b3697b90SSteven Stallion 334b3697b90SSteven Stallion mutex_init(&efep->efe_intrlock, NULL, MUTEX_DRIVER, 335b3697b90SSteven Stallion DDI_INTR_PRI(pri)); 336b3697b90SSteven Stallion 337b3697b90SSteven Stallion mutex_init(&efep->efe_txlock, NULL, MUTEX_DRIVER, 338b3697b90SSteven Stallion DDI_INTR_PRI(pri)); 339b3697b90SSteven Stallion 340b3697b90SSteven Stallion /* 341b3697b90SSteven Stallion * Initialize device. 342b3697b90SSteven Stallion */ 343b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 344b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 345b3697b90SSteven Stallion 346b3697b90SSteven Stallion efe_reset(efep); 347b3697b90SSteven Stallion 348b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 349b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 350b3697b90SSteven Stallion 351b3697b90SSteven Stallion /* Use factory address as default */ 352b3697b90SSteven Stallion efe_getaddr(efep, efep->efe_macaddr); 353b3697b90SSteven Stallion 354b3697b90SSteven Stallion /* 355b3697b90SSteven Stallion * Enable the ISR. 356b3697b90SSteven Stallion */ 357b3697b90SSteven Stallion if (ddi_intr_add_handler(efep->efe_intrh, efe_intr, efep, NULL) 358b3697b90SSteven Stallion != DDI_SUCCESS) { 359b3697b90SSteven Stallion efe_error(dip, "unable to add interrupt handler!"); 360b3697b90SSteven Stallion goto failure; 361b3697b90SSteven Stallion } 362b3697b90SSteven Stallion 363b3697b90SSteven Stallion if (ddi_intr_enable(efep->efe_intrh) != DDI_SUCCESS) { 364b3697b90SSteven Stallion efe_error(dip, "unable to enable interrupt!"); 365b3697b90SSteven Stallion goto failure; 366b3697b90SSteven Stallion } 367b3697b90SSteven Stallion 368b3697b90SSteven Stallion /* 369b3697b90SSteven Stallion * Allocate MII resources. 370b3697b90SSteven Stallion */ 371b3697b90SSteven Stallion if ((efep->efe_miih = mii_alloc(efep, dip, &efe_mii_ops)) == NULL) { 372b3697b90SSteven Stallion efe_error(dip, "unable to allocate mii resources!"); 373b3697b90SSteven Stallion goto failure; 374b3697b90SSteven Stallion } 375b3697b90SSteven Stallion 376b3697b90SSteven Stallion /* 377b3697b90SSteven Stallion * Allocate MAC resources. 378b3697b90SSteven Stallion */ 379b3697b90SSteven Stallion if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 380b3697b90SSteven Stallion efe_error(dip, "unable to allocate mac resources!"); 381b3697b90SSteven Stallion goto failure; 382b3697b90SSteven Stallion } 383b3697b90SSteven Stallion 384b3697b90SSteven Stallion macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 385b3697b90SSteven Stallion macp->m_driver = efep; 386b3697b90SSteven Stallion macp->m_dip = dip; 387b3697b90SSteven Stallion macp->m_src_addr = efep->efe_macaddr; 388b3697b90SSteven Stallion macp->m_callbacks = &efe_m_callbacks; 389b3697b90SSteven Stallion macp->m_min_sdu = 0; 390b3697b90SSteven Stallion macp->m_max_sdu = ETHERMTU; 391b3697b90SSteven Stallion macp->m_margin = VLAN_TAGSZ; 392b3697b90SSteven Stallion 393b3697b90SSteven Stallion if (mac_register(macp, &efep->efe_mh) != 0) { 394b3697b90SSteven Stallion efe_error(dip, "unable to register with mac!"); 395b3697b90SSteven Stallion goto failure; 396b3697b90SSteven Stallion } 397b3697b90SSteven Stallion mac_free(macp); 398b3697b90SSteven Stallion 399b3697b90SSteven Stallion ddi_report_dev(dip); 400b3697b90SSteven Stallion 401b3697b90SSteven Stallion return (DDI_SUCCESS); 402b3697b90SSteven Stallion 403b3697b90SSteven Stallion failure: 404b3697b90SSteven Stallion if (macp != NULL) { 405b3697b90SSteven Stallion mac_free(macp); 406b3697b90SSteven Stallion } 407b3697b90SSteven Stallion 408b3697b90SSteven Stallion if (efep->efe_miih != NULL) { 409b3697b90SSteven Stallion mii_free(efep->efe_miih); 410b3697b90SSteven Stallion } 411b3697b90SSteven Stallion 412b3697b90SSteven Stallion if (efep->efe_intrh != NULL) { 413b3697b90SSteven Stallion (void) ddi_intr_disable(efep->efe_intrh); 414b3697b90SSteven Stallion (void) ddi_intr_remove_handler(efep->efe_intrh); 415b3697b90SSteven Stallion (void) ddi_intr_free(efep->efe_intrh); 416b3697b90SSteven Stallion } 417b3697b90SSteven Stallion 418b3697b90SSteven Stallion mutex_destroy(&efep->efe_txlock); 419b3697b90SSteven Stallion mutex_destroy(&efep->efe_intrlock); 420b3697b90SSteven Stallion 421b3697b90SSteven Stallion if (efep->efe_tx_ring != NULL) { 422b3697b90SSteven Stallion efe_ring_free(&efep->efe_tx_ring); 423b3697b90SSteven Stallion } 424b3697b90SSteven Stallion if (efep->efe_rx_ring != NULL) { 425b3697b90SSteven Stallion efe_ring_free(&efep->efe_rx_ring); 426b3697b90SSteven Stallion } 427b3697b90SSteven Stallion 428b3697b90SSteven Stallion if (efep->efe_regs_acch != NULL) { 429b3697b90SSteven Stallion ddi_regs_map_free(&efep->efe_regs_acch); 430b3697b90SSteven Stallion } 431b3697b90SSteven Stallion 432b3697b90SSteven Stallion kmem_free(efep, sizeof (efe_t)); 433b3697b90SSteven Stallion 434b3697b90SSteven Stallion return (DDI_FAILURE); 435b3697b90SSteven Stallion } 436b3697b90SSteven Stallion 437b3697b90SSteven Stallion int 438b3697b90SSteven Stallion efe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 439b3697b90SSteven Stallion { 440b3697b90SSteven Stallion efe_t *efep = ddi_get_driver_private(dip); 441b3697b90SSteven Stallion 442b3697b90SSteven Stallion switch (cmd) { 443b3697b90SSteven Stallion case DDI_DETACH: 444b3697b90SSteven Stallion break; 445b3697b90SSteven Stallion 446b3697b90SSteven Stallion case DDI_SUSPEND: 447b3697b90SSteven Stallion return (efe_suspend(efep)); 448b3697b90SSteven Stallion 449b3697b90SSteven Stallion default: 450b3697b90SSteven Stallion return (DDI_FAILURE); 451b3697b90SSteven Stallion } 452b3697b90SSteven Stallion 453b3697b90SSteven Stallion if (mac_unregister(efep->efe_mh) != 0) { 454b3697b90SSteven Stallion efe_error(dip, "unable to unregister from mac!"); 455b3697b90SSteven Stallion return (DDI_FAILURE); 456b3697b90SSteven Stallion } 457b3697b90SSteven Stallion 458b3697b90SSteven Stallion mii_free(efep->efe_miih); 459b3697b90SSteven Stallion 460b3697b90SSteven Stallion (void) ddi_intr_disable(efep->efe_intrh); 461b3697b90SSteven Stallion (void) ddi_intr_remove_handler(efep->efe_intrh); 462b3697b90SSteven Stallion (void) ddi_intr_free(efep->efe_intrh); 463b3697b90SSteven Stallion 464b3697b90SSteven Stallion mutex_destroy(&efep->efe_txlock); 465b3697b90SSteven Stallion mutex_destroy(&efep->efe_intrlock); 466b3697b90SSteven Stallion 467b3697b90SSteven Stallion if (efep->efe_tx_ring != NULL) { 468b3697b90SSteven Stallion efe_ring_free(&efep->efe_tx_ring); 469b3697b90SSteven Stallion } 470b3697b90SSteven Stallion if (efep->efe_rx_ring != NULL) { 471b3697b90SSteven Stallion efe_ring_free(&efep->efe_rx_ring); 472b3697b90SSteven Stallion } 473b3697b90SSteven Stallion 474b3697b90SSteven Stallion ddi_regs_map_free(&efep->efe_regs_acch); 475b3697b90SSteven Stallion 476b3697b90SSteven Stallion kmem_free(efep, sizeof (efe_t)); 477b3697b90SSteven Stallion 478b3697b90SSteven Stallion return (DDI_SUCCESS); 479b3697b90SSteven Stallion } 480b3697b90SSteven Stallion 481b3697b90SSteven Stallion int 482b3697b90SSteven Stallion efe_quiesce(dev_info_t *dip) 483b3697b90SSteven Stallion { 484b3697b90SSteven Stallion efe_t *efep = ddi_get_driver_private(dip); 485b3697b90SSteven Stallion 486b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, GENCTL_RESET); 487b3697b90SSteven Stallion drv_usecwait(RESET_DELAY); 488b3697b90SSteven Stallion 489b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN); 490b3697b90SSteven Stallion 491b3697b90SSteven Stallion return (DDI_SUCCESS); 492b3697b90SSteven Stallion } 493b3697b90SSteven Stallion 494b3697b90SSteven Stallion /* 495b3697b90SSteven Stallion * MII entry points. 496b3697b90SSteven Stallion */ 497b3697b90SSteven Stallion uint16_t 498b3697b90SSteven Stallion efe_mii_read(void *arg, uint8_t phy, uint8_t reg) 499b3697b90SSteven Stallion { 500b3697b90SSteven Stallion efe_t *efep = arg; 501b3697b90SSteven Stallion 502b3697b90SSteven Stallion PUTCSR(efep, CSR_MMCTL, MMCTL_READ | 503b3697b90SSteven Stallion reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR); 504b3697b90SSteven Stallion 505b3697b90SSteven Stallion for (int i = 0; i < MII_DELAY_CYCLES; ++i) { 506b3697b90SSteven Stallion if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_READ)) { 507b3697b90SSteven Stallion return ((uint16_t)GETCSR(efep, CSR_MMDATA)); 508b3697b90SSteven Stallion } 509b3697b90SSteven Stallion drv_usecwait(MII_DELAY); 510b3697b90SSteven Stallion } 511b3697b90SSteven Stallion efe_error(efep->efe_dip, "timed out reading from MII!"); 512b3697b90SSteven Stallion 513b3697b90SSteven Stallion return (0); 514b3697b90SSteven Stallion } 515b3697b90SSteven Stallion 516b3697b90SSteven Stallion void 517b3697b90SSteven Stallion efe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data) 518b3697b90SSteven Stallion { 519b3697b90SSteven Stallion efe_t *efep = arg; 520b3697b90SSteven Stallion 521b3697b90SSteven Stallion PUTCSR(efep, CSR_MMDATA, data); 522b3697b90SSteven Stallion 523b3697b90SSteven Stallion PUTCSR(efep, CSR_MMCTL, MMCTL_WRITE | 524b3697b90SSteven Stallion reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR); 525b3697b90SSteven Stallion 526b3697b90SSteven Stallion for (int i = 0; i < MII_DELAY_CYCLES; ++i) { 527b3697b90SSteven Stallion if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_WRITE)) { 528b3697b90SSteven Stallion return; 529b3697b90SSteven Stallion } 530b3697b90SSteven Stallion drv_usecwait(MII_DELAY); 531b3697b90SSteven Stallion } 532b3697b90SSteven Stallion efe_error(efep->efe_dip, "timed out writing to MII!"); 533b3697b90SSteven Stallion } 534b3697b90SSteven Stallion 535b3697b90SSteven Stallion void 536b3697b90SSteven Stallion efe_mii_notify(void *arg, link_state_t link) 537b3697b90SSteven Stallion { 538b3697b90SSteven Stallion efe_t *efep = arg; 539b3697b90SSteven Stallion 540b3697b90SSteven Stallion mac_link_update(efep->efe_mh, link); 541b3697b90SSteven Stallion } 542b3697b90SSteven Stallion 543b3697b90SSteven Stallion /* 544b3697b90SSteven Stallion * MAC entry points. 545b3697b90SSteven Stallion */ 546b3697b90SSteven Stallion int 547b3697b90SSteven Stallion efe_m_getstat(void *arg, uint_t stat, uint64_t *val) 548b3697b90SSteven Stallion { 549b3697b90SSteven Stallion efe_t *efep = arg; 550b3697b90SSteven Stallion 551b3697b90SSteven Stallion if (mii_m_getstat(efep->efe_miih, stat, val) == 0) { 552b3697b90SSteven Stallion return (0); 553b3697b90SSteven Stallion } 554b3697b90SSteven Stallion 555b3697b90SSteven Stallion switch (stat) { 556b3697b90SSteven Stallion case MAC_STAT_MULTIRCV: 557b3697b90SSteven Stallion *val = efep->efe_multircv; 558b3697b90SSteven Stallion break; 559b3697b90SSteven Stallion 560b3697b90SSteven Stallion case MAC_STAT_BRDCSTRCV: 561b3697b90SSteven Stallion *val = efep->efe_brdcstrcv; 562b3697b90SSteven Stallion break; 563b3697b90SSteven Stallion 564b3697b90SSteven Stallion case MAC_STAT_MULTIXMT: 565b3697b90SSteven Stallion *val = efep->efe_multixmt; 566b3697b90SSteven Stallion break; 567b3697b90SSteven Stallion 568b3697b90SSteven Stallion case MAC_STAT_BRDCSTXMT: 569b3697b90SSteven Stallion *val = efep->efe_brdcstxmt; 570b3697b90SSteven Stallion break; 571b3697b90SSteven Stallion 572b3697b90SSteven Stallion case MAC_STAT_NORCVBUF: 573b3697b90SSteven Stallion *val = efep->efe_norcvbuf; 574b3697b90SSteven Stallion break; 575b3697b90SSteven Stallion 576b3697b90SSteven Stallion case MAC_STAT_IERRORS: 577b3697b90SSteven Stallion *val = efep->efe_ierrors; 578b3697b90SSteven Stallion break; 579b3697b90SSteven Stallion 580b3697b90SSteven Stallion case MAC_STAT_NOXMTBUF: 581b3697b90SSteven Stallion *val = efep->efe_noxmtbuf; 582b3697b90SSteven Stallion break; 583b3697b90SSteven Stallion 584b3697b90SSteven Stallion case MAC_STAT_OERRORS: 585b3697b90SSteven Stallion *val = efep->efe_oerrors; 586b3697b90SSteven Stallion break; 587b3697b90SSteven Stallion 588b3697b90SSteven Stallion case MAC_STAT_COLLISIONS: 589b3697b90SSteven Stallion *val = efep->efe_collisions; 590b3697b90SSteven Stallion break; 591b3697b90SSteven Stallion 592b3697b90SSteven Stallion case MAC_STAT_RBYTES: 593b3697b90SSteven Stallion *val = efep->efe_rbytes; 594b3697b90SSteven Stallion break; 595b3697b90SSteven Stallion 596b3697b90SSteven Stallion case MAC_STAT_IPACKETS: 597b3697b90SSteven Stallion *val = efep->efe_ipackets; 598b3697b90SSteven Stallion break; 599b3697b90SSteven Stallion 600b3697b90SSteven Stallion case MAC_STAT_OBYTES: 601b3697b90SSteven Stallion *val = efep->efe_obytes; 602b3697b90SSteven Stallion break; 603b3697b90SSteven Stallion 604b3697b90SSteven Stallion case MAC_STAT_OPACKETS: 605b3697b90SSteven Stallion *val = efep->efe_opackets; 606b3697b90SSteven Stallion break; 607b3697b90SSteven Stallion 608b3697b90SSteven Stallion case MAC_STAT_UNDERFLOWS: 609b3697b90SSteven Stallion *val = efep->efe_uflo; 610b3697b90SSteven Stallion break; 611b3697b90SSteven Stallion 612b3697b90SSteven Stallion case MAC_STAT_OVERFLOWS: 613b3697b90SSteven Stallion *val = efep->efe_oflo; 614b3697b90SSteven Stallion break; 615b3697b90SSteven Stallion 616b3697b90SSteven Stallion case ETHER_STAT_ALIGN_ERRORS: 617b3697b90SSteven Stallion *val = efep->efe_align_errors; 618b3697b90SSteven Stallion break; 619b3697b90SSteven Stallion 620b3697b90SSteven Stallion case ETHER_STAT_FCS_ERRORS: 621b3697b90SSteven Stallion *val = efep->efe_fcs_errors; 622b3697b90SSteven Stallion break; 623b3697b90SSteven Stallion 624b3697b90SSteven Stallion case ETHER_STAT_FIRST_COLLISIONS: 625b3697b90SSteven Stallion *val = efep->efe_first_collisions; 626b3697b90SSteven Stallion break; 627b3697b90SSteven Stallion 628b3697b90SSteven Stallion case ETHER_STAT_TX_LATE_COLLISIONS: 629b3697b90SSteven Stallion *val = efep->efe_tx_late_collisions; 630b3697b90SSteven Stallion break; 631b3697b90SSteven Stallion 632b3697b90SSteven Stallion case ETHER_STAT_DEFER_XMTS: 633b3697b90SSteven Stallion *val = efep->efe_defer_xmts; 634b3697b90SSteven Stallion break; 635b3697b90SSteven Stallion 636b3697b90SSteven Stallion case ETHER_STAT_EX_COLLISIONS: 637b3697b90SSteven Stallion *val = efep->efe_ex_collisions; 638b3697b90SSteven Stallion break; 639b3697b90SSteven Stallion 640b3697b90SSteven Stallion case ETHER_STAT_MACXMT_ERRORS: 641b3697b90SSteven Stallion *val = efep->efe_macxmt_errors; 642b3697b90SSteven Stallion break; 643b3697b90SSteven Stallion 644b3697b90SSteven Stallion case ETHER_STAT_CARRIER_ERRORS: 645b3697b90SSteven Stallion *val = efep->efe_carrier_errors; 646b3697b90SSteven Stallion break; 647b3697b90SSteven Stallion 648b3697b90SSteven Stallion case ETHER_STAT_TOOLONG_ERRORS: 649b3697b90SSteven Stallion *val = efep->efe_toolong_errors; 650b3697b90SSteven Stallion break; 651b3697b90SSteven Stallion 652b3697b90SSteven Stallion case ETHER_STAT_MACRCV_ERRORS: 653b3697b90SSteven Stallion *val = efep->efe_macrcv_errors; 654b3697b90SSteven Stallion break; 655b3697b90SSteven Stallion 656b3697b90SSteven Stallion case ETHER_STAT_TOOSHORT_ERRORS: 657b3697b90SSteven Stallion *val = efep->efe_runt_errors; 658b3697b90SSteven Stallion break; 659b3697b90SSteven Stallion 660b3697b90SSteven Stallion case ETHER_STAT_JABBER_ERRORS: 661b3697b90SSteven Stallion *val = efep->efe_jabber_errors; 662b3697b90SSteven Stallion break; 663b3697b90SSteven Stallion 664b3697b90SSteven Stallion default: 665b3697b90SSteven Stallion return (ENOTSUP); 666b3697b90SSteven Stallion } 667b3697b90SSteven Stallion 668b3697b90SSteven Stallion return (0); 669b3697b90SSteven Stallion } 670b3697b90SSteven Stallion 671b3697b90SSteven Stallion int 672b3697b90SSteven Stallion efe_m_start(void *arg) 673b3697b90SSteven Stallion { 674b3697b90SSteven Stallion efe_t *efep = arg; 675b3697b90SSteven Stallion 676b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 677b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 678b3697b90SSteven Stallion 679b3697b90SSteven Stallion efe_start(efep); 680b3697b90SSteven Stallion efep->efe_flags |= FLAG_RUNNING; 681b3697b90SSteven Stallion 682b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 683b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 684b3697b90SSteven Stallion 685b3697b90SSteven Stallion mii_start(efep->efe_miih); 686b3697b90SSteven Stallion 687b3697b90SSteven Stallion return (0); 688b3697b90SSteven Stallion } 689b3697b90SSteven Stallion 690b3697b90SSteven Stallion void 691b3697b90SSteven Stallion efe_m_stop(void *arg) 692b3697b90SSteven Stallion { 693b3697b90SSteven Stallion efe_t *efep = arg; 694b3697b90SSteven Stallion 695b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 696b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 697b3697b90SSteven Stallion 698b3697b90SSteven Stallion efe_stop(efep); 699b3697b90SSteven Stallion efep->efe_flags &= ~FLAG_RUNNING; 700b3697b90SSteven Stallion 701b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 702b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 703b3697b90SSteven Stallion 704b3697b90SSteven Stallion mii_stop(efep->efe_miih); 705b3697b90SSteven Stallion } 706b3697b90SSteven Stallion 707b3697b90SSteven Stallion int 708b3697b90SSteven Stallion efe_m_setpromisc(void *arg, boolean_t on) 709b3697b90SSteven Stallion { 710b3697b90SSteven Stallion efe_t *efep = arg; 711b3697b90SSteven Stallion 712b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 713b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 714b3697b90SSteven Stallion 715b3697b90SSteven Stallion if (efep->efe_flags & FLAG_SUSPENDED) { 716b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 717b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 718b3697b90SSteven Stallion return (0); 719b3697b90SSteven Stallion } 720b3697b90SSteven Stallion 721b3697b90SSteven Stallion efep->efe_promisc = on; 722b3697b90SSteven Stallion 723b3697b90SSteven Stallion if (efep->efe_flags & FLAG_RUNNING) { 724b3697b90SSteven Stallion efe_restart(efep); 725b3697b90SSteven Stallion } 726b3697b90SSteven Stallion 727b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 728b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 729b3697b90SSteven Stallion 730b3697b90SSteven Stallion return (0); 731b3697b90SSteven Stallion } 732b3697b90SSteven Stallion 733b3697b90SSteven Stallion int 734b3697b90SSteven Stallion efe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 735b3697b90SSteven Stallion { 736b3697b90SSteven Stallion efe_t *efep = arg; 737b3697b90SSteven Stallion uint32_t val; 738b3697b90SSteven Stallion int index; 739b3697b90SSteven Stallion int bit; 740b3697b90SSteven Stallion boolean_t restart = B_FALSE; 741b3697b90SSteven Stallion 742b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 743b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 744b3697b90SSteven Stallion 745b3697b90SSteven Stallion if (efep->efe_flags & FLAG_SUSPENDED) { 746b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 747b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 748b3697b90SSteven Stallion return (0); 749b3697b90SSteven Stallion } 750b3697b90SSteven Stallion 751b3697b90SSteven Stallion CRC32(val, macaddr, ETHERADDRL, -1U, crc32_table); 752b3697b90SSteven Stallion val %= MCHASHL; 753b3697b90SSteven Stallion 754b3697b90SSteven Stallion index = val / MCHASHSZ; 755b3697b90SSteven Stallion bit = 1U << (val % MCHASHSZ); 756b3697b90SSteven Stallion 757b3697b90SSteven Stallion if (add) { 758b3697b90SSteven Stallion efep->efe_mccount[val]++; 759b3697b90SSteven Stallion if (efep->efe_mccount[val] == 1) { 760b3697b90SSteven Stallion efep->efe_mchash[index] |= bit; 761b3697b90SSteven Stallion restart = B_TRUE; 762b3697b90SSteven Stallion } 763b3697b90SSteven Stallion 764b3697b90SSteven Stallion } else { 765b3697b90SSteven Stallion efep->efe_mccount[val]--; 766b3697b90SSteven Stallion if (efep->efe_mccount[val] == 0) { 767b3697b90SSteven Stallion efep->efe_mchash[index] &= ~bit; 768b3697b90SSteven Stallion restart = B_TRUE; 769b3697b90SSteven Stallion } 770b3697b90SSteven Stallion } 771b3697b90SSteven Stallion 772b3697b90SSteven Stallion if (restart && efep->efe_flags & FLAG_RUNNING) { 773b3697b90SSteven Stallion efe_restart(efep); 774b3697b90SSteven Stallion } 775b3697b90SSteven Stallion 776b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 777b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 778b3697b90SSteven Stallion 779b3697b90SSteven Stallion return (0); 780b3697b90SSteven Stallion } 781b3697b90SSteven Stallion 782b3697b90SSteven Stallion int 783b3697b90SSteven Stallion efe_m_unicst(void *arg, const uint8_t *macaddr) 784b3697b90SSteven Stallion { 785b3697b90SSteven Stallion efe_t *efep = arg; 786b3697b90SSteven Stallion 787b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 788b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 789b3697b90SSteven Stallion 790b3697b90SSteven Stallion if (efep->efe_flags & FLAG_SUSPENDED) { 791b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 792b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 793b3697b90SSteven Stallion return (0); 794b3697b90SSteven Stallion } 795b3697b90SSteven Stallion 796b3697b90SSteven Stallion bcopy(macaddr, efep->efe_macaddr, ETHERADDRL); 797b3697b90SSteven Stallion 798b3697b90SSteven Stallion if (efep->efe_flags & FLAG_RUNNING) { 799b3697b90SSteven Stallion efe_restart(efep); 800b3697b90SSteven Stallion } 801b3697b90SSteven Stallion 802b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 803b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 804b3697b90SSteven Stallion 805b3697b90SSteven Stallion return (0); 806b3697b90SSteven Stallion } 807b3697b90SSteven Stallion 808b3697b90SSteven Stallion mblk_t * 809b3697b90SSteven Stallion efe_m_tx(void *arg, mblk_t *mp) 810b3697b90SSteven Stallion { 811b3697b90SSteven Stallion efe_t *efep = arg; 812b3697b90SSteven Stallion 813b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 814b3697b90SSteven Stallion 815b3697b90SSteven Stallion if (efep->efe_flags & FLAG_SUSPENDED) { 816b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 817b3697b90SSteven Stallion return (mp); 818b3697b90SSteven Stallion } 819b3697b90SSteven Stallion 820b3697b90SSteven Stallion while (mp != NULL) { 821b3697b90SSteven Stallion mblk_t *tmp = mp->b_next; 822b3697b90SSteven Stallion mp->b_next = NULL; 823b3697b90SSteven Stallion 824b3697b90SSteven Stallion if (efe_send(efep, mp) != DDI_SUCCESS) { 825b3697b90SSteven Stallion mp->b_next = tmp; 826b3697b90SSteven Stallion break; 827b3697b90SSteven Stallion } 828b3697b90SSteven Stallion mp = tmp; 829b3697b90SSteven Stallion } 830b3697b90SSteven Stallion 831b3697b90SSteven Stallion /* Kick the transmitter */ 832b3697b90SSteven Stallion PUTCSR(efep, CSR_COMMAND, COMMAND_TXQUEUED); 833b3697b90SSteven Stallion 834b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 835b3697b90SSteven Stallion 836b3697b90SSteven Stallion return (mp); 837b3697b90SSteven Stallion } 838b3697b90SSteven Stallion 839b3697b90SSteven Stallion int 840b3697b90SSteven Stallion efe_m_setprop(void *arg, const char *name, mac_prop_id_t id, 841b3697b90SSteven Stallion uint_t valsize, const void *val) 842b3697b90SSteven Stallion { 843b3697b90SSteven Stallion efe_t *efep = arg; 844b3697b90SSteven Stallion 845b3697b90SSteven Stallion return (mii_m_setprop(efep->efe_miih, name, id, valsize, val)); 846b3697b90SSteven Stallion } 847b3697b90SSteven Stallion 848b3697b90SSteven Stallion int 849b3697b90SSteven Stallion efe_m_getprop(void *arg, const char *name, mac_prop_id_t id, 850b3697b90SSteven Stallion uint_t valsize, void *val) 851b3697b90SSteven Stallion { 852b3697b90SSteven Stallion efe_t *efep = arg; 853b3697b90SSteven Stallion 854b3697b90SSteven Stallion return (mii_m_getprop(efep->efe_miih, name, id, valsize, val)); 855b3697b90SSteven Stallion } 856b3697b90SSteven Stallion 857b3697b90SSteven Stallion void 858b3697b90SSteven Stallion efe_m_propinfo(void *arg, const char *name, mac_prop_id_t id, 859b3697b90SSteven Stallion mac_prop_info_handle_t state) 860b3697b90SSteven Stallion { 861b3697b90SSteven Stallion efe_t *efep = arg; 862b3697b90SSteven Stallion 863b3697b90SSteven Stallion mii_m_propinfo(efep->efe_miih, name, id, state); 864b3697b90SSteven Stallion } 865b3697b90SSteven Stallion 866b3697b90SSteven Stallion /* 867b3697b90SSteven Stallion * ISR/periodic callbacks. 868b3697b90SSteven Stallion */ 869b3697b90SSteven Stallion uint_t 870b3697b90SSteven Stallion efe_intr(caddr_t arg1, caddr_t arg2) 871b3697b90SSteven Stallion { 872b3697b90SSteven Stallion efe_t *efep = (void *)arg1; 873b3697b90SSteven Stallion uint32_t status; 874b3697b90SSteven Stallion mblk_t *mp = NULL; 875b3697b90SSteven Stallion 876b3697b90SSteven Stallion _NOTE(ARGUNUSED(arg2)); 877b3697b90SSteven Stallion 878b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 879b3697b90SSteven Stallion 880b3697b90SSteven Stallion if (efep->efe_flags & FLAG_SUSPENDED) { 881b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 882b3697b90SSteven Stallion return (DDI_INTR_UNCLAIMED); 883b3697b90SSteven Stallion } 884b3697b90SSteven Stallion 885b3697b90SSteven Stallion status = GETCSR(efep, CSR_INTSTAT); 886b3697b90SSteven Stallion if (!(status & INTSTAT_ACTV)) { 887b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 888b3697b90SSteven Stallion return (DDI_INTR_UNCLAIMED); 889b3697b90SSteven Stallion } 890b3697b90SSteven Stallion PUTCSR(efep, CSR_INTSTAT, status); 891b3697b90SSteven Stallion 892b3697b90SSteven Stallion if (status & INTSTAT_RCC) { 893b3697b90SSteven Stallion mp = efe_recv(efep); 894b3697b90SSteven Stallion } 895b3697b90SSteven Stallion 896b3697b90SSteven Stallion if (status & INTSTAT_RQE) { 897b3697b90SSteven Stallion efep->efe_ierrors++; 898b3697b90SSteven Stallion efep->efe_macrcv_errors++; 899b3697b90SSteven Stallion 900b3697b90SSteven Stallion /* Kick the receiver */ 901b3697b90SSteven Stallion PUTCSR(efep, CSR_COMMAND, COMMAND_RXQUEUED); 902b3697b90SSteven Stallion } 903b3697b90SSteven Stallion 904b3697b90SSteven Stallion if (status & INTSTAT_TXC) { 905b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 906b3697b90SSteven Stallion 907b3697b90SSteven Stallion efe_send_done(efep); 908b3697b90SSteven Stallion 909b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 910b3697b90SSteven Stallion } 911b3697b90SSteven Stallion 912b3697b90SSteven Stallion if (status & INTSTAT_FATAL) { 913b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 914b3697b90SSteven Stallion 915b3697b90SSteven Stallion efe_error(efep->efe_dip, "bus error; resetting!"); 916b3697b90SSteven Stallion efe_restart(efep); 917b3697b90SSteven Stallion 918b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 919b3697b90SSteven Stallion } 920b3697b90SSteven Stallion 921b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 922b3697b90SSteven Stallion 923b3697b90SSteven Stallion if (mp != NULL) { 924b3697b90SSteven Stallion mac_rx(efep->efe_mh, NULL, mp); 925b3697b90SSteven Stallion } 926b3697b90SSteven Stallion 927b3697b90SSteven Stallion if (status & INTSTAT_TXC) { 928b3697b90SSteven Stallion mac_tx_update(efep->efe_mh); 929b3697b90SSteven Stallion } 930b3697b90SSteven Stallion 931b3697b90SSteven Stallion if (status & INTSTAT_FATAL) { 932b3697b90SSteven Stallion mii_reset(efep->efe_miih); 933b3697b90SSteven Stallion } 934b3697b90SSteven Stallion 935b3697b90SSteven Stallion return (DDI_INTR_CLAIMED); 936b3697b90SSteven Stallion } 937b3697b90SSteven Stallion 938b3697b90SSteven Stallion /* 939b3697b90SSteven Stallion * Support functions. 940b3697b90SSteven Stallion */ 941b3697b90SSteven Stallion void 942b3697b90SSteven Stallion efe_init(efe_t *efep) 943b3697b90SSteven Stallion { 944b3697b90SSteven Stallion uint32_t val; 945b3697b90SSteven Stallion 946b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 947b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 948b3697b90SSteven Stallion 949b3697b90SSteven Stallion efe_reset(efep); 950b3697b90SSteven Stallion 951b3697b90SSteven Stallion val = GENCTL_ONECOPY | GENCTL_RFT_128 | GENCTL_MRM; 952b3697b90SSteven Stallion #ifdef _BIG_ENDIAN 953b3697b90SSteven Stallion val |= GENCTL_BE; 954b3697b90SSteven Stallion #endif /* _BIG_ENDIAN */ 955b3697b90SSteven Stallion 956b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, val); 957b3697b90SSteven Stallion PUTCSR(efep, CSR_PBLCNT, BURSTLEN); 958b3697b90SSteven Stallion 959b3697b90SSteven Stallion efe_init_rx_ring(efep); 960b3697b90SSteven Stallion efe_init_tx_ring(efep); 961b3697b90SSteven Stallion 962b3697b90SSteven Stallion efe_setaddr(efep, efep->efe_macaddr); 963b3697b90SSteven Stallion 964b3697b90SSteven Stallion if (efep->efe_promisc) { 965b3697b90SSteven Stallion efe_setmchash(efep, efe_mchash_promisc); 966b3697b90SSteven Stallion } else { 967b3697b90SSteven Stallion efe_setmchash(efep, efep->efe_mchash); 968b3697b90SSteven Stallion } 969b3697b90SSteven Stallion } 970b3697b90SSteven Stallion 971b3697b90SSteven Stallion void 972b3697b90SSteven Stallion efe_init_rx_ring(efe_t *efep) 973b3697b90SSteven Stallion { 974b3697b90SSteven Stallion efe_ring_t *rp; 975b3697b90SSteven Stallion 976b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 977b3697b90SSteven Stallion 978b3697b90SSteven Stallion rp = efep->efe_rx_ring; 979b3697b90SSteven Stallion 980b3697b90SSteven Stallion for (int i = 0; i < DESCLEN(rp); ++i) { 981b3697b90SSteven Stallion efe_desc_t *dp = GETDESC(rp, i); 982b3697b90SSteven Stallion efe_buf_t *bp = GETBUF(rp, i); 983b3697b90SSteven Stallion 984b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER); 985b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_len, 0); 986b3697b90SSteven Stallion PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp)); 987b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp)); 988b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_control, 0); 989b3697b90SSteven Stallion PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i)); 990b3697b90SSteven Stallion 991b3697b90SSteven Stallion SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV); 992b3697b90SSteven Stallion } 993b3697b90SSteven Stallion 994b3697b90SSteven Stallion efep->efe_rx_desc = 0; 995b3697b90SSteven Stallion 996b3697b90SSteven Stallion PUTCSR(efep, CSR_PRCDAR, DESCADDR(rp, 0)); 997b3697b90SSteven Stallion } 998b3697b90SSteven Stallion 999b3697b90SSteven Stallion void 1000b3697b90SSteven Stallion efe_init_tx_ring(efe_t *efep) 1001b3697b90SSteven Stallion { 1002b3697b90SSteven Stallion efe_ring_t *rp; 1003b3697b90SSteven Stallion 1004b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1005b3697b90SSteven Stallion 1006b3697b90SSteven Stallion rp = efep->efe_tx_ring; 1007b3697b90SSteven Stallion 1008b3697b90SSteven Stallion for (int i = 0; i < DESCLEN(rp); ++i) { 1009b3697b90SSteven Stallion efe_desc_t *dp = GETDESC(rp, i); 1010b3697b90SSteven Stallion efe_buf_t *bp = GETBUF(rp, i); 1011b3697b90SSteven Stallion 1012b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_status, 0); 1013b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_len, 0); 1014b3697b90SSteven Stallion PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp)); 1015b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp)); 1016b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_control, 0); 1017b3697b90SSteven Stallion PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i)); 1018b3697b90SSteven Stallion 1019b3697b90SSteven Stallion SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV); 1020b3697b90SSteven Stallion } 1021b3697b90SSteven Stallion 1022b3697b90SSteven Stallion efep->efe_tx_desc = 0; 1023b3697b90SSteven Stallion efep->efe_tx_sent = 0; 1024b3697b90SSteven Stallion 1025b3697b90SSteven Stallion PUTCSR(efep, CSR_PTCDAR, DESCADDR(rp, 0)); 1026b3697b90SSteven Stallion } 1027b3697b90SSteven Stallion 1028b3697b90SSteven Stallion void 1029b3697b90SSteven Stallion efe_reset(efe_t *efep) 1030b3697b90SSteven Stallion { 1031b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1032b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1033b3697b90SSteven Stallion 1034b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, GENCTL_RESET); 1035b3697b90SSteven Stallion drv_usecwait(RESET_DELAY); 1036b3697b90SSteven Stallion 1037b3697b90SSteven Stallion /* Assert internal clock source (AN 7.15) */ 1038b3697b90SSteven Stallion for (int i = 0; i < RESET_TEST_CYCLES; ++i) { 1039b3697b90SSteven Stallion PUTCSR(efep, CSR_TEST, TEST_CLOCK); 1040b3697b90SSteven Stallion } 1041b3697b90SSteven Stallion } 1042b3697b90SSteven Stallion 1043b3697b90SSteven Stallion void 1044b3697b90SSteven Stallion efe_start(efe_t *efep) 1045b3697b90SSteven Stallion { 1046b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1047b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1048b3697b90SSteven Stallion 1049b3697b90SSteven Stallion efe_init(efep); 1050b3697b90SSteven Stallion 1051b3697b90SSteven Stallion PUTCSR(efep, CSR_RXCON, 1052b3697b90SSteven Stallion RXCON_SEP | RXCON_RRF | RXCON_RBF | RXCON_RMF | 1053b3697b90SSteven Stallion (efep->efe_promisc ? RXCON_PROMISC : 0)); 1054b3697b90SSteven Stallion 1055b3697b90SSteven Stallion PUTCSR(efep, CSR_TXCON, TXCON_LB_3); 1056b3697b90SSteven Stallion 1057b3697b90SSteven Stallion efe_intr_enable(efep); 1058b3697b90SSteven Stallion 1059b3697b90SSteven Stallion SETBIT(efep, CSR_COMMAND, 1060b3697b90SSteven Stallion COMMAND_START_RX | COMMAND_RXQUEUED); 1061b3697b90SSteven Stallion } 1062b3697b90SSteven Stallion 1063b3697b90SSteven Stallion void 1064b3697b90SSteven Stallion efe_stop(efe_t *efep) 1065b3697b90SSteven Stallion { 1066b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1067b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1068b3697b90SSteven Stallion 1069b3697b90SSteven Stallion efe_intr_disable(efep); 1070b3697b90SSteven Stallion 1071b3697b90SSteven Stallion PUTCSR(efep, CSR_COMMAND, COMMAND_STOP_RX); 1072b3697b90SSteven Stallion 1073b3697b90SSteven Stallion efe_stop_dma(efep); 1074b3697b90SSteven Stallion 1075b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, GENCTL_RESET); 1076b3697b90SSteven Stallion drv_usecwait(RESET_DELAY); 1077b3697b90SSteven Stallion 1078b3697b90SSteven Stallion PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN); 1079b3697b90SSteven Stallion } 1080b3697b90SSteven Stallion 1081b3697b90SSteven Stallion void 1082b3697b90SSteven Stallion efe_stop_dma(efe_t *efep) 1083b3697b90SSteven Stallion { 1084b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1085b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1086b3697b90SSteven Stallion 1087b3697b90SSteven Stallion PUTCSR(efep, CSR_COMMAND, 1088b3697b90SSteven Stallion COMMAND_STOP_RDMA | COMMAND_STOP_TDMA); 1089b3697b90SSteven Stallion 1090b3697b90SSteven Stallion for (int i = 0; i < STOP_DELAY_CYCLES; ++i) { 1091b3697b90SSteven Stallion uint32_t status = GETCSR(efep, CSR_INTSTAT); 1092b3697b90SSteven Stallion if (status & INTSTAT_RXIDLE && 1093b3697b90SSteven Stallion status & INTSTAT_TXIDLE) { 1094b3697b90SSteven Stallion return; 1095b3697b90SSteven Stallion } 1096b3697b90SSteven Stallion drv_usecwait(STOP_DELAY); 1097b3697b90SSteven Stallion } 1098b3697b90SSteven Stallion efe_error(efep->efe_dip, "timed out stopping DMA engine!"); 1099b3697b90SSteven Stallion } 1100b3697b90SSteven Stallion 1101*e65fcc69SRichard Lowe static inline void 1102b3697b90SSteven Stallion efe_restart(efe_t *efep) 1103b3697b90SSteven Stallion { 1104b3697b90SSteven Stallion efe_stop(efep); 1105b3697b90SSteven Stallion efe_start(efep); 1106b3697b90SSteven Stallion } 1107b3697b90SSteven Stallion 1108b3697b90SSteven Stallion int 1109b3697b90SSteven Stallion efe_suspend(efe_t *efep) 1110b3697b90SSteven Stallion { 1111b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 1112b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 1113b3697b90SSteven Stallion 1114b3697b90SSteven Stallion if (efep->efe_flags & FLAG_RUNNING) { 1115b3697b90SSteven Stallion efe_stop(efep); 1116b3697b90SSteven Stallion } 1117b3697b90SSteven Stallion efep->efe_flags |= FLAG_SUSPENDED; 1118b3697b90SSteven Stallion 1119b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 1120b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 1121b3697b90SSteven Stallion 1122b3697b90SSteven Stallion mii_suspend(efep->efe_miih); 1123b3697b90SSteven Stallion 1124b3697b90SSteven Stallion return (DDI_SUCCESS); 1125b3697b90SSteven Stallion } 1126b3697b90SSteven Stallion 1127b3697b90SSteven Stallion int 1128b3697b90SSteven Stallion efe_resume(efe_t *efep) 1129b3697b90SSteven Stallion { 1130b3697b90SSteven Stallion mutex_enter(&efep->efe_intrlock); 1131b3697b90SSteven Stallion mutex_enter(&efep->efe_txlock); 1132b3697b90SSteven Stallion 1133b3697b90SSteven Stallion if (efep->efe_flags & FLAG_RUNNING) { 1134b3697b90SSteven Stallion efe_start(efep); 1135b3697b90SSteven Stallion } 1136b3697b90SSteven Stallion efep->efe_flags &= ~FLAG_SUSPENDED; 1137b3697b90SSteven Stallion 1138b3697b90SSteven Stallion mutex_exit(&efep->efe_txlock); 1139b3697b90SSteven Stallion mutex_exit(&efep->efe_intrlock); 1140b3697b90SSteven Stallion 1141b3697b90SSteven Stallion mii_resume(efep->efe_miih); 1142b3697b90SSteven Stallion 1143b3697b90SSteven Stallion return (DDI_SUCCESS); 1144b3697b90SSteven Stallion } 1145b3697b90SSteven Stallion 1146b3697b90SSteven Stallion efe_ring_t * 1147b3697b90SSteven Stallion efe_ring_alloc(dev_info_t *dip, size_t len) 1148b3697b90SSteven Stallion { 1149b3697b90SSteven Stallion efe_ring_t *rp; 1150b3697b90SSteven Stallion size_t rlen; 1151b3697b90SSteven Stallion uint_t ccount; 1152b3697b90SSteven Stallion 1153b3697b90SSteven Stallion ASSERT(len > 1); 1154b3697b90SSteven Stallion 1155b3697b90SSteven Stallion rp = kmem_zalloc(sizeof (efe_ring_t), KM_SLEEP); 1156b3697b90SSteven Stallion rp->r_len = len; 1157b3697b90SSteven Stallion 1158b3697b90SSteven Stallion if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL, 1159b3697b90SSteven Stallion &rp->r_dmah) != DDI_SUCCESS) { 1160b3697b90SSteven Stallion efe_error(dip, "unable to allocate DMA handle!"); 1161b3697b90SSteven Stallion goto failure; 1162b3697b90SSteven Stallion } 1163b3697b90SSteven Stallion 1164b3697b90SSteven Stallion if (ddi_dma_mem_alloc(rp->r_dmah, DESCSZ(len), &efe_buf_acc_attr, 1165b3697b90SSteven Stallion DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, (caddr_t *)&rp->r_descp, 1166b3697b90SSteven Stallion &rlen, &rp->r_acch) != DDI_SUCCESS) { 1167b3697b90SSteven Stallion efe_error(dip, "unable to allocate descriptors!"); 1168b3697b90SSteven Stallion goto failure; 1169b3697b90SSteven Stallion } 1170b3697b90SSteven Stallion 1171b3697b90SSteven Stallion if (ddi_dma_addr_bind_handle(rp->r_dmah, NULL, (caddr_t)rp->r_descp, 1172b3697b90SSteven Stallion DESCSZ(len), DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 1173b3697b90SSteven Stallion NULL, &rp->r_dmac, &ccount) != DDI_DMA_MAPPED) { 1174b3697b90SSteven Stallion efe_error(dip, "unable to bind DMA handle to descriptors!"); 1175b3697b90SSteven Stallion goto failure; 1176b3697b90SSteven Stallion } 1177b3697b90SSteven Stallion 1178b3697b90SSteven Stallion rp->r_bufpp = kmem_zalloc(BUFPSZ(len), KM_SLEEP); 1179b3697b90SSteven Stallion 1180b3697b90SSteven Stallion for (int i = 0; i < len; ++i) { 1181b3697b90SSteven Stallion efe_buf_t *bp = efe_buf_alloc(dip, BUFSZ); 1182b3697b90SSteven Stallion if (bp == NULL) { 1183b3697b90SSteven Stallion goto failure; 1184b3697b90SSteven Stallion } 1185b3697b90SSteven Stallion rp->r_bufpp[i] = bp; 1186b3697b90SSteven Stallion } 1187b3697b90SSteven Stallion 1188b3697b90SSteven Stallion return (rp); 1189b3697b90SSteven Stallion 1190b3697b90SSteven Stallion failure: 1191b3697b90SSteven Stallion efe_ring_free(&rp); 1192b3697b90SSteven Stallion 1193b3697b90SSteven Stallion return (NULL); 1194b3697b90SSteven Stallion } 1195b3697b90SSteven Stallion 1196b3697b90SSteven Stallion void 1197b3697b90SSteven Stallion efe_ring_free(efe_ring_t **rpp) 1198b3697b90SSteven Stallion { 1199b3697b90SSteven Stallion efe_ring_t *rp = *rpp; 1200b3697b90SSteven Stallion 1201b3697b90SSteven Stallion ASSERT(rp != NULL); 1202b3697b90SSteven Stallion 1203b3697b90SSteven Stallion for (int i = 0; i < DESCLEN(rp); ++i) { 1204b3697b90SSteven Stallion efe_buf_t *bp = GETBUF(rp, i); 1205b3697b90SSteven Stallion if (bp != NULL) { 1206b3697b90SSteven Stallion efe_buf_free(&bp); 1207b3697b90SSteven Stallion } 1208b3697b90SSteven Stallion } 1209b3697b90SSteven Stallion kmem_free(rp->r_bufpp, BUFPSZ(DESCLEN(rp))); 1210b3697b90SSteven Stallion 1211b3697b90SSteven Stallion if (rp->r_descp != NULL) { 1212b3697b90SSteven Stallion (void) ddi_dma_unbind_handle(rp->r_dmah); 1213b3697b90SSteven Stallion } 1214b3697b90SSteven Stallion if (rp->r_acch != NULL) { 1215b3697b90SSteven Stallion ddi_dma_mem_free(&rp->r_acch); 1216b3697b90SSteven Stallion } 1217b3697b90SSteven Stallion if (rp->r_dmah != NULL) { 1218b3697b90SSteven Stallion ddi_dma_free_handle(&rp->r_dmah); 1219b3697b90SSteven Stallion } 1220b3697b90SSteven Stallion kmem_free(rp, sizeof (efe_ring_t)); 1221b3697b90SSteven Stallion 1222b3697b90SSteven Stallion *rpp = NULL; 1223b3697b90SSteven Stallion } 1224b3697b90SSteven Stallion 1225b3697b90SSteven Stallion efe_buf_t * 1226b3697b90SSteven Stallion efe_buf_alloc(dev_info_t *dip, size_t len) 1227b3697b90SSteven Stallion { 1228b3697b90SSteven Stallion efe_buf_t *bp; 1229b3697b90SSteven Stallion size_t rlen; 1230b3697b90SSteven Stallion uint_t ccount; 1231b3697b90SSteven Stallion 1232b3697b90SSteven Stallion bp = kmem_zalloc(sizeof (efe_buf_t), KM_SLEEP); 1233b3697b90SSteven Stallion bp->b_len = len; 1234b3697b90SSteven Stallion 1235b3697b90SSteven Stallion if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL, 1236b3697b90SSteven Stallion &bp->b_dmah) != DDI_SUCCESS) { 1237b3697b90SSteven Stallion efe_error(dip, "unable to allocate DMA handle!"); 1238b3697b90SSteven Stallion goto failure; 1239b3697b90SSteven Stallion } 1240b3697b90SSteven Stallion 1241b3697b90SSteven Stallion if (ddi_dma_mem_alloc(bp->b_dmah, len, &efe_buf_acc_attr, 1242b3697b90SSteven Stallion DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &bp->b_kaddr, &rlen, 1243b3697b90SSteven Stallion &bp->b_acch) != DDI_SUCCESS) { 1244b3697b90SSteven Stallion efe_error(dip, "unable to allocate buffer!"); 1245b3697b90SSteven Stallion goto failure; 1246b3697b90SSteven Stallion } 1247b3697b90SSteven Stallion 1248b3697b90SSteven Stallion if (ddi_dma_addr_bind_handle(bp->b_dmah, NULL, bp->b_kaddr, 1249b3697b90SSteven Stallion len, DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, 1250b3697b90SSteven Stallion &bp->b_dmac, &ccount) != DDI_DMA_MAPPED) { 1251b3697b90SSteven Stallion efe_error(dip, "unable to bind DMA handle to buffer!"); 1252b3697b90SSteven Stallion goto failure; 1253b3697b90SSteven Stallion } 1254b3697b90SSteven Stallion 1255b3697b90SSteven Stallion return (bp); 1256b3697b90SSteven Stallion 1257b3697b90SSteven Stallion failure: 1258b3697b90SSteven Stallion efe_buf_free(&bp); 1259b3697b90SSteven Stallion 1260b3697b90SSteven Stallion return (NULL); 1261b3697b90SSteven Stallion } 1262b3697b90SSteven Stallion 1263b3697b90SSteven Stallion void 1264b3697b90SSteven Stallion efe_buf_free(efe_buf_t **bpp) 1265b3697b90SSteven Stallion { 1266b3697b90SSteven Stallion efe_buf_t *bp = *bpp; 1267b3697b90SSteven Stallion 1268b3697b90SSteven Stallion ASSERT(bp != NULL); 1269b3697b90SSteven Stallion 1270b3697b90SSteven Stallion if (bp->b_kaddr != NULL) { 1271b3697b90SSteven Stallion (void) ddi_dma_unbind_handle(bp->b_dmah); 1272b3697b90SSteven Stallion } 1273b3697b90SSteven Stallion if (bp->b_acch != NULL) { 1274b3697b90SSteven Stallion ddi_dma_mem_free(&bp->b_acch); 1275b3697b90SSteven Stallion } 1276b3697b90SSteven Stallion if (bp->b_dmah != NULL) { 1277b3697b90SSteven Stallion ddi_dma_free_handle(&bp->b_dmah); 1278b3697b90SSteven Stallion } 1279b3697b90SSteven Stallion kmem_free(bp, sizeof (efe_buf_t)); 1280b3697b90SSteven Stallion 1281b3697b90SSteven Stallion *bpp = NULL; 1282b3697b90SSteven Stallion } 1283b3697b90SSteven Stallion 1284b3697b90SSteven Stallion void 1285b3697b90SSteven Stallion efe_intr_enable(efe_t *efep) 1286b3697b90SSteven Stallion { 1287b3697b90SSteven Stallion PUTCSR(efep, CSR_INTMASK, 1288b3697b90SSteven Stallion INTMASK_RCC | INTMASK_RQE | INTMASK_TXC | INTMASK_FATAL); 1289b3697b90SSteven Stallion 1290b3697b90SSteven Stallion SETBIT(efep, CSR_GENCTL, GENCTL_INT); 1291b3697b90SSteven Stallion } 1292b3697b90SSteven Stallion 1293b3697b90SSteven Stallion void 1294b3697b90SSteven Stallion efe_intr_disable(efe_t *efep) 1295b3697b90SSteven Stallion { 1296b3697b90SSteven Stallion PUTCSR(efep, CSR_INTMASK, 0); 1297b3697b90SSteven Stallion 1298b3697b90SSteven Stallion CLRBIT(efep, CSR_GENCTL, GENCTL_INT); 1299b3697b90SSteven Stallion } 1300b3697b90SSteven Stallion 1301b3697b90SSteven Stallion mblk_t * 1302b3697b90SSteven Stallion efe_recv(efe_t *efep) 1303b3697b90SSteven Stallion { 1304b3697b90SSteven Stallion efe_ring_t *rp; 1305b3697b90SSteven Stallion mblk_t *mp = NULL; 1306b3697b90SSteven Stallion mblk_t **mpp = ∓ 1307b3697b90SSteven Stallion 1308b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1309b3697b90SSteven Stallion 1310b3697b90SSteven Stallion rp = efep->efe_rx_ring; 1311b3697b90SSteven Stallion 1312b3697b90SSteven Stallion for (;;) { 1313b3697b90SSteven Stallion efe_desc_t *dp; 1314b3697b90SSteven Stallion uint16_t status; 1315b3697b90SSteven Stallion 1316b3697b90SSteven Stallion dp = GETDESC(rp, efep->efe_rx_desc); 1317b3697b90SSteven Stallion SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORKERNEL); 1318b3697b90SSteven Stallion 1319b3697b90SSteven Stallion status = GETDESC16(rp, &dp->d_status); 1320b3697b90SSteven Stallion 1321b3697b90SSteven Stallion /* Stop if device owns descriptor */ 1322b3697b90SSteven Stallion if (status & RXSTAT_OWNER) { 1323b3697b90SSteven Stallion break; 1324b3697b90SSteven Stallion } 1325b3697b90SSteven Stallion 1326b3697b90SSteven Stallion if (status & RXSTAT_PRI) { 1327b3697b90SSteven Stallion mblk_t *tmp = efe_recv_pkt(efep, dp); 1328b3697b90SSteven Stallion if (tmp != NULL) { 1329b3697b90SSteven Stallion *mpp = tmp; 1330b3697b90SSteven Stallion mpp = &tmp->b_next; 1331b3697b90SSteven Stallion } 1332b3697b90SSteven Stallion 1333b3697b90SSteven Stallion } else { 1334b3697b90SSteven Stallion efep->efe_ierrors++; 1335b3697b90SSteven Stallion 1336b3697b90SSteven Stallion if (status & RXSTAT_FAE) { 1337b3697b90SSteven Stallion efep->efe_align_errors++; 1338b3697b90SSteven Stallion } 1339b3697b90SSteven Stallion if (status & RXSTAT_CRC) { 1340b3697b90SSteven Stallion efep->efe_fcs_errors++; 1341b3697b90SSteven Stallion } 1342b3697b90SSteven Stallion if (status & RXSTAT_MP) { 1343b3697b90SSteven Stallion efep->efe_oflo++; 1344b3697b90SSteven Stallion } 1345b3697b90SSteven Stallion } 1346b3697b90SSteven Stallion 1347b3697b90SSteven Stallion /* Release ownership to device */ 1348b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER); 1349b3697b90SSteven Stallion 1350b3697b90SSteven Stallion SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORDEV); 1351b3697b90SSteven Stallion 1352b3697b90SSteven Stallion efep->efe_rx_desc = NEXTDESC(rp, efep->efe_rx_desc); 1353b3697b90SSteven Stallion } 1354b3697b90SSteven Stallion 1355b3697b90SSteven Stallion return (mp); 1356b3697b90SSteven Stallion } 1357b3697b90SSteven Stallion 1358b3697b90SSteven Stallion mblk_t * 1359b3697b90SSteven Stallion efe_recv_pkt(efe_t *efep, efe_desc_t *dp) 1360b3697b90SSteven Stallion { 1361b3697b90SSteven Stallion efe_ring_t *rp; 1362b3697b90SSteven Stallion efe_buf_t *bp; 1363b3697b90SSteven Stallion uint16_t len; 1364b3697b90SSteven Stallion mblk_t *mp; 1365b3697b90SSteven Stallion uint16_t status; 1366b3697b90SSteven Stallion 1367b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_intrlock)); 1368b3697b90SSteven Stallion 1369b3697b90SSteven Stallion rp = efep->efe_rx_ring; 1370b3697b90SSteven Stallion 1371b3697b90SSteven Stallion len = GETDESC16(rp, &dp->d_len) - ETHERFCSL; 1372b3697b90SSteven Stallion 1373b3697b90SSteven Stallion if (len < ETHERMIN) { 1374b3697b90SSteven Stallion efep->efe_ierrors++; 1375b3697b90SSteven Stallion efep->efe_runt_errors++; 1376b3697b90SSteven Stallion return (NULL); 1377b3697b90SSteven Stallion } 1378b3697b90SSteven Stallion 1379b3697b90SSteven Stallion if (len > ETHERMAX + VLAN_TAGSZ) { 1380b3697b90SSteven Stallion efep->efe_ierrors++; 1381b3697b90SSteven Stallion efep->efe_toolong_errors++; 1382b3697b90SSteven Stallion return (NULL); 1383b3697b90SSteven Stallion } 1384b3697b90SSteven Stallion 1385b3697b90SSteven Stallion mp = allocb(len, 0); 1386b3697b90SSteven Stallion if (mp == NULL) { 1387b3697b90SSteven Stallion efep->efe_ierrors++; 1388b3697b90SSteven Stallion efep->efe_norcvbuf++; 1389b3697b90SSteven Stallion return (NULL); 1390b3697b90SSteven Stallion } 1391b3697b90SSteven Stallion mp->b_wptr = mp->b_rptr + len; 1392b3697b90SSteven Stallion 1393b3697b90SSteven Stallion bp = GETBUF(rp, efep->efe_rx_desc); 1394b3697b90SSteven Stallion SYNCBUF(bp, DDI_DMA_SYNC_FORKERNEL); 1395b3697b90SSteven Stallion 1396b3697b90SSteven Stallion bcopy(bp->b_kaddr, mp->b_rptr, len); 1397b3697b90SSteven Stallion 1398b3697b90SSteven Stallion efep->efe_ipackets++; 1399b3697b90SSteven Stallion efep->efe_rbytes += len; 1400b3697b90SSteven Stallion 1401b3697b90SSteven Stallion status = GETDESC16(rp, &dp->d_status); 1402b3697b90SSteven Stallion 1403b3697b90SSteven Stallion if (status & RXSTAT_BAR) { 1404b3697b90SSteven Stallion efep->efe_brdcstrcv++; 1405b3697b90SSteven Stallion 1406b3697b90SSteven Stallion } else if (status & RXSTAT_MAR) { 1407b3697b90SSteven Stallion efep->efe_multircv++; 1408b3697b90SSteven Stallion } 1409b3697b90SSteven Stallion 1410b3697b90SSteven Stallion return (mp); 1411b3697b90SSteven Stallion } 1412b3697b90SSteven Stallion 1413b3697b90SSteven Stallion int 1414b3697b90SSteven Stallion efe_send(efe_t *efep, mblk_t *mp) 1415b3697b90SSteven Stallion { 1416b3697b90SSteven Stallion efe_ring_t *rp; 1417b3697b90SSteven Stallion uint16_t len; 1418b3697b90SSteven Stallion efe_desc_t *dp; 1419b3697b90SSteven Stallion uint16_t status; 1420b3697b90SSteven Stallion efe_buf_t *bp; 1421b3697b90SSteven Stallion 1422b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1423b3697b90SSteven Stallion 1424b3697b90SSteven Stallion rp = efep->efe_tx_ring; 1425b3697b90SSteven Stallion 1426b3697b90SSteven Stallion len = msgsize(mp); 1427b3697b90SSteven Stallion 1428b3697b90SSteven Stallion if (len > ETHERMAX + VLAN_TAGSZ) { 1429b3697b90SSteven Stallion efep->efe_oerrors++; 1430b3697b90SSteven Stallion efep->efe_macxmt_errors++; 1431b3697b90SSteven Stallion freemsg(mp); 1432b3697b90SSteven Stallion return (DDI_SUCCESS); 1433b3697b90SSteven Stallion } 1434b3697b90SSteven Stallion 1435b3697b90SSteven Stallion dp = GETDESC(rp, efep->efe_tx_desc); 1436b3697b90SSteven Stallion SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORKERNEL); 1437b3697b90SSteven Stallion 1438b3697b90SSteven Stallion status = GETDESC16(efep->efe_tx_ring, &dp->d_status); 1439b3697b90SSteven Stallion 1440b3697b90SSteven Stallion /* Stop if device owns descriptor */ 1441b3697b90SSteven Stallion if (status & TXSTAT_OWNER) { 1442b3697b90SSteven Stallion return (DDI_FAILURE); 1443b3697b90SSteven Stallion } 1444b3697b90SSteven Stallion 1445b3697b90SSteven Stallion bp = GETBUF(rp, efep->efe_tx_desc); 1446b3697b90SSteven Stallion 1447b3697b90SSteven Stallion mcopymsg(mp, bp->b_kaddr); 1448b3697b90SSteven Stallion 1449b3697b90SSteven Stallion /* 1450b3697b90SSteven Stallion * Packets must contain at least ETHERMIN octets. 1451b3697b90SSteven Stallion * Padded octets are zeroed out prior to sending. 1452b3697b90SSteven Stallion */ 1453b3697b90SSteven Stallion if (len < ETHERMIN) { 1454b3697b90SSteven Stallion bzero(bp->b_kaddr + len, ETHERMIN - len); 1455b3697b90SSteven Stallion len = ETHERMIN; 1456b3697b90SSteven Stallion } 1457b3697b90SSteven Stallion 1458b3697b90SSteven Stallion SYNCBUF(bp, DDI_DMA_SYNC_FORDEV); 1459b3697b90SSteven Stallion 1460b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_status, TXSTAT_OWNER); 1461b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_len, len); 1462b3697b90SSteven Stallion PUTDESC16(rp, &dp->d_control, TXCTL_LASTDESCR); 1463b3697b90SSteven Stallion 1464b3697b90SSteven Stallion SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORDEV); 1465b3697b90SSteven Stallion 1466b3697b90SSteven Stallion efep->efe_opackets++; 1467b3697b90SSteven Stallion efep->efe_obytes += len; 1468b3697b90SSteven Stallion 1469b3697b90SSteven Stallion if (*bp->b_kaddr & 0x01) { 1470b3697b90SSteven Stallion if (bcmp(bp->b_kaddr, efe_broadcast, ETHERADDRL) == 0) { 1471b3697b90SSteven Stallion efep->efe_brdcstxmt++; 1472b3697b90SSteven Stallion } else { 1473b3697b90SSteven Stallion efep->efe_multixmt++; 1474b3697b90SSteven Stallion } 1475b3697b90SSteven Stallion } 1476b3697b90SSteven Stallion 1477b3697b90SSteven Stallion efep->efe_tx_desc = NEXTDESC(rp, efep->efe_tx_desc); 1478b3697b90SSteven Stallion 1479b3697b90SSteven Stallion return (DDI_SUCCESS); 1480b3697b90SSteven Stallion } 1481b3697b90SSteven Stallion 1482b3697b90SSteven Stallion void 1483b3697b90SSteven Stallion efe_send_done(efe_t *efep) 1484b3697b90SSteven Stallion { 1485b3697b90SSteven Stallion efe_ring_t *rp; 1486b3697b90SSteven Stallion 1487b3697b90SSteven Stallion ASSERT(mutex_owned(&efep->efe_txlock)); 1488b3697b90SSteven Stallion 1489b3697b90SSteven Stallion rp = efep->efe_tx_ring; 1490b3697b90SSteven Stallion 1491b3697b90SSteven Stallion for (;;) { 1492b3697b90SSteven Stallion efe_desc_t *dp; 1493b3697b90SSteven Stallion uint16_t status; 1494b3697b90SSteven Stallion 1495b3697b90SSteven Stallion dp = GETDESC(rp, efep->efe_tx_sent); 1496b3697b90SSteven Stallion SYNCDESC(rp, efep->efe_tx_sent, DDI_DMA_SYNC_FORKERNEL); 1497b3697b90SSteven Stallion 1498b3697b90SSteven Stallion status = GETDESC16(rp, &dp->d_status); 1499b3697b90SSteven Stallion 1500b3697b90SSteven Stallion /* Stop if device owns descriptor */ 1501b3697b90SSteven Stallion if (status & TXSTAT_OWNER) { 1502b3697b90SSteven Stallion break; 1503b3697b90SSteven Stallion } 1504b3697b90SSteven Stallion 1505b3697b90SSteven Stallion if (status & TXSTAT_PTX) { 1506b3697b90SSteven Stallion if (!(status & TXSTAT_ND)) { 1507b3697b90SSteven Stallion efep->efe_defer_xmts++; 1508b3697b90SSteven Stallion } 1509b3697b90SSteven Stallion if (status & TXSTAT_COLL) { 1510b3697b90SSteven Stallion efep->efe_first_collisions++; 1511b3697b90SSteven Stallion } 1512b3697b90SSteven Stallion 1513b3697b90SSteven Stallion } else { 1514b3697b90SSteven Stallion efep->efe_oerrors++; 1515b3697b90SSteven Stallion 1516b3697b90SSteven Stallion if (status & TXSTAT_CSL) { 1517b3697b90SSteven Stallion efep->efe_carrier_errors++; 1518b3697b90SSteven Stallion } 1519b3697b90SSteven Stallion if (status & TXSTAT_UFLO) { 1520b3697b90SSteven Stallion efep->efe_uflo++; 1521b3697b90SSteven Stallion } 1522b3697b90SSteven Stallion if (status & TXSTAT_OWC) { 1523b3697b90SSteven Stallion efep->efe_tx_late_collisions++; 1524b3697b90SSteven Stallion } 1525b3697b90SSteven Stallion if (status & TXSTAT_DEFER) { 1526b3697b90SSteven Stallion efep->efe_jabber_errors++; 1527b3697b90SSteven Stallion } 1528b3697b90SSteven Stallion if (status & TXSTAT_EXCOLL) { 1529b3697b90SSteven Stallion efep->efe_ex_collisions++; 1530b3697b90SSteven Stallion } 1531b3697b90SSteven Stallion } 1532b3697b90SSteven Stallion 1533b3697b90SSteven Stallion efep->efe_collisions += 1534b3697b90SSteven Stallion (status >> TXSTAT_CCNT) & TXSTAT_CCNTMASK; 1535b3697b90SSteven Stallion 1536b3697b90SSteven Stallion efep->efe_tx_sent = NEXTDESC(rp, efep->efe_tx_sent); 1537b3697b90SSteven Stallion } 1538b3697b90SSteven Stallion } 1539b3697b90SSteven Stallion 1540b3697b90SSteven Stallion void 1541b3697b90SSteven Stallion efe_getaddr(efe_t *efep, uint8_t *macaddr) 1542b3697b90SSteven Stallion { 1543b3697b90SSteven Stallion efe_eeprom_read(efep, macaddr, ETHERADDRL, 0x0); 1544b3697b90SSteven Stallion 1545b3697b90SSteven Stallion efe_debug(efep->efe_dip, 1546b3697b90SSteven Stallion "factory address is %02x:%02x:%02x:%02x:%02x:%02x\n", 1547b3697b90SSteven Stallion macaddr[0], macaddr[1], macaddr[2], macaddr[3], 1548b3697b90SSteven Stallion macaddr[4], macaddr[5]); 1549b3697b90SSteven Stallion } 1550b3697b90SSteven Stallion 1551b3697b90SSteven Stallion void 1552b3697b90SSteven Stallion efe_setaddr(efe_t *efep, uint8_t *macaddr) 1553b3697b90SSteven Stallion { 1554b3697b90SSteven Stallion uint16_t val; 1555b3697b90SSteven Stallion 1556b3697b90SSteven Stallion bcopy(macaddr, &val, sizeof (uint16_t)); 1557b3697b90SSteven Stallion PUTCSR(efep, CSR_LAN0, val); 1558b3697b90SSteven Stallion macaddr += sizeof (uint16_t); 1559b3697b90SSteven Stallion 1560b3697b90SSteven Stallion bcopy(macaddr, &val, sizeof (uint16_t)); 1561b3697b90SSteven Stallion PUTCSR(efep, CSR_LAN1, val); 1562b3697b90SSteven Stallion macaddr += sizeof (uint16_t); 1563b3697b90SSteven Stallion 1564b3697b90SSteven Stallion bcopy(macaddr, &val, sizeof (uint16_t)); 1565b3697b90SSteven Stallion PUTCSR(efep, CSR_LAN2, val); 1566b3697b90SSteven Stallion } 1567b3697b90SSteven Stallion 1568b3697b90SSteven Stallion void 1569b3697b90SSteven Stallion efe_setmchash(efe_t *efep, uint16_t *mchash) 1570b3697b90SSteven Stallion { 1571b3697b90SSteven Stallion PUTCSR(efep, CSR_MC0, mchash[0]); 1572b3697b90SSteven Stallion PUTCSR(efep, CSR_MC1, mchash[1]); 1573b3697b90SSteven Stallion PUTCSR(efep, CSR_MC2, mchash[2]); 1574b3697b90SSteven Stallion PUTCSR(efep, CSR_MC3, mchash[3]); 1575b3697b90SSteven Stallion } 1576b3697b90SSteven Stallion 1577b3697b90SSteven Stallion void 1578b3697b90SSteven Stallion efe_eeprom_read(efe_t *efep, uint8_t *buf, size_t len, uint8_t addr) 1579b3697b90SSteven Stallion { 1580b3697b90SSteven Stallion int addrlen; 1581b3697b90SSteven Stallion 1582b3697b90SSteven Stallion ASSERT(len & ~0x1); /* non-zero; word-aligned */ 1583b3697b90SSteven Stallion 1584b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS); 1585b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1586b3697b90SSteven Stallion 1587b3697b90SSteven Stallion addrlen = (GETCSR(efep, CSR_EECTL) & EECTL_SIZE ? 1588b3697b90SSteven Stallion AT93C46_ADDRLEN : AT93C56_ADDRLEN); 1589b3697b90SSteven Stallion 1590b3697b90SSteven Stallion for (int i = 0; i < len / sizeof (uint16_t); ++i) { 1591b3697b90SSteven Stallion uint16_t val = efe_eeprom_readw(efep, addrlen, addr + i); 1592b3697b90SSteven Stallion bcopy(&val, buf, sizeof (uint16_t)); 1593b3697b90SSteven Stallion buf += sizeof (uint16_t); 1594b3697b90SSteven Stallion } 1595b3697b90SSteven Stallion } 1596b3697b90SSteven Stallion 1597b3697b90SSteven Stallion uint16_t 1598b3697b90SSteven Stallion efe_eeprom_readw(efe_t *efep, int addrlen, uint8_t addr) 1599b3697b90SSteven Stallion { 1600b3697b90SSteven Stallion uint16_t val = 0; 1601b3697b90SSteven Stallion 1602b3697b90SSteven Stallion ASSERT(addrlen > 0); 1603b3697b90SSteven Stallion 1604b3697b90SSteven Stallion /* Write Start Bit (SB) */ 1605b3697b90SSteven Stallion efe_eeprom_writebit(efep, 1); 1606b3697b90SSteven Stallion 1607b3697b90SSteven Stallion /* Write READ instruction */ 1608b3697b90SSteven Stallion efe_eeprom_writebit(efep, 1); 1609b3697b90SSteven Stallion efe_eeprom_writebit(efep, 0); 1610b3697b90SSteven Stallion 1611b3697b90SSteven Stallion /* Write EEPROM address */ 1612b3697b90SSteven Stallion for (int i = addrlen - 1; i >= 0; --i) { 1613b3697b90SSteven Stallion efe_eeprom_writebit(efep, addr & 1U << i); 1614b3697b90SSteven Stallion } 1615b3697b90SSteven Stallion 1616b3697b90SSteven Stallion /* Read EEPROM word */ 1617b3697b90SSteven Stallion for (int i = EEPROM_WORDSZ - 1; i >= 0; --i) { 1618b3697b90SSteven Stallion val |= efe_eeprom_readbit(efep) << i; 1619b3697b90SSteven Stallion } 1620b3697b90SSteven Stallion 1621b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE); 1622b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1623b3697b90SSteven Stallion 1624b3697b90SSteven Stallion return (val); 1625b3697b90SSteven Stallion } 1626b3697b90SSteven Stallion 1627b3697b90SSteven Stallion inline int 1628b3697b90SSteven Stallion efe_eeprom_readbit(efe_t *efep) 1629b3697b90SSteven Stallion { 1630b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS); 1631b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1632b3697b90SSteven Stallion 1633b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS | 1634b3697b90SSteven Stallion EECTL_EESK); 1635b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1636b3697b90SSteven Stallion 1637b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS); 1638b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1639b3697b90SSteven Stallion 1640b3697b90SSteven Stallion return (!!(GETCSR(efep, CSR_EECTL) & EECTL_EEDO)); 1641b3697b90SSteven Stallion } 1642b3697b90SSteven Stallion 1643b3697b90SSteven Stallion inline void 1644b3697b90SSteven Stallion efe_eeprom_writebit(efe_t *efep, int bit) 1645b3697b90SSteven Stallion { 1646b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS); 1647b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1648b3697b90SSteven Stallion 1649b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS | 1650b3697b90SSteven Stallion EECTL_EESK | (bit ? EECTL_EEDI : 0)); 1651b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1652b3697b90SSteven Stallion 1653b3697b90SSteven Stallion PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS); 1654b3697b90SSteven Stallion drv_usecwait(EEPROM_DELAY); 1655b3697b90SSteven Stallion } 1656b3697b90SSteven Stallion 1657b3697b90SSteven Stallion void 1658b3697b90SSteven Stallion efe_dprintf(dev_info_t *dip, int level, const char *format, ...) 1659b3697b90SSteven Stallion { 1660b3697b90SSteven Stallion va_list ap; 1661b3697b90SSteven Stallion char buf[255]; 1662b3697b90SSteven Stallion 1663b3697b90SSteven Stallion va_start(ap, format); 1664b3697b90SSteven Stallion 1665b3697b90SSteven Stallion (void) vsnprintf(buf, sizeof (buf), format, ap); 1666b3697b90SSteven Stallion 1667b3697b90SSteven Stallion cmn_err(level, "?%s%d %s", ddi_driver_name(dip), 1668b3697b90SSteven Stallion ddi_get_instance(dip), buf); 1669b3697b90SSteven Stallion 1670b3697b90SSteven Stallion va_end(ap); 1671b3697b90SSteven Stallion } 1672