19860Sgdamore@opensolaris.org /* 29860Sgdamore@opensolaris.org * CDDL HEADER START 39860Sgdamore@opensolaris.org * 49860Sgdamore@opensolaris.org * The contents of this file are subject to the terms of the 59860Sgdamore@opensolaris.org * Common Development and Distribution License (the "License"). 69860Sgdamore@opensolaris.org * You may not use this file except in compliance with the License. 79860Sgdamore@opensolaris.org * 89860Sgdamore@opensolaris.org * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99860Sgdamore@opensolaris.org * or http://www.opensolaris.org/os/licensing. 109860Sgdamore@opensolaris.org * See the License for the specific language governing permissions 119860Sgdamore@opensolaris.org * and limitations under the License. 129860Sgdamore@opensolaris.org * 139860Sgdamore@opensolaris.org * When distributing Covered Code, include this CDDL HEADER in each 149860Sgdamore@opensolaris.org * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159860Sgdamore@opensolaris.org * If applicable, add the following below this CDDL HEADER, with the 169860Sgdamore@opensolaris.org * fields enclosed by brackets "[]" replaced with your own identifying 179860Sgdamore@opensolaris.org * information: Portions Copyright [yyyy] [name of copyright owner] 189860Sgdamore@opensolaris.org * 199860Sgdamore@opensolaris.org * CDDL HEADER END 209860Sgdamore@opensolaris.org */ 219860Sgdamore@opensolaris.org 229860Sgdamore@opensolaris.org /* 239860Sgdamore@opensolaris.org * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 249860Sgdamore@opensolaris.org * Use is subject to license terms. 259860Sgdamore@opensolaris.org */ 269860Sgdamore@opensolaris.org 279860Sgdamore@opensolaris.org 289860Sgdamore@opensolaris.org /* 299860Sgdamore@opensolaris.org * dnet -- DEC 21x4x 309860Sgdamore@opensolaris.org * 319860Sgdamore@opensolaris.org * Currently supports: 329860Sgdamore@opensolaris.org * 21040, 21041, 21140, 21142, 21143 339860Sgdamore@opensolaris.org * SROM versions 1, 3, 3.03, 4 349860Sgdamore@opensolaris.org * TP, AUI, BNC, 100BASETX, 100BASET4 359860Sgdamore@opensolaris.org * 369860Sgdamore@opensolaris.org * XXX NEEDSWORK 379860Sgdamore@opensolaris.org * All media SHOULD work, FX is untested 389860Sgdamore@opensolaris.org * 39*10340Sstallion@opensolaris.org * Depends on the Generic LAN Driver utility functions in /kernel/misc/mac 409860Sgdamore@opensolaris.org */ 419860Sgdamore@opensolaris.org 429860Sgdamore@opensolaris.org #define BUG_4010796 /* See 4007871, 4010796 */ 439860Sgdamore@opensolaris.org 449860Sgdamore@opensolaris.org #include <sys/types.h> 459860Sgdamore@opensolaris.org #include <sys/errno.h> 469860Sgdamore@opensolaris.org #include <sys/param.h> 479860Sgdamore@opensolaris.org #include <sys/stropts.h> 489860Sgdamore@opensolaris.org #include <sys/stream.h> 499860Sgdamore@opensolaris.org #include <sys/kmem.h> 509860Sgdamore@opensolaris.org #include <sys/conf.h> 519860Sgdamore@opensolaris.org #include <sys/devops.h> 529860Sgdamore@opensolaris.org #include <sys/ksynch.h> 539860Sgdamore@opensolaris.org #include <sys/stat.h> 549860Sgdamore@opensolaris.org #include <sys/modctl.h> 559860Sgdamore@opensolaris.org #include <sys/debug.h> 569860Sgdamore@opensolaris.org #include <sys/dlpi.h> 579860Sgdamore@opensolaris.org #include <sys/ethernet.h> 58*10340Sstallion@opensolaris.org #include <sys/vlan.h> 59*10340Sstallion@opensolaris.org #include <sys/mac.h> 60*10340Sstallion@opensolaris.org #include <sys/mac_ether.h> 61*10340Sstallion@opensolaris.org #include <sys/mac_provider.h> 629860Sgdamore@opensolaris.org #include <sys/pci.h> 639860Sgdamore@opensolaris.org #include <sys/ddi.h> 649860Sgdamore@opensolaris.org #include <sys/sunddi.h> 65*10340Sstallion@opensolaris.org #include <sys/strsun.h> 669860Sgdamore@opensolaris.org 679860Sgdamore@opensolaris.org #include "dnet_mii.h" 689860Sgdamore@opensolaris.org #include "dnet.h" 699860Sgdamore@opensolaris.org 709860Sgdamore@opensolaris.org /* 719860Sgdamore@opensolaris.org * Declarations and Module Linkage 729860Sgdamore@opensolaris.org */ 739860Sgdamore@opensolaris.org 749860Sgdamore@opensolaris.org #define IDENT "DNET 21x4x" 759860Sgdamore@opensolaris.org 769860Sgdamore@opensolaris.org /* 779860Sgdamore@opensolaris.org * #define DNET_NOISY 789860Sgdamore@opensolaris.org * #define SROMDEBUG 799860Sgdamore@opensolaris.org * #define SROMDUMPSTRUCTURES 809860Sgdamore@opensolaris.org */ 819860Sgdamore@opensolaris.org 829860Sgdamore@opensolaris.org #ifdef DNETDEBUG 839860Sgdamore@opensolaris.org #ifdef DNET_NOISY 849860Sgdamore@opensolaris.org int dnetdebug = -1; 859860Sgdamore@opensolaris.org #else 869860Sgdamore@opensolaris.org int dnetdebug = 0; 879860Sgdamore@opensolaris.org #endif 889860Sgdamore@opensolaris.org #endif 899860Sgdamore@opensolaris.org 909860Sgdamore@opensolaris.org /* used for message allocated using desballoc() */ 919860Sgdamore@opensolaris.org struct free_ptr { 929860Sgdamore@opensolaris.org struct free_rtn free_rtn; 939860Sgdamore@opensolaris.org caddr_t buf; 949860Sgdamore@opensolaris.org }; 959860Sgdamore@opensolaris.org 969860Sgdamore@opensolaris.org struct rbuf_list { 979860Sgdamore@opensolaris.org struct rbuf_list *rbuf_next; /* next in the list */ 989860Sgdamore@opensolaris.org caddr_t rbuf_vaddr; /* virual addr of the buf */ 999860Sgdamore@opensolaris.org uint32_t rbuf_paddr; /* physical addr of the buf */ 1009860Sgdamore@opensolaris.org uint32_t rbuf_endpaddr; /* physical addr at the end */ 1019860Sgdamore@opensolaris.org ddi_dma_handle_t rbuf_dmahdl; /* dma handle */ 1029860Sgdamore@opensolaris.org ddi_acc_handle_t rbuf_acchdl; /* handle for DDI functions */ 1039860Sgdamore@opensolaris.org }; 1049860Sgdamore@opensolaris.org 1059860Sgdamore@opensolaris.org /* Required system entry points */ 106*10340Sstallion@opensolaris.org static int dnet_probe(dev_info_t *); 107*10340Sstallion@opensolaris.org static int dnet_attach(dev_info_t *, ddi_attach_cmd_t); 108*10340Sstallion@opensolaris.org static int dnet_detach(dev_info_t *, ddi_detach_cmd_t); 109*10340Sstallion@opensolaris.org static int dnet_quiesce(dev_info_t *); 110*10340Sstallion@opensolaris.org 111*10340Sstallion@opensolaris.org /* Required driver entry points for GLDv3 */ 112*10340Sstallion@opensolaris.org static int dnet_m_start(void *); 113*10340Sstallion@opensolaris.org static void dnet_m_stop(void *); 114*10340Sstallion@opensolaris.org static int dnet_m_getstat(void *, uint_t, uint64_t *); 115*10340Sstallion@opensolaris.org static int dnet_m_setpromisc(void *, boolean_t); 116*10340Sstallion@opensolaris.org static int dnet_m_multicst(void *, boolean_t, const uint8_t *); 117*10340Sstallion@opensolaris.org static int dnet_m_unicst(void *, const uint8_t *); 118*10340Sstallion@opensolaris.org static mblk_t *dnet_m_tx(void *, mblk_t *); 119*10340Sstallion@opensolaris.org 120*10340Sstallion@opensolaris.org static uint_t dnet_intr(caddr_t); 1219860Sgdamore@opensolaris.org 1229860Sgdamore@opensolaris.org /* Internal functions used by the above entry points */ 1239860Sgdamore@opensolaris.org static void write_gpr(struct dnetinstance *dnetp, uint32_t val); 124*10340Sstallion@opensolaris.org static void dnet_reset_board(struct dnetinstance *); 125*10340Sstallion@opensolaris.org static void dnet_init_board(struct dnetinstance *); 126*10340Sstallion@opensolaris.org static void dnet_chip_init(struct dnetinstance *); 127*10340Sstallion@opensolaris.org static uint32_t hashindex(const uint8_t *); 128*10340Sstallion@opensolaris.org static int dnet_start(struct dnetinstance *); 129*10340Sstallion@opensolaris.org static int dnet_set_addr(struct dnetinstance *); 130*10340Sstallion@opensolaris.org 131*10340Sstallion@opensolaris.org static boolean_t dnet_send(struct dnetinstance *, mblk_t *); 132*10340Sstallion@opensolaris.org 133*10340Sstallion@opensolaris.org static void dnet_getp(struct dnetinstance *); 134*10340Sstallion@opensolaris.org static void update_rx_stats(struct dnetinstance *, int); 135*10340Sstallion@opensolaris.org static void update_tx_stats(struct dnetinstance *, int); 1369860Sgdamore@opensolaris.org 1379860Sgdamore@opensolaris.org /* Media Selection Setup Routines */ 138*10340Sstallion@opensolaris.org static void set_gpr(struct dnetinstance *); 139*10340Sstallion@opensolaris.org static void set_opr(struct dnetinstance *); 140*10340Sstallion@opensolaris.org static void set_sia(struct dnetinstance *); 1419860Sgdamore@opensolaris.org 1429860Sgdamore@opensolaris.org /* Buffer Management Routines */ 143*10340Sstallion@opensolaris.org static int dnet_alloc_bufs(struct dnetinstance *); 144*10340Sstallion@opensolaris.org static void dnet_free_bufs(struct dnetinstance *); 145*10340Sstallion@opensolaris.org static void dnet_init_txrx_bufs(struct dnetinstance *); 146*10340Sstallion@opensolaris.org static int alloc_descriptor(struct dnetinstance *); 147*10340Sstallion@opensolaris.org static void dnet_reclaim_Tx_desc(struct dnetinstance *); 1489860Sgdamore@opensolaris.org static int dnet_rbuf_init(dev_info_t *, int); 1499860Sgdamore@opensolaris.org static int dnet_rbuf_destroy(); 1509860Sgdamore@opensolaris.org static struct rbuf_list *dnet_rbuf_alloc(dev_info_t *, int); 1519860Sgdamore@opensolaris.org static void dnet_rbuf_free(caddr_t); 1529860Sgdamore@opensolaris.org static void dnet_freemsg_buf(struct free_ptr *); 1539860Sgdamore@opensolaris.org 154*10340Sstallion@opensolaris.org static void setup_block(struct dnetinstance *); 1559860Sgdamore@opensolaris.org 1569860Sgdamore@opensolaris.org /* SROM read functions */ 1579860Sgdamore@opensolaris.org static int dnet_read_srom(dev_info_t *, int, ddi_acc_handle_t, caddr_t, 1589860Sgdamore@opensolaris.org uchar_t *, int); 1599860Sgdamore@opensolaris.org static void dnet_read21040addr(dev_info_t *, ddi_acc_handle_t, caddr_t, 1609860Sgdamore@opensolaris.org uchar_t *, int *); 1619860Sgdamore@opensolaris.org static void dnet_read21140srom(ddi_acc_handle_t, caddr_t, uchar_t *, int); 1629860Sgdamore@opensolaris.org static int get_alternative_srom_image(dev_info_t *, uchar_t *, int); 1639860Sgdamore@opensolaris.org static void dnet_print_srom(SROM_FORMAT *sr); 1649860Sgdamore@opensolaris.org static void dnet_dump_leaf(LEAF_FORMAT *leaf); 1659860Sgdamore@opensolaris.org static void dnet_dump_block(media_block_t *block); 1669860Sgdamore@opensolaris.org #ifdef BUG_4010796 1679860Sgdamore@opensolaris.org static void set_alternative_srom_image(dev_info_t *, uchar_t *, int); 168*10340Sstallion@opensolaris.org static int dnet_hack(dev_info_t *); 1699860Sgdamore@opensolaris.org #endif 1709860Sgdamore@opensolaris.org 171*10340Sstallion@opensolaris.org static int dnet_hack_interrupts(struct dnetinstance *, int); 1729860Sgdamore@opensolaris.org static int dnet_detach_hacked_interrupt(dev_info_t *devinfo); 173*10340Sstallion@opensolaris.org static void enable_interrupts(struct dnetinstance *); 1749860Sgdamore@opensolaris.org 1759860Sgdamore@opensolaris.org /* SROM parsing functions */ 1769860Sgdamore@opensolaris.org static void dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, 1779860Sgdamore@opensolaris.org uchar_t *vi); 1789860Sgdamore@opensolaris.org static void parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf, 1799860Sgdamore@opensolaris.org uchar_t *vi); 1809860Sgdamore@opensolaris.org static uchar_t *parse_media_block(struct dnetinstance *dnetp, 1819860Sgdamore@opensolaris.org media_block_t *block, uchar_t *vi); 1829860Sgdamore@opensolaris.org static int check_srom_valid(uchar_t *); 1839860Sgdamore@opensolaris.org static void dnet_dumpbin(char *msg, uchar_t *, int size, int len); 1849860Sgdamore@opensolaris.org static void setup_legacy_blocks(); 1859860Sgdamore@opensolaris.org /* Active Media Determination Routines */ 186*10340Sstallion@opensolaris.org static void find_active_media(struct dnetinstance *); 187*10340Sstallion@opensolaris.org static int send_test_packet(struct dnetinstance *); 188*10340Sstallion@opensolaris.org static int dnet_link_sense(struct dnetinstance *); 1899860Sgdamore@opensolaris.org 1909860Sgdamore@opensolaris.org /* PHY MII Routines */ 1919860Sgdamore@opensolaris.org static ushort_t dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num); 1929860Sgdamore@opensolaris.org static void dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, 1939860Sgdamore@opensolaris.org int reg_dat); 1949860Sgdamore@opensolaris.org static void write_mii(struct dnetinstance *, uint32_t, int); 1959860Sgdamore@opensolaris.org static void mii_tristate(struct dnetinstance *); 196*10340Sstallion@opensolaris.org static void do_phy(struct dnetinstance *); 1979860Sgdamore@opensolaris.org static void dnet_mii_link_cb(dev_info_t *, int, enum mii_phy_state); 198*10340Sstallion@opensolaris.org static void dnet_mii_link_up(struct dnetinstance *); 1999860Sgdamore@opensolaris.org static void set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf); 2009860Sgdamore@opensolaris.org 2019860Sgdamore@opensolaris.org #ifdef DNETDEBUG 2029860Sgdamore@opensolaris.org uint32_t dnet_usecelapsed(struct dnetinstance *dnetp); 2039860Sgdamore@opensolaris.org void dnet_timestamp(struct dnetinstance *, char *); 2049860Sgdamore@opensolaris.org void dnet_usectimeout(struct dnetinstance *, uint32_t, int, timercb_t); 2059860Sgdamore@opensolaris.org #endif 2069860Sgdamore@opensolaris.org static char *media_str[] = { 2079860Sgdamore@opensolaris.org "10BaseT", 2089860Sgdamore@opensolaris.org "10Base2", 2099860Sgdamore@opensolaris.org "10Base5", 2109860Sgdamore@opensolaris.org "100BaseTX", 2119860Sgdamore@opensolaris.org "10BaseT FD", 2129860Sgdamore@opensolaris.org "100BaseTX FD", 2139860Sgdamore@opensolaris.org "100BaseT4", 2149860Sgdamore@opensolaris.org "100BaseFX", 2159860Sgdamore@opensolaris.org "100BaseFX FD", 2169860Sgdamore@opensolaris.org "MII" 2179860Sgdamore@opensolaris.org }; 2189860Sgdamore@opensolaris.org 2199860Sgdamore@opensolaris.org /* default SROM info for cards with no SROMs */ 2209860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_default_100; 2219860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_asante; 2229860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_phylegacy; 2239860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_cogent_100; 2249860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_21041; 2259860Sgdamore@opensolaris.org static LEAF_FORMAT leaf_21040; 2269860Sgdamore@opensolaris.org 227*10340Sstallion@opensolaris.org /* rx buffer size (rounded up to 4) */ 228*10340Sstallion@opensolaris.org int rx_buf_size = (ETHERMAX + ETHERFCSL + VLAN_TAGSZ + 3) & ~3; 2299860Sgdamore@opensolaris.org 2309860Sgdamore@opensolaris.org int max_rx_desc_21040 = MAX_RX_DESC_21040; 2319860Sgdamore@opensolaris.org int max_rx_desc_21140 = MAX_RX_DESC_21140; 2329860Sgdamore@opensolaris.org int max_tx_desc = MAX_TX_DESC; 2339860Sgdamore@opensolaris.org int dnet_xmit_threshold = MAX_TX_DESC >> 2; /* XXX need tuning? */ 2349860Sgdamore@opensolaris.org 2359860Sgdamore@opensolaris.org static kmutex_t dnet_rbuf_lock; /* mutex to protect rbuf_list data */ 2369860Sgdamore@opensolaris.org 2379860Sgdamore@opensolaris.org /* used for buffers allocated by ddi_dma_mem_alloc() */ 2389860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr = { 2399860Sgdamore@opensolaris.org DMA_ATTR_V0, /* dma_attr version */ 2409860Sgdamore@opensolaris.org 0, /* dma_attr_addr_lo */ 2419860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 2429860Sgdamore@opensolaris.org 0x7FFFFFFF, /* dma_attr_count_max */ 2439860Sgdamore@opensolaris.org 4, /* dma_attr_align */ 2449860Sgdamore@opensolaris.org 0x3F, /* dma_attr_burstsizes */ 2459860Sgdamore@opensolaris.org 1, /* dma_attr_minxfer */ 2469860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 2479860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 2489860Sgdamore@opensolaris.org 1, /* dma_attr_sgllen */ 2499860Sgdamore@opensolaris.org 1, /* dma_attr_granular */ 2509860Sgdamore@opensolaris.org 0, /* dma_attr_flags */ 2519860Sgdamore@opensolaris.org }; 2529860Sgdamore@opensolaris.org 2539860Sgdamore@opensolaris.org /* used for buffers allocated for rbuf, allow 2 cookies */ 2549860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr_rb = { 2559860Sgdamore@opensolaris.org DMA_ATTR_V0, /* dma_attr version */ 2569860Sgdamore@opensolaris.org 0, /* dma_attr_addr_lo */ 2579860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 2589860Sgdamore@opensolaris.org 0x7FFFFFFF, /* dma_attr_count_max */ 2599860Sgdamore@opensolaris.org 4, /* dma_attr_align */ 2609860Sgdamore@opensolaris.org 0x3F, /* dma_attr_burstsizes */ 2619860Sgdamore@opensolaris.org 1, /* dma_attr_minxfer */ 2629860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 2639860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 2649860Sgdamore@opensolaris.org 2, /* dma_attr_sgllen */ 2659860Sgdamore@opensolaris.org 1, /* dma_attr_granular */ 2669860Sgdamore@opensolaris.org 0, /* dma_attr_flags */ 2679860Sgdamore@opensolaris.org }; 2689860Sgdamore@opensolaris.org /* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */ 2699860Sgdamore@opensolaris.org static ddi_dma_attr_t dma_attr_tx = { 2709860Sgdamore@opensolaris.org DMA_ATTR_V0, /* dma_attr version */ 2719860Sgdamore@opensolaris.org 0, /* dma_attr_addr_lo */ 2729860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 2739860Sgdamore@opensolaris.org 0x7FFFFFFF, /* dma_attr_count_max */ 2749860Sgdamore@opensolaris.org 1, /* dma_attr_align */ 2759860Sgdamore@opensolaris.org 0x3F, /* dma_attr_burstsizes */ 2769860Sgdamore@opensolaris.org 1, /* dma_attr_minxfer */ 2779860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 2789860Sgdamore@opensolaris.org (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 2799860Sgdamore@opensolaris.org 0x7FFF, /* dma_attr_sgllen */ 2809860Sgdamore@opensolaris.org 1, /* dma_attr_granular */ 2819860Sgdamore@opensolaris.org 0, /* dma_attr_flags */ 2829860Sgdamore@opensolaris.org }; 2839860Sgdamore@opensolaris.org 2849860Sgdamore@opensolaris.org static ddi_device_acc_attr_t accattr = { 2859860Sgdamore@opensolaris.org DDI_DEVICE_ATTR_V0, 2869860Sgdamore@opensolaris.org DDI_NEVERSWAP_ACC, 2879860Sgdamore@opensolaris.org DDI_STRICTORDER_ACC, 2889860Sgdamore@opensolaris.org }; 2899860Sgdamore@opensolaris.org 2909860Sgdamore@opensolaris.org uchar_t dnet_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 2919860Sgdamore@opensolaris.org 2929860Sgdamore@opensolaris.org /* Standard Module linkage initialization for a Streams driver */ 2939860Sgdamore@opensolaris.org extern struct mod_ops mod_driverops; 2949860Sgdamore@opensolaris.org 295*10340Sstallion@opensolaris.org DDI_DEFINE_STREAM_OPS(dnet_devops, nulldev, dnet_probe, dnet_attach, 296*10340Sstallion@opensolaris.org dnet_detach, nodev, NULL, D_MP, NULL, dnet_quiesce); 297*10340Sstallion@opensolaris.org 298*10340Sstallion@opensolaris.org static struct modldrv dnet_modldrv = { 2999860Sgdamore@opensolaris.org &mod_driverops, /* Type of module. This one is a driver */ 3009860Sgdamore@opensolaris.org IDENT, /* short description */ 301*10340Sstallion@opensolaris.org &dnet_devops /* driver specific ops */ 302*10340Sstallion@opensolaris.org }; 303*10340Sstallion@opensolaris.org 304*10340Sstallion@opensolaris.org static struct modlinkage dnet_modlinkage = { 305*10340Sstallion@opensolaris.org MODREV_1, /* ml_rev */ 306*10340Sstallion@opensolaris.org { &dnet_modldrv, NULL } /* ml_linkage */ 3079860Sgdamore@opensolaris.org }; 3089860Sgdamore@opensolaris.org 309*10340Sstallion@opensolaris.org static mac_callbacks_t dnet_m_callbacks = { 310*10340Sstallion@opensolaris.org 0, /* mc_callbacks */ 311*10340Sstallion@opensolaris.org dnet_m_getstat, /* mc_getstat */ 312*10340Sstallion@opensolaris.org dnet_m_start, /* mc_start */ 313*10340Sstallion@opensolaris.org dnet_m_stop, /* mc_stop */ 314*10340Sstallion@opensolaris.org dnet_m_setpromisc, /* mc_setpromisc */ 315*10340Sstallion@opensolaris.org dnet_m_multicst, /* mc_multicst */ 316*10340Sstallion@opensolaris.org dnet_m_unicst, /* mc_unicst */ 317*10340Sstallion@opensolaris.org dnet_m_tx, /* mc_tx */ 318*10340Sstallion@opensolaris.org NULL, /* mc_ioctl */ 319*10340Sstallion@opensolaris.org NULL, /* mc_getcapab */ 320*10340Sstallion@opensolaris.org NULL, /* mc_open */ 321*10340Sstallion@opensolaris.org NULL /* mc_close */ 3229860Sgdamore@opensolaris.org }; 3239860Sgdamore@opensolaris.org 3249860Sgdamore@opensolaris.org /* 3259860Sgdamore@opensolaris.org * Passed to the hacked interrupt for multiport Cogent and ZNYX cards with 3269860Sgdamore@opensolaris.org * dodgy interrupt routing 3279860Sgdamore@opensolaris.org */ 3289860Sgdamore@opensolaris.org #define MAX_INST 8 /* Maximum instances on a multiport adapter. */ 3299860Sgdamore@opensolaris.org struct hackintr_inf 3309860Sgdamore@opensolaris.org { 331*10340Sstallion@opensolaris.org struct dnetinstance *dnetps[MAX_INST]; /* dnetps for each port */ 3329860Sgdamore@opensolaris.org dev_info_t *devinfo; /* Devinfo of the primary device */ 3339860Sgdamore@opensolaris.org kmutex_t lock; 3349860Sgdamore@opensolaris.org /* Ensures the interrupt doesn't get called while detaching */ 3359860Sgdamore@opensolaris.org }; 3369860Sgdamore@opensolaris.org static char hackintr_propname[] = "InterruptData"; 3379860Sgdamore@opensolaris.org static char macoffset_propname[] = "MAC_offset"; 3389860Sgdamore@opensolaris.org static char speed_propname[] = "speed"; 3399860Sgdamore@opensolaris.org static char ofloprob_propname[] = "dmaworkaround"; 3409860Sgdamore@opensolaris.org static char duplex_propname[] = "full-duplex"; /* Must agree with MII */ 3419860Sgdamore@opensolaris.org static char printsrom_propname[] = "print-srom"; 3429860Sgdamore@opensolaris.org 3439860Sgdamore@opensolaris.org static uint_t dnet_hack_intr(struct hackintr_inf *); 3449860Sgdamore@opensolaris.org 3459860Sgdamore@opensolaris.org int 3469860Sgdamore@opensolaris.org _init(void) 3479860Sgdamore@opensolaris.org { 3489860Sgdamore@opensolaris.org int i; 3499860Sgdamore@opensolaris.org 3509860Sgdamore@opensolaris.org /* Configure fake sroms for legacy cards */ 3519860Sgdamore@opensolaris.org mutex_init(&dnet_rbuf_lock, NULL, MUTEX_DRIVER, NULL); 3529860Sgdamore@opensolaris.org setup_legacy_blocks(); 353*10340Sstallion@opensolaris.org 354*10340Sstallion@opensolaris.org mac_init_ops(&dnet_devops, "dnet"); 355*10340Sstallion@opensolaris.org 356*10340Sstallion@opensolaris.org if ((i = mod_install(&dnet_modlinkage)) != 0) { 357*10340Sstallion@opensolaris.org mac_fini_ops(&dnet_devops); 3589860Sgdamore@opensolaris.org mutex_destroy(&dnet_rbuf_lock); 3599860Sgdamore@opensolaris.org } 3609860Sgdamore@opensolaris.org return (i); 3619860Sgdamore@opensolaris.org } 3629860Sgdamore@opensolaris.org 3639860Sgdamore@opensolaris.org int 3649860Sgdamore@opensolaris.org _fini(void) 3659860Sgdamore@opensolaris.org { 3669860Sgdamore@opensolaris.org int i; 367*10340Sstallion@opensolaris.org 368*10340Sstallion@opensolaris.org if ((i = mod_remove(&dnet_modlinkage)) == 0) { 369*10340Sstallion@opensolaris.org mac_fini_ops(&dnet_devops); 370*10340Sstallion@opensolaris.org 3719860Sgdamore@opensolaris.org /* loop until all the receive buffers are freed */ 3729860Sgdamore@opensolaris.org while (dnet_rbuf_destroy() != 0) { 3739860Sgdamore@opensolaris.org delay(drv_usectohz(100000)); 3749860Sgdamore@opensolaris.org #ifdef DNETDEBUG 3759860Sgdamore@opensolaris.org if (dnetdebug & DNETDDI) 3769860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet _fini delay"); 3779860Sgdamore@opensolaris.org #endif 3789860Sgdamore@opensolaris.org } 3799860Sgdamore@opensolaris.org mutex_destroy(&dnet_rbuf_lock); 3809860Sgdamore@opensolaris.org } 3819860Sgdamore@opensolaris.org return (i); 3829860Sgdamore@opensolaris.org } 3839860Sgdamore@opensolaris.org 3849860Sgdamore@opensolaris.org int 3859860Sgdamore@opensolaris.org _info(struct modinfo *modinfop) 3869860Sgdamore@opensolaris.org { 387*10340Sstallion@opensolaris.org return (mod_info(&dnet_modlinkage, modinfop)); 3889860Sgdamore@opensolaris.org } 3899860Sgdamore@opensolaris.org 3909860Sgdamore@opensolaris.org /* 3919860Sgdamore@opensolaris.org * probe(9E) -- Determine if a device is present 3929860Sgdamore@opensolaris.org */ 3939860Sgdamore@opensolaris.org static int 394*10340Sstallion@opensolaris.org dnet_probe(dev_info_t *devinfo) 3959860Sgdamore@opensolaris.org { 3969860Sgdamore@opensolaris.org ddi_acc_handle_t handle; 3979860Sgdamore@opensolaris.org uint16_t vendorid; 3989860Sgdamore@opensolaris.org uint16_t deviceid; 3999860Sgdamore@opensolaris.org 4009860Sgdamore@opensolaris.org if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 4019860Sgdamore@opensolaris.org return (DDI_PROBE_FAILURE); 4029860Sgdamore@opensolaris.org 4039860Sgdamore@opensolaris.org vendorid = pci_config_get16(handle, PCI_CONF_VENID); 4049860Sgdamore@opensolaris.org 4059860Sgdamore@opensolaris.org if (vendorid != DEC_VENDOR_ID) { 4069860Sgdamore@opensolaris.org pci_config_teardown(&handle); 4079860Sgdamore@opensolaris.org return (DDI_PROBE_FAILURE); 4089860Sgdamore@opensolaris.org } 4099860Sgdamore@opensolaris.org 4109860Sgdamore@opensolaris.org deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 4119860Sgdamore@opensolaris.org switch (deviceid) { 4129860Sgdamore@opensolaris.org case DEVICE_ID_21040: 4139860Sgdamore@opensolaris.org case DEVICE_ID_21041: 4149860Sgdamore@opensolaris.org case DEVICE_ID_21140: 4159860Sgdamore@opensolaris.org case DEVICE_ID_21143: /* And 142 */ 4169860Sgdamore@opensolaris.org break; 4179860Sgdamore@opensolaris.org default: 4189860Sgdamore@opensolaris.org pci_config_teardown(&handle); 4199860Sgdamore@opensolaris.org return (DDI_PROBE_FAILURE); 4209860Sgdamore@opensolaris.org } 4219860Sgdamore@opensolaris.org 4229860Sgdamore@opensolaris.org pci_config_teardown(&handle); 4239860Sgdamore@opensolaris.org #ifndef BUG_4010796 4249860Sgdamore@opensolaris.org return (DDI_PROBE_SUCCESS); 4259860Sgdamore@opensolaris.org #else 426*10340Sstallion@opensolaris.org return (dnet_hack(devinfo)); 4279860Sgdamore@opensolaris.org #endif 4289860Sgdamore@opensolaris.org } 4299860Sgdamore@opensolaris.org 4309860Sgdamore@opensolaris.org #ifdef BUG_4010796 4319860Sgdamore@opensolaris.org /* 4329860Sgdamore@opensolaris.org * If we have a device, but we cannot presently access its SROM data, 4339860Sgdamore@opensolaris.org * then we return DDI_PROBE_PARTIAL and hope that sometime later we 4349860Sgdamore@opensolaris.org * will be able to get at the SROM data. This can only happen if we 4359860Sgdamore@opensolaris.org * are a secondary port with no SROM, and the bootstrap failed to set 4369860Sgdamore@opensolaris.org * our DNET_SROM property, and our primary sibling has not yet probed. 4379860Sgdamore@opensolaris.org */ 4389860Sgdamore@opensolaris.org static int 439*10340Sstallion@opensolaris.org dnet_hack(dev_info_t *devinfo) 4409860Sgdamore@opensolaris.org { 4419860Sgdamore@opensolaris.org uchar_t vendor_info[SROM_SIZE]; 4429860Sgdamore@opensolaris.org uint32_t csr; 4439860Sgdamore@opensolaris.org uint16_t deviceid; 4449860Sgdamore@opensolaris.org ddi_acc_handle_t handle; 4459860Sgdamore@opensolaris.org uint32_t retval; 4469860Sgdamore@opensolaris.org int secondary; 4479860Sgdamore@opensolaris.org ddi_acc_handle_t io_handle; 4489860Sgdamore@opensolaris.org caddr_t io_reg; 4499860Sgdamore@opensolaris.org 4509860Sgdamore@opensolaris.org #define DNET_PCI_RNUMBER 1 4519860Sgdamore@opensolaris.org 4529860Sgdamore@opensolaris.org if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 4539860Sgdamore@opensolaris.org return (DDI_PROBE_FAILURE); 4549860Sgdamore@opensolaris.org 4559860Sgdamore@opensolaris.org deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 4569860Sgdamore@opensolaris.org 4579860Sgdamore@opensolaris.org /* 4589860Sgdamore@opensolaris.org * Turn on Master Enable and IO Enable bits. 4599860Sgdamore@opensolaris.org */ 4609860Sgdamore@opensolaris.org csr = pci_config_get32(handle, PCI_CONF_COMM); 4619860Sgdamore@opensolaris.org pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO)); 4629860Sgdamore@opensolaris.org 4639860Sgdamore@opensolaris.org pci_config_teardown(&handle); 4649860Sgdamore@opensolaris.org 4659860Sgdamore@opensolaris.org /* Now map I/O register */ 4669860Sgdamore@opensolaris.org if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, 4679860Sgdamore@opensolaris.org &io_reg, 0, 0, &accattr, &io_handle) != DDI_SUCCESS) { 4689860Sgdamore@opensolaris.org return (DDI_PROBE_FAILURE); 4699860Sgdamore@opensolaris.org } 4709860Sgdamore@opensolaris.org 4719860Sgdamore@opensolaris.org /* 4729860Sgdamore@opensolaris.org * Reset the chip 4739860Sgdamore@opensolaris.org */ 4749860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), SW_RESET); 4759860Sgdamore@opensolaris.org drv_usecwait(3); 4769860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), 0); 4779860Sgdamore@opensolaris.org drv_usecwait(8); 4789860Sgdamore@opensolaris.org 4799860Sgdamore@opensolaris.org secondary = dnet_read_srom(devinfo, deviceid, io_handle, 4809860Sgdamore@opensolaris.org io_reg, vendor_info, sizeof (vendor_info)); 4819860Sgdamore@opensolaris.org 4829860Sgdamore@opensolaris.org switch (secondary) { 4839860Sgdamore@opensolaris.org case -1: 4849860Sgdamore@opensolaris.org /* We can't access our SROM data! */ 4859860Sgdamore@opensolaris.org retval = DDI_PROBE_PARTIAL; 4869860Sgdamore@opensolaris.org break; 4879860Sgdamore@opensolaris.org case 0: 4889860Sgdamore@opensolaris.org retval = DDI_PROBE_SUCCESS; 4899860Sgdamore@opensolaris.org break; 4909860Sgdamore@opensolaris.org default: 4919860Sgdamore@opensolaris.org retval = DDI_PROBE_SUCCESS; 4929860Sgdamore@opensolaris.org } 4939860Sgdamore@opensolaris.org 4949860Sgdamore@opensolaris.org ddi_regs_map_free(&io_handle); 4959860Sgdamore@opensolaris.org return (retval); 4969860Sgdamore@opensolaris.org } 4979860Sgdamore@opensolaris.org #endif /* BUG_4010796 */ 4989860Sgdamore@opensolaris.org 4999860Sgdamore@opensolaris.org /* 5009860Sgdamore@opensolaris.org * attach(9E) -- Attach a device to the system 5019860Sgdamore@opensolaris.org * 5029860Sgdamore@opensolaris.org * Called once for each board successfully probed. 5039860Sgdamore@opensolaris.org */ 5049860Sgdamore@opensolaris.org static int 505*10340Sstallion@opensolaris.org dnet_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 5069860Sgdamore@opensolaris.org { 5079860Sgdamore@opensolaris.org uint16_t revid; 5089860Sgdamore@opensolaris.org struct dnetinstance *dnetp; /* Our private device info */ 509*10340Sstallion@opensolaris.org mac_register_t *macp; 5109860Sgdamore@opensolaris.org uchar_t vendor_info[SROM_SIZE]; 5119860Sgdamore@opensolaris.org uint32_t csr; 5129860Sgdamore@opensolaris.org uint16_t deviceid; 5139860Sgdamore@opensolaris.org ddi_acc_handle_t handle; 5149860Sgdamore@opensolaris.org int secondary; 5159860Sgdamore@opensolaris.org 5169860Sgdamore@opensolaris.org #define DNET_PCI_RNUMBER 1 5179860Sgdamore@opensolaris.org 5189860Sgdamore@opensolaris.org switch (cmd) { 5199860Sgdamore@opensolaris.org case DDI_ATTACH: 5209860Sgdamore@opensolaris.org break; 5219860Sgdamore@opensolaris.org 5229860Sgdamore@opensolaris.org case DDI_RESUME: 523*10340Sstallion@opensolaris.org /* Get the driver private (dnetinstance) structure */ 524*10340Sstallion@opensolaris.org dnetp = ddi_get_driver_private(devinfo); 5259860Sgdamore@opensolaris.org 5269860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 5279860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 528*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 529*10340Sstallion@opensolaris.org dnet_init_board(dnetp); 5309860Sgdamore@opensolaris.org dnetp->suspended = B_FALSE; 5319860Sgdamore@opensolaris.org 5329860Sgdamore@opensolaris.org if (dnetp->running) { 533*10340Sstallion@opensolaris.org dnetp->need_tx_update = B_FALSE; 5349860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 535*10340Sstallion@opensolaris.org (void) dnet_start(dnetp); 5369860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 537*10340Sstallion@opensolaris.org mac_tx_update(dnetp->mac_handle); 5389860Sgdamore@opensolaris.org } else { 5399860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 5409860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 5419860Sgdamore@opensolaris.org } 5429860Sgdamore@opensolaris.org return (DDI_SUCCESS); 5439860Sgdamore@opensolaris.org default: 5449860Sgdamore@opensolaris.org return (DDI_FAILURE); 5459860Sgdamore@opensolaris.org } 546*10340Sstallion@opensolaris.org 5479860Sgdamore@opensolaris.org if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 5489860Sgdamore@opensolaris.org return (DDI_FAILURE); 5499860Sgdamore@opensolaris.org 5509860Sgdamore@opensolaris.org deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 5519860Sgdamore@opensolaris.org switch (deviceid) { 5529860Sgdamore@opensolaris.org case DEVICE_ID_21040: 5539860Sgdamore@opensolaris.org case DEVICE_ID_21041: 5549860Sgdamore@opensolaris.org case DEVICE_ID_21140: 5559860Sgdamore@opensolaris.org case DEVICE_ID_21143: /* And 142 */ 5569860Sgdamore@opensolaris.org break; 5579860Sgdamore@opensolaris.org default: 5589860Sgdamore@opensolaris.org pci_config_teardown(&handle); 5599860Sgdamore@opensolaris.org return (DDI_FAILURE); 5609860Sgdamore@opensolaris.org } 5619860Sgdamore@opensolaris.org 5629860Sgdamore@opensolaris.org /* 5639860Sgdamore@opensolaris.org * Turn on Master Enable and IO Enable bits. 5649860Sgdamore@opensolaris.org */ 5659860Sgdamore@opensolaris.org csr = pci_config_get32(handle, PCI_CONF_COMM); 5669860Sgdamore@opensolaris.org pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO)); 5679860Sgdamore@opensolaris.org 5689860Sgdamore@opensolaris.org /* Make sure the device is not asleep */ 5699860Sgdamore@opensolaris.org csr = pci_config_get32(handle, PCI_DNET_CONF_CFDD); 5709860Sgdamore@opensolaris.org pci_config_put32(handle, PCI_DNET_CONF_CFDD, 5719860Sgdamore@opensolaris.org csr & ~(CFDD_SLEEP|CFDD_SNOOZE)); 5729860Sgdamore@opensolaris.org 5739860Sgdamore@opensolaris.org revid = pci_config_get8(handle, PCI_CONF_REVID); 5749860Sgdamore@opensolaris.org pci_config_teardown(&handle); 5759860Sgdamore@opensolaris.org 576*10340Sstallion@opensolaris.org dnetp = kmem_zalloc(sizeof (struct dnetinstance), KM_SLEEP); 577*10340Sstallion@opensolaris.org ddi_set_driver_private(devinfo, dnetp); 5789860Sgdamore@opensolaris.org 5799860Sgdamore@opensolaris.org /* Now map I/O register */ 5809860Sgdamore@opensolaris.org if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, &dnetp->io_reg, 5819860Sgdamore@opensolaris.org 0, 0, &accattr, &dnetp->io_handle) != DDI_SUCCESS) { 5829860Sgdamore@opensolaris.org kmem_free(dnetp, sizeof (struct dnetinstance)); 5839860Sgdamore@opensolaris.org return (DDI_FAILURE); 5849860Sgdamore@opensolaris.org } 5859860Sgdamore@opensolaris.org 5869860Sgdamore@opensolaris.org dnetp->devinfo = devinfo; 5879860Sgdamore@opensolaris.org dnetp->board_type = deviceid; 5889860Sgdamore@opensolaris.org 5899860Sgdamore@opensolaris.org /* 5909860Sgdamore@opensolaris.org * Get the iblock cookie with which to initialize the mutexes. 5919860Sgdamore@opensolaris.org */ 592*10340Sstallion@opensolaris.org if (ddi_get_iblock_cookie(devinfo, 0, &dnetp->icookie) 5939860Sgdamore@opensolaris.org != DDI_SUCCESS) 5949860Sgdamore@opensolaris.org goto fail; 5959860Sgdamore@opensolaris.org 5969860Sgdamore@opensolaris.org /* 5979860Sgdamore@opensolaris.org * Initialize mutex's for this device. 5989860Sgdamore@opensolaris.org * Do this before registering the interrupt handler to avoid 5999860Sgdamore@opensolaris.org * condition where interrupt handler can try using uninitialized 6009860Sgdamore@opensolaris.org * mutex. 6019860Sgdamore@opensolaris.org * Lock ordering rules: always lock intrlock first before 6029860Sgdamore@opensolaris.org * txlock if both are required. 6039860Sgdamore@opensolaris.org */ 604*10340Sstallion@opensolaris.org mutex_init(&dnetp->txlock, NULL, MUTEX_DRIVER, dnetp->icookie); 605*10340Sstallion@opensolaris.org mutex_init(&dnetp->intrlock, NULL, MUTEX_DRIVER, dnetp->icookie); 6069860Sgdamore@opensolaris.org 6079860Sgdamore@opensolaris.org /* 6089860Sgdamore@opensolaris.org * Get the BNC/TP indicator from the conf file for 21040 6099860Sgdamore@opensolaris.org */ 6109860Sgdamore@opensolaris.org dnetp->bnc_indicator = 6119860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 6129860Sgdamore@opensolaris.org "bncaui", -1); 6139860Sgdamore@opensolaris.org 6149860Sgdamore@opensolaris.org /* 6159860Sgdamore@opensolaris.org * For 21140 check the data rate set in the conf file. Default is 6169860Sgdamore@opensolaris.org * 100Mb/s. Disallow connections at settings that would conflict 6179860Sgdamore@opensolaris.org * with what's in the conf file 6189860Sgdamore@opensolaris.org */ 6199860Sgdamore@opensolaris.org dnetp->speed = 6209860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 6219860Sgdamore@opensolaris.org speed_propname, 0); 6229860Sgdamore@opensolaris.org dnetp->full_duplex = 6239860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 6249860Sgdamore@opensolaris.org duplex_propname, -1); 6259860Sgdamore@opensolaris.org 6269860Sgdamore@opensolaris.org if (dnetp->speed == 100) { 6279860Sgdamore@opensolaris.org dnetp->disallowed_media |= (1UL<<MEDIA_TP) | (1UL<<MEDIA_TP_FD); 6289860Sgdamore@opensolaris.org } else if (dnetp->speed == 10) { 6299860Sgdamore@opensolaris.org dnetp->disallowed_media |= 6309860Sgdamore@opensolaris.org (1UL<<MEDIA_SYM_SCR) | (1UL<<MEDIA_SYM_SCR_FD); 6319860Sgdamore@opensolaris.org } 6329860Sgdamore@opensolaris.org 6339860Sgdamore@opensolaris.org if (dnetp->full_duplex == 1) { 6349860Sgdamore@opensolaris.org dnetp->disallowed_media |= 6359860Sgdamore@opensolaris.org (1UL<<MEDIA_TP) | (1UL<<MEDIA_SYM_SCR); 6369860Sgdamore@opensolaris.org } else if (dnetp->full_duplex == 0) { 6379860Sgdamore@opensolaris.org dnetp->disallowed_media |= 6389860Sgdamore@opensolaris.org (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_SYM_SCR_FD); 6399860Sgdamore@opensolaris.org } 6409860Sgdamore@opensolaris.org 6419860Sgdamore@opensolaris.org if (dnetp->bnc_indicator == 0) /* Disable BNC and AUI media */ 6429860Sgdamore@opensolaris.org dnetp->disallowed_media |= (1UL<<MEDIA_BNC) | (1UL<<MEDIA_AUI); 6439860Sgdamore@opensolaris.org else if (dnetp->bnc_indicator == 1) /* Force BNC only */ 6449860Sgdamore@opensolaris.org dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_BNC); 6459860Sgdamore@opensolaris.org else if (dnetp->bnc_indicator == 2) /* Force AUI only */ 6469860Sgdamore@opensolaris.org dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_AUI); 6479860Sgdamore@opensolaris.org 648*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 6499860Sgdamore@opensolaris.org 6509860Sgdamore@opensolaris.org secondary = dnet_read_srom(devinfo, dnetp->board_type, dnetp->io_handle, 6519860Sgdamore@opensolaris.org dnetp->io_reg, vendor_info, sizeof (vendor_info)); 6529860Sgdamore@opensolaris.org 6539860Sgdamore@opensolaris.org if (secondary == -1) /* ASSERT (vendor_info not big enough) */ 6549860Sgdamore@opensolaris.org goto fail1; 6559860Sgdamore@opensolaris.org 6569860Sgdamore@opensolaris.org dnet_parse_srom(dnetp, &dnetp->sr, vendor_info); 6579860Sgdamore@opensolaris.org 6589860Sgdamore@opensolaris.org if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 6599860Sgdamore@opensolaris.org printsrom_propname, 0)) 6609860Sgdamore@opensolaris.org dnet_print_srom(&dnetp->sr); 6619860Sgdamore@opensolaris.org 6629860Sgdamore@opensolaris.org dnetp->sr.netaddr[ETHERADDRL-1] += secondary; /* unique ether addr */ 6639860Sgdamore@opensolaris.org 6649860Sgdamore@opensolaris.org BCOPY((caddr_t)dnetp->sr.netaddr, 6659860Sgdamore@opensolaris.org (caddr_t)dnetp->vendor_addr, ETHERADDRL); 6669860Sgdamore@opensolaris.org 6679860Sgdamore@opensolaris.org BCOPY((caddr_t)dnetp->sr.netaddr, 6689860Sgdamore@opensolaris.org (caddr_t)dnetp->curr_macaddr, ETHERADDRL); 6699860Sgdamore@opensolaris.org 6709860Sgdamore@opensolaris.org /* 6719860Sgdamore@opensolaris.org * determine whether to implement workaround from DEC 6729860Sgdamore@opensolaris.org * for DMA overrun errata. 6739860Sgdamore@opensolaris.org */ 6749860Sgdamore@opensolaris.org dnetp->overrun_workaround = 6759860Sgdamore@opensolaris.org ((dnetp->board_type == DEVICE_ID_21140 && revid >= 0x20) || 6769860Sgdamore@opensolaris.org (dnetp->board_type == DEVICE_ID_21143 && revid <= 0x30)) ? 1 : 0; 6779860Sgdamore@opensolaris.org 6789860Sgdamore@opensolaris.org dnetp->overrun_workaround = 6799860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 6809860Sgdamore@opensolaris.org ofloprob_propname, dnetp->overrun_workaround); 6819860Sgdamore@opensolaris.org 6829860Sgdamore@opensolaris.org /* 6839860Sgdamore@opensolaris.org * Add the interrupt handler if dnet_hack_interrupts() returns 0. 6849860Sgdamore@opensolaris.org * Otherwise dnet_hack_interrupts() itself adds the handler. 6859860Sgdamore@opensolaris.org */ 686*10340Sstallion@opensolaris.org if (!dnet_hack_interrupts(dnetp, secondary)) { 6879860Sgdamore@opensolaris.org (void) ddi_add_intr(devinfo, 0, NULL, 688*10340Sstallion@opensolaris.org NULL, dnet_intr, (caddr_t)dnetp); 6899860Sgdamore@opensolaris.org } 6909860Sgdamore@opensolaris.org 6919860Sgdamore@opensolaris.org dnetp->max_tx_desc = max_tx_desc; 6929860Sgdamore@opensolaris.org dnetp->max_rx_desc = max_rx_desc_21040; 6939860Sgdamore@opensolaris.org if (dnetp->board_type != DEVICE_ID_21040 && 6949860Sgdamore@opensolaris.org dnetp->board_type != DEVICE_ID_21041 && 6959860Sgdamore@opensolaris.org dnetp->speed != 10) 6969860Sgdamore@opensolaris.org dnetp->max_rx_desc = max_rx_desc_21140; 6979860Sgdamore@opensolaris.org 6989860Sgdamore@opensolaris.org /* Allocate the TX and RX descriptors/buffers. */ 699*10340Sstallion@opensolaris.org if (dnet_alloc_bufs(dnetp) == FAILURE) { 7009860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Not enough DMA memory for buffers."); 7019860Sgdamore@opensolaris.org goto fail2; 7029860Sgdamore@opensolaris.org } 7039860Sgdamore@opensolaris.org 7049860Sgdamore@opensolaris.org /* 705*10340Sstallion@opensolaris.org * Register ourselves with the GLDv3 interface 7069860Sgdamore@opensolaris.org */ 707*10340Sstallion@opensolaris.org if ((macp = mac_alloc(MAC_VERSION)) == NULL) 708*10340Sstallion@opensolaris.org goto fail2; 709*10340Sstallion@opensolaris.org 710*10340Sstallion@opensolaris.org macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 711*10340Sstallion@opensolaris.org macp->m_driver = dnetp; 712*10340Sstallion@opensolaris.org macp->m_dip = devinfo; 713*10340Sstallion@opensolaris.org macp->m_src_addr = dnetp->curr_macaddr; 714*10340Sstallion@opensolaris.org macp->m_callbacks = &dnet_m_callbacks; 715*10340Sstallion@opensolaris.org macp->m_min_sdu = 0; 716*10340Sstallion@opensolaris.org macp->m_max_sdu = ETHERMTU; 717*10340Sstallion@opensolaris.org macp->m_margin = VLAN_TAGSZ; 718*10340Sstallion@opensolaris.org 719*10340Sstallion@opensolaris.org if (mac_register(macp, &dnetp->mac_handle) == 0) { 720*10340Sstallion@opensolaris.org mac_free(macp); 721*10340Sstallion@opensolaris.org 7229860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 723*10340Sstallion@opensolaris.org 7249860Sgdamore@opensolaris.org dnetp->phyaddr = -1; 7259860Sgdamore@opensolaris.org if (dnetp->board_type == DEVICE_ID_21140 || 7269860Sgdamore@opensolaris.org dnetp->board_type == DEVICE_ID_21143) 727*10340Sstallion@opensolaris.org do_phy(dnetp); /* Initialize the PHY, if any */ 728*10340Sstallion@opensolaris.org find_active_media(dnetp); 7299860Sgdamore@opensolaris.org 7309860Sgdamore@opensolaris.org /* if the chosen media is non-MII, stop the port monitor */ 7319860Sgdamore@opensolaris.org if (dnetp->selected_media_block->media_code != MEDIA_MII && 7329860Sgdamore@opensolaris.org dnetp->mii != NULL) { 7339860Sgdamore@opensolaris.org mii_destroy(dnetp->mii); 7349860Sgdamore@opensolaris.org dnetp->mii = NULL; 7359860Sgdamore@opensolaris.org dnetp->phyaddr = -1; 7369860Sgdamore@opensolaris.org } 7379860Sgdamore@opensolaris.org 7389860Sgdamore@opensolaris.org #ifdef DNETDEBUG 7399860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 7409860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "dnet: link configured : %s", 7419860Sgdamore@opensolaris.org media_str[dnetp->selected_media_block->media_code]); 7429860Sgdamore@opensolaris.org #endif 7439860Sgdamore@opensolaris.org bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE); 744*10340Sstallion@opensolaris.org 745*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 746*10340Sstallion@opensolaris.org dnet_init_board(dnetp); 747*10340Sstallion@opensolaris.org 7489860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 749*10340Sstallion@opensolaris.org 750*10340Sstallion@opensolaris.org (void) dnet_m_unicst(dnetp, dnetp->curr_macaddr); 751*10340Sstallion@opensolaris.org (void) dnet_m_multicst(dnetp, B_TRUE, dnet_broadcastaddr); 752*10340Sstallion@opensolaris.org 7539860Sgdamore@opensolaris.org return (DDI_SUCCESS); 7549860Sgdamore@opensolaris.org } 755*10340Sstallion@opensolaris.org 756*10340Sstallion@opensolaris.org mac_free(macp); 7579860Sgdamore@opensolaris.org fail2: 7589860Sgdamore@opensolaris.org /* XXX function return value ignored */ 7599860Sgdamore@opensolaris.org /* 7609860Sgdamore@opensolaris.org * dnet_detach_hacked_interrupt() will remove 7619860Sgdamore@opensolaris.org * interrupt for the non-hacked case also. 7629860Sgdamore@opensolaris.org */ 7639860Sgdamore@opensolaris.org (void) dnet_detach_hacked_interrupt(devinfo); 764*10340Sstallion@opensolaris.org dnet_free_bufs(dnetp); 7659860Sgdamore@opensolaris.org fail1: 7669860Sgdamore@opensolaris.org mutex_destroy(&dnetp->txlock); 7679860Sgdamore@opensolaris.org mutex_destroy(&dnetp->intrlock); 7689860Sgdamore@opensolaris.org fail: 7699860Sgdamore@opensolaris.org ddi_regs_map_free(&dnetp->io_handle); 7709860Sgdamore@opensolaris.org kmem_free(dnetp, sizeof (struct dnetinstance)); 7719860Sgdamore@opensolaris.org return (DDI_FAILURE); 7729860Sgdamore@opensolaris.org } 7739860Sgdamore@opensolaris.org 7749860Sgdamore@opensolaris.org /* 7759860Sgdamore@opensolaris.org * detach(9E) -- Detach a device from the system 7769860Sgdamore@opensolaris.org */ 7779860Sgdamore@opensolaris.org static int 778*10340Sstallion@opensolaris.org dnet_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 7799860Sgdamore@opensolaris.org { 7809860Sgdamore@opensolaris.org int32_t rc; 7819860Sgdamore@opensolaris.org struct dnetinstance *dnetp; /* Our private device info */ 7829860Sgdamore@opensolaris.org int32_t proplen; 7839860Sgdamore@opensolaris.org 784*10340Sstallion@opensolaris.org /* Get the driver private (dnetinstance) structure */ 785*10340Sstallion@opensolaris.org dnetp = ddi_get_driver_private(devinfo); 7869860Sgdamore@opensolaris.org 7879860Sgdamore@opensolaris.org switch (cmd) { 7889860Sgdamore@opensolaris.org case DDI_DETACH: 7899860Sgdamore@opensolaris.org break; 7909860Sgdamore@opensolaris.org 7919860Sgdamore@opensolaris.org case DDI_SUSPEND: 7929860Sgdamore@opensolaris.org /* 7939860Sgdamore@opensolaris.org * NB: dnetp->suspended can only be modified (marked true) 7949860Sgdamore@opensolaris.org * if both intrlock and txlock are held. This keeps both 7959860Sgdamore@opensolaris.org * tx and rx code paths excluded. 7969860Sgdamore@opensolaris.org */ 7979860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 7989860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 7999860Sgdamore@opensolaris.org dnetp->suspended = B_TRUE; 800*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 8019860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 8029860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 8039860Sgdamore@opensolaris.org return (DDI_SUCCESS); 8049860Sgdamore@opensolaris.org 8059860Sgdamore@opensolaris.org default: 8069860Sgdamore@opensolaris.org return (DDI_FAILURE); 8079860Sgdamore@opensolaris.org } 8089860Sgdamore@opensolaris.org 8099860Sgdamore@opensolaris.org /* 810*10340Sstallion@opensolaris.org * Unregister ourselves from the GLDv3 interface 8119860Sgdamore@opensolaris.org */ 812*10340Sstallion@opensolaris.org if (mac_unregister(dnetp->mac_handle) != 0) 8139860Sgdamore@opensolaris.org return (DDI_FAILURE); 8149860Sgdamore@opensolaris.org 8159860Sgdamore@opensolaris.org /* stop the board if it is running */ 816*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 8179860Sgdamore@opensolaris.org 8189860Sgdamore@opensolaris.org if ((rc = dnet_detach_hacked_interrupt(devinfo)) != DDI_SUCCESS) 8199860Sgdamore@opensolaris.org return (rc); 8209860Sgdamore@opensolaris.org 8219860Sgdamore@opensolaris.org if (dnetp->mii != NULL) 8229860Sgdamore@opensolaris.org mii_destroy(dnetp->mii); 8239860Sgdamore@opensolaris.org 8249860Sgdamore@opensolaris.org /* Free leaf information */ 8259860Sgdamore@opensolaris.org set_leaf(&dnetp->sr, NULL); 8269860Sgdamore@opensolaris.org 8279860Sgdamore@opensolaris.org ddi_regs_map_free(&dnetp->io_handle); 828*10340Sstallion@opensolaris.org dnet_free_bufs(dnetp); 8299860Sgdamore@opensolaris.org mutex_destroy(&dnetp->txlock); 8309860Sgdamore@opensolaris.org mutex_destroy(&dnetp->intrlock); 8319860Sgdamore@opensolaris.org kmem_free(dnetp, sizeof (struct dnetinstance)); 8329860Sgdamore@opensolaris.org 8339860Sgdamore@opensolaris.org #ifdef BUG_4010796 8349860Sgdamore@opensolaris.org if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, 0, 8359860Sgdamore@opensolaris.org "DNET_HACK", &proplen) != DDI_PROP_SUCCESS) 8369860Sgdamore@opensolaris.org return (DDI_SUCCESS); 8379860Sgdamore@opensolaris.org 8389860Sgdamore@opensolaris.org /* 8399860Sgdamore@opensolaris.org * We must remove the properties we added, because if we leave 8409860Sgdamore@opensolaris.org * them in the devinfo nodes and the driver is unloaded, when 8419860Sgdamore@opensolaris.org * the driver is reloaded the info will still be there, causing 8429860Sgdamore@opensolaris.org * nodes which had returned PROBE_PARTIAL the first time to 8439860Sgdamore@opensolaris.org * instead return PROBE_SUCCESS, in turn causing the nodes to be 8449860Sgdamore@opensolaris.org * attached in a different order, causing their PPA numbers to 8459860Sgdamore@opensolaris.org * be different the second time around, which is undesirable. 8469860Sgdamore@opensolaris.org */ 8479860Sgdamore@opensolaris.org (void) ddi_prop_remove(DDI_DEV_T_NONE, devinfo, "DNET_HACK"); 8489860Sgdamore@opensolaris.org (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 8499860Sgdamore@opensolaris.org "DNET_SROM"); 8509860Sgdamore@opensolaris.org (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 8519860Sgdamore@opensolaris.org "DNET_DEVNUM"); 8529860Sgdamore@opensolaris.org #endif 8539860Sgdamore@opensolaris.org 8549860Sgdamore@opensolaris.org return (DDI_SUCCESS); 8559860Sgdamore@opensolaris.org } 8569860Sgdamore@opensolaris.org 857*10340Sstallion@opensolaris.org int 858*10340Sstallion@opensolaris.org dnet_quiesce(dev_info_t *dip) 8599860Sgdamore@opensolaris.org { 860*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = ddi_get_driver_private(dip); 861*10340Sstallion@opensolaris.org 8629860Sgdamore@opensolaris.org /* 863*10340Sstallion@opensolaris.org * Reset chip (disables interrupts). 8649860Sgdamore@opensolaris.org */ 865*10340Sstallion@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0); 866*10340Sstallion@opensolaris.org ddi_put32(dnetp->io_handle, 867*10340Sstallion@opensolaris.org REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET); 868*10340Sstallion@opensolaris.org 869*10340Sstallion@opensolaris.org return (DDI_SUCCESS); 8709860Sgdamore@opensolaris.org } 8719860Sgdamore@opensolaris.org 8729860Sgdamore@opensolaris.org static void 873*10340Sstallion@opensolaris.org dnet_reset_board(struct dnetinstance *dnetp) 8749860Sgdamore@opensolaris.org { 8759860Sgdamore@opensolaris.org uint32_t val; 8769860Sgdamore@opensolaris.org 8779860Sgdamore@opensolaris.org /* 8789860Sgdamore@opensolaris.org * before initializing the dnet should be in STOP state 8799860Sgdamore@opensolaris.org */ 8809860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 8819860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 8829860Sgdamore@opensolaris.org val & ~(START_TRANSMIT | START_RECEIVE)); 8839860Sgdamore@opensolaris.org 8849860Sgdamore@opensolaris.org /* 8859860Sgdamore@opensolaris.org * Reset the chip 8869860Sgdamore@opensolaris.org */ 8879860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0); 8889860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 8899860Sgdamore@opensolaris.org REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET); 8909860Sgdamore@opensolaris.org drv_usecwait(5); 8919860Sgdamore@opensolaris.org } 8929860Sgdamore@opensolaris.org 8939860Sgdamore@opensolaris.org /* 8949860Sgdamore@opensolaris.org * dnet_init_board() -- initialize the specified network board short of 8959860Sgdamore@opensolaris.org * actually starting the board. Call after dnet_reset_board(). 8969860Sgdamore@opensolaris.org * called with intrlock held. 8979860Sgdamore@opensolaris.org */ 8989860Sgdamore@opensolaris.org static void 899*10340Sstallion@opensolaris.org dnet_init_board(struct dnetinstance *dnetp) 9009860Sgdamore@opensolaris.org { 901*10340Sstallion@opensolaris.org set_opr(dnetp); 902*10340Sstallion@opensolaris.org set_gpr(dnetp); 903*10340Sstallion@opensolaris.org set_sia(dnetp); 904*10340Sstallion@opensolaris.org dnet_chip_init(dnetp); 9059860Sgdamore@opensolaris.org } 9069860Sgdamore@opensolaris.org 9079860Sgdamore@opensolaris.org /* dnet_chip_init() - called with intrlock held */ 9089860Sgdamore@opensolaris.org static void 909*10340Sstallion@opensolaris.org dnet_chip_init(struct dnetinstance *dnetp) 9109860Sgdamore@opensolaris.org { 9119860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, BUS_MODE_REG), 9129860Sgdamore@opensolaris.org CACHE_ALIGN | BURST_SIZE); /* CSR0 */ 9139860Sgdamore@opensolaris.org 9149860Sgdamore@opensolaris.org /* 9159860Sgdamore@opensolaris.org * Initialize the TX and RX descriptors/buffers 9169860Sgdamore@opensolaris.org */ 917*10340Sstallion@opensolaris.org dnet_init_txrx_bufs(dnetp); 9189860Sgdamore@opensolaris.org 9199860Sgdamore@opensolaris.org /* 9209860Sgdamore@opensolaris.org * Set the base address of the Rx descriptor list in CSR3 9219860Sgdamore@opensolaris.org */ 9229860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, RX_BASE_ADDR_REG), 9239860Sgdamore@opensolaris.org dnetp->rx_desc_paddr); 9249860Sgdamore@opensolaris.org 9259860Sgdamore@opensolaris.org /* 9269860Sgdamore@opensolaris.org * Set the base address of the Tx descrptor list in CSR4 9279860Sgdamore@opensolaris.org */ 9289860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_BASE_ADDR_REG), 9299860Sgdamore@opensolaris.org dnetp->tx_desc_paddr); 9309860Sgdamore@opensolaris.org 9319860Sgdamore@opensolaris.org dnetp->tx_current_desc = dnetp->rx_current_desc = 0; 9329860Sgdamore@opensolaris.org dnetp->transmitted_desc = 0; 9339860Sgdamore@opensolaris.org dnetp->free_desc = dnetp->max_tx_desc; 934*10340Sstallion@opensolaris.org enable_interrupts(dnetp); 9359860Sgdamore@opensolaris.org } 9369860Sgdamore@opensolaris.org 9379860Sgdamore@opensolaris.org /* 9389860Sgdamore@opensolaris.org * dnet_start() -- start the board receiving and allow transmits. 9399860Sgdamore@opensolaris.org * Called with intrlock held. 9409860Sgdamore@opensolaris.org */ 9419860Sgdamore@opensolaris.org static int 942*10340Sstallion@opensolaris.org dnet_start(struct dnetinstance *dnetp) 9439860Sgdamore@opensolaris.org { 944*10340Sstallion@opensolaris.org uint32_t val; 9459860Sgdamore@opensolaris.org 9469860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 9479860Sgdamore@opensolaris.org /* 9489860Sgdamore@opensolaris.org * start the board and enable receiving 9499860Sgdamore@opensolaris.org */ 9509860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 9519860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 9529860Sgdamore@opensolaris.org val | START_TRANSMIT); 953*10340Sstallion@opensolaris.org (void) dnet_set_addr(dnetp); 9549860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 9559860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 9569860Sgdamore@opensolaris.org val | START_RECEIVE); 957*10340Sstallion@opensolaris.org enable_interrupts(dnetp); 9589860Sgdamore@opensolaris.org return (0); 9599860Sgdamore@opensolaris.org } 9609860Sgdamore@opensolaris.org 9619860Sgdamore@opensolaris.org static int 962*10340Sstallion@opensolaris.org dnet_m_start(void *arg) 9639860Sgdamore@opensolaris.org { 964*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 9659860Sgdamore@opensolaris.org 9669860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 9679860Sgdamore@opensolaris.org dnetp->running = B_TRUE; 9689860Sgdamore@opensolaris.org /* 9699860Sgdamore@opensolaris.org * start the board and enable receiving 9709860Sgdamore@opensolaris.org */ 9719860Sgdamore@opensolaris.org if (!dnetp->suspended) 972*10340Sstallion@opensolaris.org (void) dnet_start(dnetp); 973*10340Sstallion@opensolaris.org dnet_mii_link_up(dnetp); 9749860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 9759860Sgdamore@opensolaris.org return (0); 9769860Sgdamore@opensolaris.org } 9779860Sgdamore@opensolaris.org 978*10340Sstallion@opensolaris.org static void 979*10340Sstallion@opensolaris.org dnet_m_stop(void *arg) 9809860Sgdamore@opensolaris.org { 981*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 982*10340Sstallion@opensolaris.org uint32_t val; 983*10340Sstallion@opensolaris.org 9849860Sgdamore@opensolaris.org /* 9859860Sgdamore@opensolaris.org * stop the board and disable transmit/receive 9869860Sgdamore@opensolaris.org */ 9879860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 9889860Sgdamore@opensolaris.org if (!dnetp->suspended) { 989*10340Sstallion@opensolaris.org if (dnetp->mii_up) { 990*10340Sstallion@opensolaris.org dnetp->mii_up = 0; 991*10340Sstallion@opensolaris.org dnetp->mii_speed = 0; 992*10340Sstallion@opensolaris.org dnetp->mii_duplex = 0; 993*10340Sstallion@opensolaris.org } 994*10340Sstallion@opensolaris.org mac_link_update(dnetp->mac_handle, LINK_STATE_UNKNOWN); 9959860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, 9969860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG)); 9979860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 9989860Sgdamore@opensolaris.org val & ~(START_TRANSMIT | START_RECEIVE)); 9999860Sgdamore@opensolaris.org } 10009860Sgdamore@opensolaris.org dnetp->running = B_FALSE; 10019860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 10029860Sgdamore@opensolaris.org } 10039860Sgdamore@opensolaris.org 10049860Sgdamore@opensolaris.org /* 10059860Sgdamore@opensolaris.org * dnet_set_addr() -- set the physical network address on the board 10069860Sgdamore@opensolaris.org * Called with intrlock held. 10079860Sgdamore@opensolaris.org */ 10089860Sgdamore@opensolaris.org static int 1009*10340Sstallion@opensolaris.org dnet_set_addr(struct dnetinstance *dnetp) 10109860Sgdamore@opensolaris.org { 10119860Sgdamore@opensolaris.org struct tx_desc_type *desc; 10129860Sgdamore@opensolaris.org int current_desc; 10139860Sgdamore@opensolaris.org uint32_t val; 10149860Sgdamore@opensolaris.org 10159860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 10169860Sgdamore@opensolaris.org 10179860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 10189860Sgdamore@opensolaris.org if (!(val & START_TRANSMIT)) 10199860Sgdamore@opensolaris.org return (0); 10209860Sgdamore@opensolaris.org 10219860Sgdamore@opensolaris.org current_desc = dnetp->tx_current_desc; 10229860Sgdamore@opensolaris.org desc = &dnetp->tx_desc[current_desc]; 10239860Sgdamore@opensolaris.org 10249860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 10259860Sgdamore@opensolaris.org dnetp->need_saddr = 0; 10269860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 10279860Sgdamore@opensolaris.org 1028*10340Sstallion@opensolaris.org if ((alloc_descriptor(dnetp)) == FAILURE) { 10299860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 10309860Sgdamore@opensolaris.org dnetp->need_saddr = 1; 10319860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 10329860Sgdamore@opensolaris.org #ifdef DNETDEBUG 10339860Sgdamore@opensolaris.org if (dnetdebug & DNETTRACE) 10349860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET saddr:alloc descriptor failure"); 10359860Sgdamore@opensolaris.org #endif 10369860Sgdamore@opensolaris.org return (0); 10379860Sgdamore@opensolaris.org } 10389860Sgdamore@opensolaris.org 10399860Sgdamore@opensolaris.org desc->buffer1 = dnetp->setup_buf_paddr; 10409860Sgdamore@opensolaris.org desc->buffer2 = 0; 10419860Sgdamore@opensolaris.org desc->desc1.buffer_size1 = SETUPBUF_SIZE; 10429860Sgdamore@opensolaris.org desc->desc1.buffer_size2 = 0; 10439860Sgdamore@opensolaris.org desc->desc1.setup_packet = 1; 10449860Sgdamore@opensolaris.org desc->desc1.first_desc = 0; 10459860Sgdamore@opensolaris.org desc->desc1.last_desc = 0; 10469860Sgdamore@opensolaris.org desc->desc1.filter_type0 = 1; 10479860Sgdamore@opensolaris.org desc->desc1.filter_type1 = 1; 10489860Sgdamore@opensolaris.org desc->desc1.int_on_comp = 1; 10499860Sgdamore@opensolaris.org 10509860Sgdamore@opensolaris.org desc->desc0.own = 1; 10519860Sgdamore@opensolaris.org ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG), 10529860Sgdamore@opensolaris.org TX_POLL_DEMAND); 10539860Sgdamore@opensolaris.org return (0); 10549860Sgdamore@opensolaris.org } 10559860Sgdamore@opensolaris.org 10569860Sgdamore@opensolaris.org static int 1057*10340Sstallion@opensolaris.org dnet_m_unicst(void *arg, const uint8_t *macaddr) 10589860Sgdamore@opensolaris.org { 1059*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 10609860Sgdamore@opensolaris.org uint32_t index; 10619860Sgdamore@opensolaris.org uint32_t *hashp; 10629860Sgdamore@opensolaris.org 10639860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 10649860Sgdamore@opensolaris.org 10659860Sgdamore@opensolaris.org bcopy(macaddr, dnetp->curr_macaddr, ETHERADDRL); 10669860Sgdamore@opensolaris.org 10679860Sgdamore@opensolaris.org /* 10689860Sgdamore@opensolaris.org * As we are using Imperfect filtering, the broadcast address has to 10699860Sgdamore@opensolaris.org * be set explicitly in the 512 bit hash table. Hence the index into 10709860Sgdamore@opensolaris.org * the hash table is calculated and the bit set to enable reception 10719860Sgdamore@opensolaris.org * of broadcast packets. 10729860Sgdamore@opensolaris.org * 10739860Sgdamore@opensolaris.org * We also use HASH_ONLY mode, without using the perfect filter for 10749860Sgdamore@opensolaris.org * our station address, because there appears to be a bug in the 10759860Sgdamore@opensolaris.org * 21140 where it fails to receive the specified perfect filter 10769860Sgdamore@opensolaris.org * address. 10779860Sgdamore@opensolaris.org * 10789860Sgdamore@opensolaris.org * Since dlsdmult comes through here, it doesn't matter that the count 10799860Sgdamore@opensolaris.org * is wrong for the two bits that correspond to the cases below. The 10809860Sgdamore@opensolaris.org * worst that could happen is that we'd leave on a bit for an old 10819860Sgdamore@opensolaris.org * macaddr, in the case where the macaddr gets changed, which is rare. 10829860Sgdamore@opensolaris.org * Since filtering is imperfect, it is OK if that happens. 10839860Sgdamore@opensolaris.org */ 10849860Sgdamore@opensolaris.org hashp = (uint32_t *)dnetp->setup_buf_vaddr; 1085*10340Sstallion@opensolaris.org index = hashindex((uint8_t *)dnet_broadcastaddr); 10869860Sgdamore@opensolaris.org hashp[ index / 16 ] |= 1 << (index % 16); 10879860Sgdamore@opensolaris.org 1088*10340Sstallion@opensolaris.org index = hashindex((uint8_t *)dnetp->curr_macaddr); 10899860Sgdamore@opensolaris.org hashp[ index / 16 ] |= 1 << (index % 16); 10909860Sgdamore@opensolaris.org 10919860Sgdamore@opensolaris.org if (!dnetp->suspended) 1092*10340Sstallion@opensolaris.org (void) dnet_set_addr(dnetp); 10939860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 10949860Sgdamore@opensolaris.org return (0); 10959860Sgdamore@opensolaris.org } 10969860Sgdamore@opensolaris.org 10979860Sgdamore@opensolaris.org static int 1098*10340Sstallion@opensolaris.org dnet_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 10999860Sgdamore@opensolaris.org { 1100*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 11019860Sgdamore@opensolaris.org uint32_t index; 11029860Sgdamore@opensolaris.org uint32_t *hashp; 11039860Sgdamore@opensolaris.org uint32_t retval; 11049860Sgdamore@opensolaris.org 11059860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 1106*10340Sstallion@opensolaris.org index = hashindex(macaddr); 11079860Sgdamore@opensolaris.org hashp = (uint32_t *)dnetp->setup_buf_vaddr; 1108*10340Sstallion@opensolaris.org if (add) { 11099860Sgdamore@opensolaris.org if (dnetp->multicast_cnt[index]++) { 11109860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 11119860Sgdamore@opensolaris.org return (0); 11129860Sgdamore@opensolaris.org } 11139860Sgdamore@opensolaris.org hashp[ index / 16 ] |= 1 << (index % 16); 11149860Sgdamore@opensolaris.org } else { 11159860Sgdamore@opensolaris.org if (--dnetp->multicast_cnt[index]) { 11169860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 11179860Sgdamore@opensolaris.org return (0); 11189860Sgdamore@opensolaris.org } 11199860Sgdamore@opensolaris.org hashp[ index / 16 ] &= ~ (1 << (index % 16)); 11209860Sgdamore@opensolaris.org } 11219860Sgdamore@opensolaris.org if (!dnetp->suspended) 1122*10340Sstallion@opensolaris.org retval = dnet_set_addr(dnetp); 11239860Sgdamore@opensolaris.org else 11249860Sgdamore@opensolaris.org retval = 0; 11259860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 11269860Sgdamore@opensolaris.org return (retval); 11279860Sgdamore@opensolaris.org } 11289860Sgdamore@opensolaris.org 11299860Sgdamore@opensolaris.org /* 11309860Sgdamore@opensolaris.org * A hashing function used for setting the 11319860Sgdamore@opensolaris.org * node address or a multicast address 11329860Sgdamore@opensolaris.org */ 11339860Sgdamore@opensolaris.org static uint32_t 1134*10340Sstallion@opensolaris.org hashindex(const uint8_t *address) 11359860Sgdamore@opensolaris.org { 11369860Sgdamore@opensolaris.org uint32_t crc = (uint32_t)HASH_CRC; 11379860Sgdamore@opensolaris.org uint32_t const POLY = HASH_POLY; 11389860Sgdamore@opensolaris.org uint32_t msb; 11399860Sgdamore@opensolaris.org int32_t byteslength; 11409860Sgdamore@opensolaris.org uint8_t currentbyte; 11419860Sgdamore@opensolaris.org uint32_t index; 11429860Sgdamore@opensolaris.org int32_t bit; 11439860Sgdamore@opensolaris.org int32_t shift; 11449860Sgdamore@opensolaris.org 11459860Sgdamore@opensolaris.org for (byteslength = 0; byteslength < ETHERADDRL; byteslength++) { 11469860Sgdamore@opensolaris.org currentbyte = address[byteslength]; 11479860Sgdamore@opensolaris.org for (bit = 0; bit < 8; bit++) { 11489860Sgdamore@opensolaris.org msb = crc >> 31; 11499860Sgdamore@opensolaris.org crc <<= 1; 11509860Sgdamore@opensolaris.org if (msb ^ (currentbyte & 1)) { 11519860Sgdamore@opensolaris.org crc ^= POLY; 11529860Sgdamore@opensolaris.org crc |= 0x00000001; 11539860Sgdamore@opensolaris.org } 11549860Sgdamore@opensolaris.org currentbyte >>= 1; 11559860Sgdamore@opensolaris.org } 11569860Sgdamore@opensolaris.org } 11579860Sgdamore@opensolaris.org 11589860Sgdamore@opensolaris.org for (index = 0, bit = 23, shift = 8; shift >= 0; bit++, shift--) { 11599860Sgdamore@opensolaris.org index |= (((crc >> bit) & 1) << shift); 11609860Sgdamore@opensolaris.org } 11619860Sgdamore@opensolaris.org return (index); 11629860Sgdamore@opensolaris.org } 11639860Sgdamore@opensolaris.org 11649860Sgdamore@opensolaris.org static int 1165*10340Sstallion@opensolaris.org dnet_m_setpromisc(void *arg, boolean_t on) 11669860Sgdamore@opensolaris.org { 1167*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 11689860Sgdamore@opensolaris.org uint32_t val; 11699860Sgdamore@opensolaris.org 11709860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 11719860Sgdamore@opensolaris.org if (dnetp->promisc == on) { 11729860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 1173*10340Sstallion@opensolaris.org return (0); 11749860Sgdamore@opensolaris.org } 11759860Sgdamore@opensolaris.org dnetp->promisc = on; 11769860Sgdamore@opensolaris.org 11779860Sgdamore@opensolaris.org if (!dnetp->suspended) { 11789860Sgdamore@opensolaris.org val = ddi_get32(dnetp->io_handle, 11799860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG)); 1180*10340Sstallion@opensolaris.org if (on) 11819860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 11829860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), 11839860Sgdamore@opensolaris.org val | PROM_MODE); 11849860Sgdamore@opensolaris.org else 11859860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 11869860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), 11879860Sgdamore@opensolaris.org val & (~PROM_MODE)); 11889860Sgdamore@opensolaris.org } 11899860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 1190*10340Sstallion@opensolaris.org return (0); 11919860Sgdamore@opensolaris.org } 11929860Sgdamore@opensolaris.org 11939860Sgdamore@opensolaris.org static int 1194*10340Sstallion@opensolaris.org dnet_m_getstat(void *arg, uint_t stat, uint64_t *val) 11959860Sgdamore@opensolaris.org { 1196*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 1197*10340Sstallion@opensolaris.org 1198*10340Sstallion@opensolaris.org switch (stat) { 1199*10340Sstallion@opensolaris.org case MAC_STAT_IFSPEED: 1200*10340Sstallion@opensolaris.org *val = (dnetp->mii_up ? 1201*10340Sstallion@opensolaris.org dnetp->mii_speed : dnetp->speed) * 1000000; 1202*10340Sstallion@opensolaris.org break; 1203*10340Sstallion@opensolaris.org 1204*10340Sstallion@opensolaris.org case MAC_STAT_NORCVBUF: 1205*10340Sstallion@opensolaris.org *val = dnetp->stat_norcvbuf; 1206*10340Sstallion@opensolaris.org break; 1207*10340Sstallion@opensolaris.org 1208*10340Sstallion@opensolaris.org case MAC_STAT_IERRORS: 1209*10340Sstallion@opensolaris.org *val = dnetp->stat_errrcv; 1210*10340Sstallion@opensolaris.org break; 1211*10340Sstallion@opensolaris.org 1212*10340Sstallion@opensolaris.org case MAC_STAT_OERRORS: 1213*10340Sstallion@opensolaris.org *val = dnetp->stat_errxmt; 1214*10340Sstallion@opensolaris.org break; 1215*10340Sstallion@opensolaris.org 1216*10340Sstallion@opensolaris.org case MAC_STAT_COLLISIONS: 1217*10340Sstallion@opensolaris.org *val = dnetp->stat_collisions; 1218*10340Sstallion@opensolaris.org break; 1219*10340Sstallion@opensolaris.org 1220*10340Sstallion@opensolaris.org case ETHER_STAT_DEFER_XMTS: 1221*10340Sstallion@opensolaris.org *val = dnetp->stat_defer; 1222*10340Sstallion@opensolaris.org break; 1223*10340Sstallion@opensolaris.org 1224*10340Sstallion@opensolaris.org case ETHER_STAT_CARRIER_ERRORS: 1225*10340Sstallion@opensolaris.org *val = dnetp->stat_nocarrier; 1226*10340Sstallion@opensolaris.org break; 1227*10340Sstallion@opensolaris.org 1228*10340Sstallion@opensolaris.org case ETHER_STAT_TOOSHORT_ERRORS: 1229*10340Sstallion@opensolaris.org *val = dnetp->stat_short; 1230*10340Sstallion@opensolaris.org break; 1231*10340Sstallion@opensolaris.org 1232*10340Sstallion@opensolaris.org case ETHER_STAT_LINK_DUPLEX: 1233*10340Sstallion@opensolaris.org if (!dnetp->running) { 1234*10340Sstallion@opensolaris.org *val = LINK_DUPLEX_UNKNOWN; 1235*10340Sstallion@opensolaris.org break; 1236*10340Sstallion@opensolaris.org } 1237*10340Sstallion@opensolaris.org 1238*10340Sstallion@opensolaris.org if (dnetp->mii_up) { 1239*10340Sstallion@opensolaris.org *val = dnetp->mii_duplex ? 1240*10340Sstallion@opensolaris.org LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; 1241*10340Sstallion@opensolaris.org } else { 1242*10340Sstallion@opensolaris.org *val = dnetp->full_duplex ? 1243*10340Sstallion@opensolaris.org LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; 1244*10340Sstallion@opensolaris.org } 1245*10340Sstallion@opensolaris.org break; 1246*10340Sstallion@opensolaris.org 1247*10340Sstallion@opensolaris.org case ETHER_STAT_TX_LATE_COLLISIONS: 1248*10340Sstallion@opensolaris.org *val = dnetp->stat_xmtlatecoll; 1249*10340Sstallion@opensolaris.org break; 1250*10340Sstallion@opensolaris.org 1251*10340Sstallion@opensolaris.org case ETHER_STAT_EX_COLLISIONS: 1252*10340Sstallion@opensolaris.org *val = dnetp->stat_excoll; 1253*10340Sstallion@opensolaris.org break; 1254*10340Sstallion@opensolaris.org 1255*10340Sstallion@opensolaris.org case MAC_STAT_OVERFLOWS: 1256*10340Sstallion@opensolaris.org *val = dnetp->stat_overflow; 1257*10340Sstallion@opensolaris.org break; 1258*10340Sstallion@opensolaris.org 1259*10340Sstallion@opensolaris.org case MAC_STAT_UNDERFLOWS: 1260*10340Sstallion@opensolaris.org *val = dnetp->stat_underflow; 1261*10340Sstallion@opensolaris.org break; 1262*10340Sstallion@opensolaris.org 1263*10340Sstallion@opensolaris.org default: 1264*10340Sstallion@opensolaris.org return (ENOTSUP); 12659860Sgdamore@opensolaris.org } 12669860Sgdamore@opensolaris.org 1267*10340Sstallion@opensolaris.org return (0); 12689860Sgdamore@opensolaris.org } 12699860Sgdamore@opensolaris.org 12709860Sgdamore@opensolaris.org #define NextTXIndex(index) (((index)+1) % dnetp->max_tx_desc) 12719860Sgdamore@opensolaris.org #define PrevTXIndex(index) (((index)-1) < 0 ? dnetp->max_tx_desc - 1: (index)-1) 12729860Sgdamore@opensolaris.org 1273*10340Sstallion@opensolaris.org static mblk_t * 1274*10340Sstallion@opensolaris.org dnet_m_tx(void *arg, mblk_t *mp) 12759860Sgdamore@opensolaris.org { 1276*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = arg; 1277*10340Sstallion@opensolaris.org 1278*10340Sstallion@opensolaris.org mutex_enter(&dnetp->txlock); 1279*10340Sstallion@opensolaris.org 1280*10340Sstallion@opensolaris.org /* if suspended, drop the packet on the floor, we missed it */ 1281*10340Sstallion@opensolaris.org if (dnetp->suspended) { 1282*10340Sstallion@opensolaris.org mutex_exit(&dnetp->txlock); 1283*10340Sstallion@opensolaris.org freemsg(mp); 1284*10340Sstallion@opensolaris.org return (NULL); 1285*10340Sstallion@opensolaris.org } 1286*10340Sstallion@opensolaris.org 1287*10340Sstallion@opensolaris.org if (dnetp->need_saddr) { 1288*10340Sstallion@opensolaris.org /* XXX function return value ignored */ 1289*10340Sstallion@opensolaris.org mutex_exit(&dnetp->txlock); 1290*10340Sstallion@opensolaris.org mutex_enter(&dnetp->intrlock); 1291*10340Sstallion@opensolaris.org (void) dnet_set_addr(dnetp); 1292*10340Sstallion@opensolaris.org mutex_exit(&dnetp->intrlock); 1293*10340Sstallion@opensolaris.org mutex_enter(&dnetp->txlock); 1294*10340Sstallion@opensolaris.org } 1295*10340Sstallion@opensolaris.org 1296*10340Sstallion@opensolaris.org while (mp != NULL) { 1297*10340Sstallion@opensolaris.org if (!dnet_send(dnetp, mp)) { 1298*10340Sstallion@opensolaris.org mutex_exit(&dnetp->txlock); 1299*10340Sstallion@opensolaris.org return (mp); 1300*10340Sstallion@opensolaris.org } 1301*10340Sstallion@opensolaris.org mp = mp->b_next; 1302*10340Sstallion@opensolaris.org } 1303*10340Sstallion@opensolaris.org 1304*10340Sstallion@opensolaris.org mutex_exit(&dnetp->txlock); 1305*10340Sstallion@opensolaris.org 1306*10340Sstallion@opensolaris.org /* 1307*10340Sstallion@opensolaris.org * Enable xmit interrupt in case we are running out of xmit descriptors 1308*10340Sstallion@opensolaris.org * or there are more packets on the queue waiting to be transmitted. 1309*10340Sstallion@opensolaris.org */ 1310*10340Sstallion@opensolaris.org mutex_enter(&dnetp->intrlock); 1311*10340Sstallion@opensolaris.org 1312*10340Sstallion@opensolaris.org enable_interrupts(dnetp); 1313*10340Sstallion@opensolaris.org 1314*10340Sstallion@opensolaris.org /* 1315*10340Sstallion@opensolaris.org * Kick the transmitter 1316*10340Sstallion@opensolaris.org */ 1317*10340Sstallion@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_POLL_REG), 1318*10340Sstallion@opensolaris.org TX_POLL_DEMAND); 1319*10340Sstallion@opensolaris.org 1320*10340Sstallion@opensolaris.org mutex_exit(&dnetp->intrlock); 1321*10340Sstallion@opensolaris.org 1322*10340Sstallion@opensolaris.org return (NULL); 1323*10340Sstallion@opensolaris.org } 1324*10340Sstallion@opensolaris.org 1325*10340Sstallion@opensolaris.org static boolean_t 1326*10340Sstallion@opensolaris.org dnet_send(struct dnetinstance *dnetp, mblk_t *mp) 1327*10340Sstallion@opensolaris.org { 13289860Sgdamore@opensolaris.org struct tx_desc_type *ring = dnetp->tx_desc; 13299860Sgdamore@opensolaris.org int mblen, totlen; 13309860Sgdamore@opensolaris.org int index, end_index, start_index; 13319860Sgdamore@opensolaris.org int avail; 13329860Sgdamore@opensolaris.org int error; 13339860Sgdamore@opensolaris.org int bufn; 13349860Sgdamore@opensolaris.org int retval; 13359860Sgdamore@opensolaris.org mblk_t *bp; 1336*10340Sstallion@opensolaris.org 1337*10340Sstallion@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->txlock)); 13389860Sgdamore@opensolaris.org 13399860Sgdamore@opensolaris.org /* reclaim any xmit descriptors completed */ 1340*10340Sstallion@opensolaris.org dnet_reclaim_Tx_desc(dnetp); 13419860Sgdamore@opensolaris.org 13429860Sgdamore@opensolaris.org /* 13439860Sgdamore@opensolaris.org * Use the data buffers from the message and construct the 13449860Sgdamore@opensolaris.org * scatter/gather list by calling ddi_dma_addr_bind_handle(). 13459860Sgdamore@opensolaris.org */ 1346*10340Sstallion@opensolaris.org error = 0; 13479860Sgdamore@opensolaris.org totlen = 0; 13489860Sgdamore@opensolaris.org bp = mp; 13499860Sgdamore@opensolaris.org bufn = 0; 13509860Sgdamore@opensolaris.org index = start_index = dnetp->tx_current_desc; 13519860Sgdamore@opensolaris.org avail = dnetp->free_desc; 13529860Sgdamore@opensolaris.org while (bp != NULL) { 13539860Sgdamore@opensolaris.org uint_t ncookies; 13549860Sgdamore@opensolaris.org ddi_dma_cookie_t dma_cookie; 13559860Sgdamore@opensolaris.org 1356*10340Sstallion@opensolaris.org mblen = MBLKL(bp); 13579860Sgdamore@opensolaris.org 13589860Sgdamore@opensolaris.org if (!mblen) { /* skip zero-length message blocks */ 13599860Sgdamore@opensolaris.org bp = bp->b_cont; 13609860Sgdamore@opensolaris.org continue; 13619860Sgdamore@opensolaris.org } 13629860Sgdamore@opensolaris.org 13639860Sgdamore@opensolaris.org retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL, 13649860Sgdamore@opensolaris.org (caddr_t)bp->b_rptr, mblen, 13659860Sgdamore@opensolaris.org DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 13669860Sgdamore@opensolaris.org &dma_cookie, &ncookies); 13679860Sgdamore@opensolaris.org 13689860Sgdamore@opensolaris.org switch (retval) { 13699860Sgdamore@opensolaris.org case DDI_DMA_MAPPED: 13709860Sgdamore@opensolaris.org break; /* everything's fine */ 13719860Sgdamore@opensolaris.org 13729860Sgdamore@opensolaris.org case DDI_DMA_NORESOURCES: 13739860Sgdamore@opensolaris.org error = 1; /* allow retry by gld */ 13749860Sgdamore@opensolaris.org break; 13759860Sgdamore@opensolaris.org 13769860Sgdamore@opensolaris.org case DDI_DMA_NOMAPPING: 13779860Sgdamore@opensolaris.org case DDI_DMA_INUSE: 13789860Sgdamore@opensolaris.org case DDI_DMA_TOOBIG: 13799860Sgdamore@opensolaris.org default: 13809860Sgdamore@opensolaris.org error = 2; /* error, no retry */ 13819860Sgdamore@opensolaris.org break; 13829860Sgdamore@opensolaris.org } 13839860Sgdamore@opensolaris.org 13849860Sgdamore@opensolaris.org /* 13859860Sgdamore@opensolaris.org * we can use two cookies per descriptor (i.e buffer1 and 13869860Sgdamore@opensolaris.org * buffer2) so we need at least (ncookies+1)/2 descriptors. 13879860Sgdamore@opensolaris.org */ 13889860Sgdamore@opensolaris.org if (((ncookies + 1) >> 1) > dnetp->free_desc) { 13899860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 13909860Sgdamore@opensolaris.org error = 1; 13919860Sgdamore@opensolaris.org break; 13929860Sgdamore@opensolaris.org } 13939860Sgdamore@opensolaris.org 13949860Sgdamore@opensolaris.org /* setup the descriptors for this data buffer */ 13959860Sgdamore@opensolaris.org while (ncookies) { 13969860Sgdamore@opensolaris.org end_index = index; 13979860Sgdamore@opensolaris.org if (bufn % 2) { 13989860Sgdamore@opensolaris.org ring[index].buffer2 = 13999860Sgdamore@opensolaris.org (uint32_t)dma_cookie.dmac_address; 14009860Sgdamore@opensolaris.org ring[index].desc1.buffer_size2 = 14019860Sgdamore@opensolaris.org dma_cookie.dmac_size; 14029860Sgdamore@opensolaris.org index = NextTXIndex(index); /* goto next desc */ 14039860Sgdamore@opensolaris.org } else { 14049860Sgdamore@opensolaris.org /* initialize the descriptor */ 14059860Sgdamore@opensolaris.org ASSERT(ring[index].desc0.own == 0); 14069860Sgdamore@opensolaris.org *(uint32_t *)&ring[index].desc0 = 0; 14079860Sgdamore@opensolaris.org *(uint32_t *)&ring[index].desc1 &= 14089860Sgdamore@opensolaris.org DNET_END_OF_RING; 14099860Sgdamore@opensolaris.org ring[index].buffer1 = 14109860Sgdamore@opensolaris.org (uint32_t)dma_cookie.dmac_address; 14119860Sgdamore@opensolaris.org ring[index].desc1.buffer_size1 = 14129860Sgdamore@opensolaris.org dma_cookie.dmac_size; 14139860Sgdamore@opensolaris.org ring[index].buffer2 = (uint32_t)(0); 14149860Sgdamore@opensolaris.org dnetp->free_desc--; 14159860Sgdamore@opensolaris.org ASSERT(dnetp->free_desc >= 0); 14169860Sgdamore@opensolaris.org } 14179860Sgdamore@opensolaris.org totlen += dma_cookie.dmac_size; 14189860Sgdamore@opensolaris.org bufn++; 14199860Sgdamore@opensolaris.org if (--ncookies) 14209860Sgdamore@opensolaris.org ddi_dma_nextcookie(dnetp->dma_handle_tx, 14219860Sgdamore@opensolaris.org &dma_cookie); 14229860Sgdamore@opensolaris.org } 14239860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 14249860Sgdamore@opensolaris.org bp = bp->b_cont; 14259860Sgdamore@opensolaris.org } 14269860Sgdamore@opensolaris.org 14279860Sgdamore@opensolaris.org if (error == 1) { 14289860Sgdamore@opensolaris.org dnetp->stat_defer++; 14299860Sgdamore@opensolaris.org dnetp->free_desc = avail; 1430*10340Sstallion@opensolaris.org dnetp->need_tx_update = B_TRUE; 1431*10340Sstallion@opensolaris.org return (B_FALSE); 14329860Sgdamore@opensolaris.org } else if (error) { 14339860Sgdamore@opensolaris.org dnetp->free_desc = avail; 14349860Sgdamore@opensolaris.org freemsg(mp); 1435*10340Sstallion@opensolaris.org return (B_TRUE); /* Drop packet, don't retry */ 14369860Sgdamore@opensolaris.org } 14379860Sgdamore@opensolaris.org 1438*10340Sstallion@opensolaris.org if (totlen > ETHERMAX + VLAN_TAGSZ) { 14399860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen); 14409860Sgdamore@opensolaris.org dnetp->free_desc = avail; 14419860Sgdamore@opensolaris.org freemsg(mp); 1442*10340Sstallion@opensolaris.org return (B_TRUE); /* Don't repeat this attempt */ 14439860Sgdamore@opensolaris.org } 14449860Sgdamore@opensolaris.org 14459860Sgdamore@opensolaris.org /* 14469860Sgdamore@opensolaris.org * Remeber the message buffer pointer to do freemsg() at xmit 14479860Sgdamore@opensolaris.org * interrupt time. 14489860Sgdamore@opensolaris.org */ 14499860Sgdamore@opensolaris.org dnetp->tx_msgbufp[end_index] = mp; 14509860Sgdamore@opensolaris.org 14519860Sgdamore@opensolaris.org /* 14529860Sgdamore@opensolaris.org * Now set the first/last buffer and own bits 14539860Sgdamore@opensolaris.org * Since the 21040 looks for these bits set in the 14549860Sgdamore@opensolaris.org * first buffer, work backwards in multiple buffers. 14559860Sgdamore@opensolaris.org */ 14569860Sgdamore@opensolaris.org ring[end_index].desc1.last_desc = 1; 14579860Sgdamore@opensolaris.org ring[end_index].desc1.int_on_comp = 1; 14589860Sgdamore@opensolaris.org for (index = end_index; index != start_index; 14599860Sgdamore@opensolaris.org index = PrevTXIndex(index)) 14609860Sgdamore@opensolaris.org ring[index].desc0.own = 1; 14619860Sgdamore@opensolaris.org ring[start_index].desc1.first_desc = 1; 14629860Sgdamore@opensolaris.org ring[start_index].desc0.own = 1; 14639860Sgdamore@opensolaris.org 14649860Sgdamore@opensolaris.org dnetp->tx_current_desc = NextTXIndex(end_index); 14659860Sgdamore@opensolaris.org 14669860Sgdamore@opensolaris.org /* 14679860Sgdamore@opensolaris.org * Safety check: make sure end-of-ring is set in last desc. 14689860Sgdamore@opensolaris.org */ 14699860Sgdamore@opensolaris.org ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0); 14709860Sgdamore@opensolaris.org 1471*10340Sstallion@opensolaris.org return (B_TRUE); 14729860Sgdamore@opensolaris.org } 14739860Sgdamore@opensolaris.org 14749860Sgdamore@opensolaris.org /* 1475*10340Sstallion@opensolaris.org * dnet_intr() -- interrupt from board to inform us that a receive or 14769860Sgdamore@opensolaris.org * transmit has completed. 14779860Sgdamore@opensolaris.org */ 14789860Sgdamore@opensolaris.org static uint_t 1479*10340Sstallion@opensolaris.org dnet_intr(caddr_t arg) 14809860Sgdamore@opensolaris.org { 1481*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = (struct dnetinstance *)arg; 1482*10340Sstallion@opensolaris.org uint32_t int_status; 14839860Sgdamore@opensolaris.org 14849860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 1485*10340Sstallion@opensolaris.org 14869860Sgdamore@opensolaris.org if (dnetp->suspended) { 14879860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 14889860Sgdamore@opensolaris.org return (DDI_INTR_UNCLAIMED); 14899860Sgdamore@opensolaris.org } 14909860Sgdamore@opensolaris.org 14919860Sgdamore@opensolaris.org int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, 14929860Sgdamore@opensolaris.org STATUS_REG)); 14939860Sgdamore@opensolaris.org 14949860Sgdamore@opensolaris.org /* 14959860Sgdamore@opensolaris.org * If interrupt was not from this board 14969860Sgdamore@opensolaris.org */ 14979860Sgdamore@opensolaris.org if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) { 14989860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 14999860Sgdamore@opensolaris.org return (DDI_INTR_UNCLAIMED); 15009860Sgdamore@opensolaris.org } 15019860Sgdamore@opensolaris.org 15029860Sgdamore@opensolaris.org dnetp->stat_intr++; 15039860Sgdamore@opensolaris.org 15049860Sgdamore@opensolaris.org if (int_status & GPTIMER_INTR) { 15059860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 15069860Sgdamore@opensolaris.org REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR); 15079860Sgdamore@opensolaris.org if (dnetp->timer.cb) 15089860Sgdamore@opensolaris.org dnetp->timer.cb(dnetp); 15099860Sgdamore@opensolaris.org else 15109860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet: unhandled timer interrupt"); 15119860Sgdamore@opensolaris.org } 15129860Sgdamore@opensolaris.org 15139860Sgdamore@opensolaris.org if (int_status & TX_INTR) { 15149860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 15159860Sgdamore@opensolaris.org REG32(dnetp->io_reg, STATUS_REG), TX_INTR); 15169860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 1517*10340Sstallion@opensolaris.org if (dnetp->need_tx_update) { 15189860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 15199860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 1520*10340Sstallion@opensolaris.org mac_tx_update(dnetp->mac_handle); 15219860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 15229860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 1523*10340Sstallion@opensolaris.org dnetp->need_tx_update = B_FALSE; 15249860Sgdamore@opensolaris.org } 15259860Sgdamore@opensolaris.org /* reclaim any xmit descriptors that are completed */ 1526*10340Sstallion@opensolaris.org dnet_reclaim_Tx_desc(dnetp); 15279860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 15289860Sgdamore@opensolaris.org } 15299860Sgdamore@opensolaris.org 15309860Sgdamore@opensolaris.org /* 15319860Sgdamore@opensolaris.org * Check if receive interrupt bit is set 15329860Sgdamore@opensolaris.org */ 15339860Sgdamore@opensolaris.org if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) { 15349860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 15359860Sgdamore@opensolaris.org REG32(dnetp->io_reg, STATUS_REG), 15369860Sgdamore@opensolaris.org int_status & (RX_INTR | RX_UNAVAIL_INTR)); 1537*10340Sstallion@opensolaris.org dnet_getp(dnetp); 15389860Sgdamore@opensolaris.org } 15399860Sgdamore@opensolaris.org 15409860Sgdamore@opensolaris.org if (int_status & ABNORMAL_INTR_SUMM) { 15419860Sgdamore@opensolaris.org /* 15429860Sgdamore@opensolaris.org * Check for system error 15439860Sgdamore@opensolaris.org */ 15449860Sgdamore@opensolaris.org if (int_status & SYS_ERR) { 15459860Sgdamore@opensolaris.org if ((int_status & SYS_ERR_BITS) == MASTER_ABORT) 15469860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Bus Master Abort"); 15479860Sgdamore@opensolaris.org if ((int_status & SYS_ERR_BITS) == TARGET_ABORT) 15489860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Bus Target Abort"); 15499860Sgdamore@opensolaris.org if ((int_status & SYS_ERR_BITS) == PARITY_ERROR) 15509860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Parity error"); 15519860Sgdamore@opensolaris.org } 15529860Sgdamore@opensolaris.org 15539860Sgdamore@opensolaris.org /* 15549860Sgdamore@opensolaris.org * If the jabber has timed out then reset the chip 15559860Sgdamore@opensolaris.org */ 15569860Sgdamore@opensolaris.org if (int_status & TX_JABBER_TIMEOUT) 15579860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Jabber timeout."); 15589860Sgdamore@opensolaris.org 15599860Sgdamore@opensolaris.org /* 15609860Sgdamore@opensolaris.org * If an underflow has occurred, reset the chip 15619860Sgdamore@opensolaris.org */ 15629860Sgdamore@opensolaris.org if (int_status & TX_UNDERFLOW) 15639860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: Tx Underflow."); 15649860Sgdamore@opensolaris.org 15659860Sgdamore@opensolaris.org #ifdef DNETDEBUG 15669860Sgdamore@opensolaris.org if (dnetdebug & DNETINT) 15679860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "Trying to reset..."); 15689860Sgdamore@opensolaris.org #endif 1569*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 1570*10340Sstallion@opensolaris.org dnet_init_board(dnetp); 15719860Sgdamore@opensolaris.org /* XXX function return value ignored */ 1572*10340Sstallion@opensolaris.org (void) dnet_start(dnetp); 15739860Sgdamore@opensolaris.org } 15749860Sgdamore@opensolaris.org 15759860Sgdamore@opensolaris.org /* 1576*10340Sstallion@opensolaris.org * Enable the interrupts. Enable xmit interrupt in case we are 15779860Sgdamore@opensolaris.org * running out of free descriptors or if there are packets 15789860Sgdamore@opensolaris.org * in the queue waiting to be transmitted. 15799860Sgdamore@opensolaris.org */ 1580*10340Sstallion@opensolaris.org enable_interrupts(dnetp); 15819860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 15829860Sgdamore@opensolaris.org return (DDI_INTR_CLAIMED); /* Indicate it was our interrupt */ 15839860Sgdamore@opensolaris.org } 15849860Sgdamore@opensolaris.org 15859860Sgdamore@opensolaris.org static void 1586*10340Sstallion@opensolaris.org dnet_getp(struct dnetinstance *dnetp) 15879860Sgdamore@opensolaris.org { 15889860Sgdamore@opensolaris.org int packet_length, index; 15899860Sgdamore@opensolaris.org mblk_t *mp; 15909860Sgdamore@opensolaris.org caddr_t virtual_address; 15919860Sgdamore@opensolaris.org struct rx_desc_type *desc = dnetp->rx_desc; 15929860Sgdamore@opensolaris.org int marker = dnetp->rx_current_desc; 15939860Sgdamore@opensolaris.org int misses; 15949860Sgdamore@opensolaris.org 15959860Sgdamore@opensolaris.org if (!dnetp->overrun_workaround) { 15969860Sgdamore@opensolaris.org /* 15979860Sgdamore@opensolaris.org * If the workaround is not in place, we must still update 15989860Sgdamore@opensolaris.org * the missed frame statistic from the on-chip counter. 15999860Sgdamore@opensolaris.org */ 16009860Sgdamore@opensolaris.org misses = ddi_get32(dnetp->io_handle, 16019860Sgdamore@opensolaris.org REG32(dnetp->io_reg, MISSED_FRAME_REG)); 16029860Sgdamore@opensolaris.org dnetp->stat_missed += (misses & MISSED_FRAME_MASK); 16039860Sgdamore@opensolaris.org } 16049860Sgdamore@opensolaris.org 16059860Sgdamore@opensolaris.org /* While host owns the current descriptor */ 16069860Sgdamore@opensolaris.org while (!(desc[dnetp->rx_current_desc].desc0.own)) { 16079860Sgdamore@opensolaris.org struct free_ptr *frp; 16089860Sgdamore@opensolaris.org caddr_t newbuf; 16099860Sgdamore@opensolaris.org struct rbuf_list *rp; 16109860Sgdamore@opensolaris.org 16119860Sgdamore@opensolaris.org index = dnetp->rx_current_desc; 16129860Sgdamore@opensolaris.org ASSERT(desc[index].desc0.first_desc != 0); 16139860Sgdamore@opensolaris.org 16149860Sgdamore@opensolaris.org /* 16159860Sgdamore@opensolaris.org * DMA overrun errata from DEC: avoid possible bus hangs 16169860Sgdamore@opensolaris.org * and data corruption 16179860Sgdamore@opensolaris.org */ 16189860Sgdamore@opensolaris.org if (dnetp->overrun_workaround && 16199860Sgdamore@opensolaris.org marker == dnetp->rx_current_desc) { 16209860Sgdamore@opensolaris.org int opn; 16219860Sgdamore@opensolaris.org do { 16229860Sgdamore@opensolaris.org marker = (marker+1) % dnetp->max_rx_desc; 16239860Sgdamore@opensolaris.org } while (!(dnetp->rx_desc[marker].desc0.own) && 16249860Sgdamore@opensolaris.org marker != index); 16259860Sgdamore@opensolaris.org 16269860Sgdamore@opensolaris.org misses = ddi_get32(dnetp->io_handle, 16279860Sgdamore@opensolaris.org REG32(dnetp->io_reg, MISSED_FRAME_REG)); 16289860Sgdamore@opensolaris.org dnetp->stat_missed += 16299860Sgdamore@opensolaris.org (misses & MISSED_FRAME_MASK); 16309860Sgdamore@opensolaris.org if (misses & OVERFLOW_COUNTER_MASK) { 16319860Sgdamore@opensolaris.org /* 16329860Sgdamore@opensolaris.org * Overflow(s) have occurred : stop receiver, 16339860Sgdamore@opensolaris.org * and wait until in stopped state 16349860Sgdamore@opensolaris.org */ 16359860Sgdamore@opensolaris.org opn = ddi_get32(dnetp->io_handle, 16369860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG)); 16379860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 16389860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), 16399860Sgdamore@opensolaris.org opn & ~(START_RECEIVE)); 16409860Sgdamore@opensolaris.org 16419860Sgdamore@opensolaris.org do { 16429860Sgdamore@opensolaris.org drv_usecwait(10); 16439860Sgdamore@opensolaris.org } while ((ddi_get32(dnetp->io_handle, 16449860Sgdamore@opensolaris.org REG32(dnetp->io_reg, STATUS_REG)) & 16459860Sgdamore@opensolaris.org RECEIVE_PROCESS_STATE) != 0); 16469860Sgdamore@opensolaris.org #ifdef DNETDEBUG 16479860Sgdamore@opensolaris.org if (dnetdebug & DNETRECV) 16489860Sgdamore@opensolaris.org cmn_err(CE_CONT, "^*"); 16499860Sgdamore@opensolaris.org #endif 16509860Sgdamore@opensolaris.org /* Discard probably corrupt frames */ 16519860Sgdamore@opensolaris.org while (!(dnetp->rx_desc[index].desc0.own)) { 16529860Sgdamore@opensolaris.org dnetp->rx_desc[index].desc0.own = 1; 16539860Sgdamore@opensolaris.org index = (index+1) % dnetp->max_rx_desc; 16549860Sgdamore@opensolaris.org dnetp->stat_missed++; 16559860Sgdamore@opensolaris.org } 16569860Sgdamore@opensolaris.org 16579860Sgdamore@opensolaris.org /* restart the receiver */ 16589860Sgdamore@opensolaris.org opn = ddi_get32(dnetp->io_handle, 16599860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG)); 16609860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 16619860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), 16629860Sgdamore@opensolaris.org opn | START_RECEIVE); 16639860Sgdamore@opensolaris.org marker = dnetp->rx_current_desc = index; 16649860Sgdamore@opensolaris.org continue; 16659860Sgdamore@opensolaris.org } 16669860Sgdamore@opensolaris.org /* 16679860Sgdamore@opensolaris.org * At this point, we know that all packets before 16689860Sgdamore@opensolaris.org * "marker" were received before a dma overrun occurred 16699860Sgdamore@opensolaris.org */ 16709860Sgdamore@opensolaris.org } 16719860Sgdamore@opensolaris.org 16729860Sgdamore@opensolaris.org /* 16739860Sgdamore@opensolaris.org * If we get an oversized packet it could span multiple 16749860Sgdamore@opensolaris.org * descriptors. If this happens an error bit should be set. 16759860Sgdamore@opensolaris.org */ 16769860Sgdamore@opensolaris.org while (desc[index].desc0.last_desc == 0) { 16779860Sgdamore@opensolaris.org index = (index + 1) % dnetp->max_rx_desc; 16789860Sgdamore@opensolaris.org if (desc[index].desc0.own) 16799860Sgdamore@opensolaris.org return; /* not done receiving large packet */ 16809860Sgdamore@opensolaris.org } 16819860Sgdamore@opensolaris.org while (dnetp->rx_current_desc != index) { 16829860Sgdamore@opensolaris.org desc[dnetp->rx_current_desc].desc0.own = 1; 16839860Sgdamore@opensolaris.org dnetp->rx_current_desc = 16849860Sgdamore@opensolaris.org (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc; 16859860Sgdamore@opensolaris.org #ifdef DNETDEBUG 16869860Sgdamore@opensolaris.org if (dnetdebug & DNETRECV) 16879860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet: received large packet"); 16889860Sgdamore@opensolaris.org #endif 16899860Sgdamore@opensolaris.org } 16909860Sgdamore@opensolaris.org 16919860Sgdamore@opensolaris.org packet_length = desc[index].desc0.frame_len; 16929860Sgdamore@opensolaris.org 16939860Sgdamore@opensolaris.org /* 16949860Sgdamore@opensolaris.org * Remove CRC from received data. This is an artefact of the 16959860Sgdamore@opensolaris.org * 21x4x chip and should not be passed higher up the network 16969860Sgdamore@opensolaris.org * stack. 16979860Sgdamore@opensolaris.org */ 16989860Sgdamore@opensolaris.org packet_length -= ETHERFCSL; 16999860Sgdamore@opensolaris.org 17009860Sgdamore@opensolaris.org /* get the virtual address of the packet received */ 17019860Sgdamore@opensolaris.org virtual_address = 17029860Sgdamore@opensolaris.org dnetp->rx_buf_vaddr[index]; 17039860Sgdamore@opensolaris.org 17049860Sgdamore@opensolaris.org /* 17059860Sgdamore@opensolaris.org * If no packet errors then do: 17069860Sgdamore@opensolaris.org * 1. Allocate a new receive buffer so that we can 17079860Sgdamore@opensolaris.org * use the current buffer as streams buffer to 17089860Sgdamore@opensolaris.org * avoid bcopy. 17099860Sgdamore@opensolaris.org * 2. If we got a new receive buffer then allocate 17109860Sgdamore@opensolaris.org * an mblk using desballoc(). 17119860Sgdamore@opensolaris.org * 3. Otherwise use the mblk from allocb() and do 17129860Sgdamore@opensolaris.org * the bcopy. 17139860Sgdamore@opensolaris.org */ 17149860Sgdamore@opensolaris.org frp = NULL; 17159860Sgdamore@opensolaris.org rp = NULL; 17169860Sgdamore@opensolaris.org newbuf = NULL; 17179860Sgdamore@opensolaris.org mp = NULL; 1718*10340Sstallion@opensolaris.org if (!desc[index].desc0.err_summary || 1719*10340Sstallion@opensolaris.org (desc[index].desc0.frame2long && 1720*10340Sstallion@opensolaris.org packet_length < rx_buf_size)) { 17219860Sgdamore@opensolaris.org ASSERT(packet_length < rx_buf_size); 17229860Sgdamore@opensolaris.org /* 17239860Sgdamore@opensolaris.org * Allocate another receive buffer for this descriptor. 17249860Sgdamore@opensolaris.org * If we fail to allocate then we do the normal bcopy. 17259860Sgdamore@opensolaris.org */ 17269860Sgdamore@opensolaris.org rp = dnet_rbuf_alloc(dnetp->devinfo, 0); 17279860Sgdamore@opensolaris.org if (rp != NULL) { 17289860Sgdamore@opensolaris.org newbuf = rp->rbuf_vaddr; 17299860Sgdamore@opensolaris.org frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP); 17309860Sgdamore@opensolaris.org if (frp != NULL) { 17319860Sgdamore@opensolaris.org frp->free_rtn.free_func = 17329860Sgdamore@opensolaris.org dnet_freemsg_buf; 17339860Sgdamore@opensolaris.org frp->free_rtn.free_arg = (char *)frp; 17349860Sgdamore@opensolaris.org frp->buf = virtual_address; 17359860Sgdamore@opensolaris.org mp = desballoc( 17369860Sgdamore@opensolaris.org (uchar_t *)virtual_address, 17379860Sgdamore@opensolaris.org packet_length, 0, &frp->free_rtn); 17389860Sgdamore@opensolaris.org if (mp == NULL) { 17399860Sgdamore@opensolaris.org kmem_free(frp, sizeof (*frp)); 17409860Sgdamore@opensolaris.org dnet_rbuf_free((caddr_t)newbuf); 17419860Sgdamore@opensolaris.org frp = NULL; 17429860Sgdamore@opensolaris.org newbuf = NULL; 17439860Sgdamore@opensolaris.org } 17449860Sgdamore@opensolaris.org } 17459860Sgdamore@opensolaris.org } 17469860Sgdamore@opensolaris.org if (mp == NULL) { 17479860Sgdamore@opensolaris.org if (newbuf != NULL) 17489860Sgdamore@opensolaris.org dnet_rbuf_free((caddr_t)newbuf); 17499860Sgdamore@opensolaris.org mp = allocb(packet_length, 0); 17509860Sgdamore@opensolaris.org } 17519860Sgdamore@opensolaris.org } 17529860Sgdamore@opensolaris.org 1753*10340Sstallion@opensolaris.org if ((desc[index].desc0.err_summary && 1754*10340Sstallion@opensolaris.org packet_length >= rx_buf_size) || mp == NULL) { 17559860Sgdamore@opensolaris.org 17569860Sgdamore@opensolaris.org /* Update gld statistics */ 17579860Sgdamore@opensolaris.org if (desc[index].desc0.err_summary) 1758*10340Sstallion@opensolaris.org update_rx_stats(dnetp, index); 17599860Sgdamore@opensolaris.org else 17609860Sgdamore@opensolaris.org dnetp->stat_norcvbuf++; 17619860Sgdamore@opensolaris.org 17629860Sgdamore@opensolaris.org /* 17639860Sgdamore@opensolaris.org * Reset ownership of the descriptor. 17649860Sgdamore@opensolaris.org */ 17659860Sgdamore@opensolaris.org desc[index].desc0.own = 1; 17669860Sgdamore@opensolaris.org dnetp->rx_current_desc = 17679860Sgdamore@opensolaris.org (dnetp->rx_current_desc+1) % dnetp->max_rx_desc; 17689860Sgdamore@opensolaris.org 17699860Sgdamore@opensolaris.org /* Demand receive polling by the chip */ 17709860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 17719860Sgdamore@opensolaris.org REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND); 17729860Sgdamore@opensolaris.org 17739860Sgdamore@opensolaris.org continue; 17749860Sgdamore@opensolaris.org } 17759860Sgdamore@opensolaris.org 17769860Sgdamore@opensolaris.org if (newbuf != NULL) { 17779860Sgdamore@opensolaris.org uint32_t end_paddr; 17789860Sgdamore@opensolaris.org /* attach the new buffer to the rx descriptor */ 17799860Sgdamore@opensolaris.org dnetp->rx_buf_vaddr[index] = newbuf; 17809860Sgdamore@opensolaris.org dnetp->rx_buf_paddr[index] = rp->rbuf_paddr; 17819860Sgdamore@opensolaris.org desc[index].buffer1 = rp->rbuf_paddr; 17829860Sgdamore@opensolaris.org desc[index].desc1.buffer_size1 = rx_buf_size; 17839860Sgdamore@opensolaris.org desc[index].desc1.buffer_size2 = 0; 17849860Sgdamore@opensolaris.org end_paddr = rp->rbuf_endpaddr; 17859860Sgdamore@opensolaris.org if ((desc[index].buffer1 & ~dnetp->pgmask) != 17869860Sgdamore@opensolaris.org (end_paddr & ~dnetp->pgmask)) { 17879860Sgdamore@opensolaris.org /* discontiguous */ 17889860Sgdamore@opensolaris.org desc[index].buffer2 = end_paddr&~dnetp->pgmask; 17899860Sgdamore@opensolaris.org desc[index].desc1.buffer_size2 = 17909860Sgdamore@opensolaris.org (end_paddr & dnetp->pgmask) + 1; 17919860Sgdamore@opensolaris.org desc[index].desc1.buffer_size1 = 17929860Sgdamore@opensolaris.org rx_buf_size-desc[index].desc1.buffer_size2; 17939860Sgdamore@opensolaris.org } 17949860Sgdamore@opensolaris.org } else { 17959860Sgdamore@opensolaris.org /* couldn't allocate another buffer; copy the data */ 17969860Sgdamore@opensolaris.org BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr, 17979860Sgdamore@opensolaris.org packet_length); 17989860Sgdamore@opensolaris.org } 17999860Sgdamore@opensolaris.org 18009860Sgdamore@opensolaris.org mp->b_wptr += packet_length; 18019860Sgdamore@opensolaris.org 18029860Sgdamore@opensolaris.org desc[dnetp->rx_current_desc].desc0.own = 1; 18039860Sgdamore@opensolaris.org 18049860Sgdamore@opensolaris.org /* 18059860Sgdamore@opensolaris.org * Increment receive desc index. This is for the scan of 18069860Sgdamore@opensolaris.org * next packet 18079860Sgdamore@opensolaris.org */ 18089860Sgdamore@opensolaris.org dnetp->rx_current_desc = 18099860Sgdamore@opensolaris.org (dnetp->rx_current_desc+1) % dnetp->max_rx_desc; 18109860Sgdamore@opensolaris.org 18119860Sgdamore@opensolaris.org /* Demand polling by chip */ 18129860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 18139860Sgdamore@opensolaris.org REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND); 18149860Sgdamore@opensolaris.org 18159860Sgdamore@opensolaris.org /* send the packet upstream */ 18169860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 1817*10340Sstallion@opensolaris.org mac_rx(dnetp->mac_handle, NULL, mp); 18189860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 18199860Sgdamore@opensolaris.org } 18209860Sgdamore@opensolaris.org } 18219860Sgdamore@opensolaris.org /* 18229860Sgdamore@opensolaris.org * Function to update receive statistics 18239860Sgdamore@opensolaris.org */ 18249860Sgdamore@opensolaris.org static void 1825*10340Sstallion@opensolaris.org update_rx_stats(struct dnetinstance *dnetp, int index) 18269860Sgdamore@opensolaris.org { 18279860Sgdamore@opensolaris.org struct rx_desc_type *descp = &(dnetp->rx_desc[index]); 18289860Sgdamore@opensolaris.org 18299860Sgdamore@opensolaris.org /* 18309860Sgdamore@opensolaris.org * Update gld statistics 18319860Sgdamore@opensolaris.org */ 18329860Sgdamore@opensolaris.org dnetp->stat_errrcv++; 18339860Sgdamore@opensolaris.org 18349860Sgdamore@opensolaris.org if (descp->desc0.overflow) { 18359860Sgdamore@opensolaris.org /* FIFO Overrun */ 18369860Sgdamore@opensolaris.org dnetp->stat_overflow++; 18379860Sgdamore@opensolaris.org } 18389860Sgdamore@opensolaris.org 18399860Sgdamore@opensolaris.org if (descp->desc0.collision) { 18409860Sgdamore@opensolaris.org /*EMPTY*/ 18419860Sgdamore@opensolaris.org /* Late Colllision on receive */ 18429860Sgdamore@opensolaris.org /* no appropriate counter */ 18439860Sgdamore@opensolaris.org } 18449860Sgdamore@opensolaris.org 18459860Sgdamore@opensolaris.org if (descp->desc0.crc) { 18469860Sgdamore@opensolaris.org /* CRC Error */ 18479860Sgdamore@opensolaris.org dnetp->stat_crc++; 18489860Sgdamore@opensolaris.org } 18499860Sgdamore@opensolaris.org 18509860Sgdamore@opensolaris.org if (descp->desc0.runt_frame) { 18519860Sgdamore@opensolaris.org /* Runt Error */ 18529860Sgdamore@opensolaris.org dnetp->stat_short++; 18539860Sgdamore@opensolaris.org } 18549860Sgdamore@opensolaris.org 18559860Sgdamore@opensolaris.org if (descp->desc0.desc_err) { 18569860Sgdamore@opensolaris.org /*EMPTY*/ 18579860Sgdamore@opensolaris.org /* Not enough receive descriptors */ 1858*10340Sstallion@opensolaris.org /* This condition is accounted in dnet_intr() */ 18599860Sgdamore@opensolaris.org } 18609860Sgdamore@opensolaris.org 18619860Sgdamore@opensolaris.org if (descp->desc0.frame2long) { 18629860Sgdamore@opensolaris.org dnetp->stat_frame++; 18639860Sgdamore@opensolaris.org } 18649860Sgdamore@opensolaris.org } 18659860Sgdamore@opensolaris.org 18669860Sgdamore@opensolaris.org /* 18679860Sgdamore@opensolaris.org * Function to update transmit statistics 18689860Sgdamore@opensolaris.org */ 18699860Sgdamore@opensolaris.org static void 1870*10340Sstallion@opensolaris.org update_tx_stats(struct dnetinstance *dnetp, int index) 18719860Sgdamore@opensolaris.org { 18729860Sgdamore@opensolaris.org struct tx_desc_type *descp = &(dnetp->tx_desc[index]); 18739860Sgdamore@opensolaris.org int fd; 18749860Sgdamore@opensolaris.org media_block_t *block = dnetp->selected_media_block; 18759860Sgdamore@opensolaris.org 18769860Sgdamore@opensolaris.org 18779860Sgdamore@opensolaris.org /* Update gld statistics */ 18789860Sgdamore@opensolaris.org dnetp->stat_errxmt++; 18799860Sgdamore@opensolaris.org 18809860Sgdamore@opensolaris.org /* If we're in full-duplex don't count collisions or carrier loss. */ 18819860Sgdamore@opensolaris.org if (dnetp->mii_up) { 18829860Sgdamore@opensolaris.org fd = dnetp->mii_duplex; 18839860Sgdamore@opensolaris.org } else { 18849860Sgdamore@opensolaris.org /* Rely on media code */ 18859860Sgdamore@opensolaris.org fd = block->media_code == MEDIA_TP_FD || 18869860Sgdamore@opensolaris.org block->media_code == MEDIA_SYM_SCR_FD; 18879860Sgdamore@opensolaris.org } 18889860Sgdamore@opensolaris.org 18899860Sgdamore@opensolaris.org if (descp->desc0.collision_count && !fd) { 18909860Sgdamore@opensolaris.org dnetp->stat_collisions += descp->desc0.collision_count; 18919860Sgdamore@opensolaris.org } 18929860Sgdamore@opensolaris.org 18939860Sgdamore@opensolaris.org if (descp->desc0.late_collision && !fd) { 18949860Sgdamore@opensolaris.org dnetp->stat_xmtlatecoll++; 18959860Sgdamore@opensolaris.org } 18969860Sgdamore@opensolaris.org 18979860Sgdamore@opensolaris.org if (descp->desc0.excess_collision && !fd) { 18989860Sgdamore@opensolaris.org dnetp->stat_excoll++; 18999860Sgdamore@opensolaris.org } 19009860Sgdamore@opensolaris.org 19019860Sgdamore@opensolaris.org if (descp->desc0.underflow) { 19029860Sgdamore@opensolaris.org dnetp->stat_underflow++; 19039860Sgdamore@opensolaris.org } 19049860Sgdamore@opensolaris.org 19059860Sgdamore@opensolaris.org #if 0 19069860Sgdamore@opensolaris.org if (descp->desc0.tx_jabber_to) { 19079860Sgdamore@opensolaris.org /* no appropriate counter */ 19089860Sgdamore@opensolaris.org } 19099860Sgdamore@opensolaris.org #endif 19109860Sgdamore@opensolaris.org 19119860Sgdamore@opensolaris.org if (descp->desc0.carrier_loss && !fd) { 19129860Sgdamore@opensolaris.org dnetp->stat_nocarrier++; 19139860Sgdamore@opensolaris.org } 19149860Sgdamore@opensolaris.org 19159860Sgdamore@opensolaris.org if (descp->desc0.no_carrier && !fd) { 19169860Sgdamore@opensolaris.org dnetp->stat_nocarrier++; 19179860Sgdamore@opensolaris.org } 19189860Sgdamore@opensolaris.org } 19199860Sgdamore@opensolaris.org 19209860Sgdamore@opensolaris.org /* 19219860Sgdamore@opensolaris.org * ========== Media Selection Setup Routines ========== 19229860Sgdamore@opensolaris.org */ 19239860Sgdamore@opensolaris.org 19249860Sgdamore@opensolaris.org 19259860Sgdamore@opensolaris.org static void 19269860Sgdamore@opensolaris.org write_gpr(struct dnetinstance *dnetp, uint32_t val) 19279860Sgdamore@opensolaris.org { 19289860Sgdamore@opensolaris.org #ifdef DEBUG 19299860Sgdamore@opensolaris.org if (dnetdebug & DNETREGCFG) 19309860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "GPR: %x", val); 19319860Sgdamore@opensolaris.org #endif 19329860Sgdamore@opensolaris.org switch (dnetp->board_type) { 19339860Sgdamore@opensolaris.org case DEVICE_ID_21143: 19349860Sgdamore@opensolaris.org /* Set the correct bit for a control write */ 19359860Sgdamore@opensolaris.org if (val & GPR_CONTROL_WRITE) 19369860Sgdamore@opensolaris.org val |= CWE_21143, val &= ~GPR_CONTROL_WRITE; 19379860Sgdamore@opensolaris.org /* Write to upper half of CSR15 */ 19389860Sgdamore@opensolaris.org dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16); 19399860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 19409860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia); 19419860Sgdamore@opensolaris.org break; 19429860Sgdamore@opensolaris.org default: 19439860Sgdamore@opensolaris.org /* Set the correct bit for a control write */ 19449860Sgdamore@opensolaris.org if (val & GPR_CONTROL_WRITE) 19459860Sgdamore@opensolaris.org val |= CWE_21140, val &= ~GPR_CONTROL_WRITE; 19469860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val); 19479860Sgdamore@opensolaris.org break; 19489860Sgdamore@opensolaris.org } 19499860Sgdamore@opensolaris.org } 19509860Sgdamore@opensolaris.org 19519860Sgdamore@opensolaris.org static uint32_t 19529860Sgdamore@opensolaris.org read_gpr(struct dnetinstance *dnetp) 19539860Sgdamore@opensolaris.org { 19549860Sgdamore@opensolaris.org switch (dnetp->board_type) { 19559860Sgdamore@opensolaris.org case DEVICE_ID_21143: 19569860Sgdamore@opensolaris.org /* Read upper half of CSR15 */ 19579860Sgdamore@opensolaris.org return (ddi_get32(dnetp->io_handle, 19589860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16); 19599860Sgdamore@opensolaris.org default: 19609860Sgdamore@opensolaris.org return (ddi_get32(dnetp->io_handle, 19619860Sgdamore@opensolaris.org REG32(dnetp->io_reg, GP_REG))); 19629860Sgdamore@opensolaris.org } 19639860Sgdamore@opensolaris.org } 19649860Sgdamore@opensolaris.org 19659860Sgdamore@opensolaris.org static void 1966*10340Sstallion@opensolaris.org set_gpr(struct dnetinstance *dnetp) 19679860Sgdamore@opensolaris.org { 19689860Sgdamore@opensolaris.org uint32_t *sequence; 19699860Sgdamore@opensolaris.org int len; 19709860Sgdamore@opensolaris.org LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf]; 19719860Sgdamore@opensolaris.org media_block_t *block = dnetp->selected_media_block; 19729860Sgdamore@opensolaris.org int i; 19739860Sgdamore@opensolaris.org 19749860Sgdamore@opensolaris.org if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo, 19759860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence, 19769860Sgdamore@opensolaris.org &len) == DDI_PROP_SUCCESS) { 19779860Sgdamore@opensolaris.org for (i = 0; i < len / sizeof (uint32_t); i++) 19789860Sgdamore@opensolaris.org write_gpr(dnetp, sequence[i]); 19799860Sgdamore@opensolaris.org kmem_free(sequence, len); 19809860Sgdamore@opensolaris.org } else { 19819860Sgdamore@opensolaris.org /* 19829860Sgdamore@opensolaris.org * Write the reset sequence if this is the first time this 19839860Sgdamore@opensolaris.org * block has been selected. 19849860Sgdamore@opensolaris.org */ 19859860Sgdamore@opensolaris.org if (block->rstseqlen) { 19869860Sgdamore@opensolaris.org for (i = 0; i < block->rstseqlen; i++) 19879860Sgdamore@opensolaris.org write_gpr(dnetp, block->rstseq[i]); 19889860Sgdamore@opensolaris.org /* 19899860Sgdamore@opensolaris.org * XXX Legacy blocks do not have reset sequences, so the 19909860Sgdamore@opensolaris.org * static blocks will never be modified by this 19919860Sgdamore@opensolaris.org */ 19929860Sgdamore@opensolaris.org block->rstseqlen = 0; 19939860Sgdamore@opensolaris.org } 19949860Sgdamore@opensolaris.org if (leaf->gpr) 19959860Sgdamore@opensolaris.org write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE); 19969860Sgdamore@opensolaris.org 19979860Sgdamore@opensolaris.org /* write GPR sequence each time */ 19989860Sgdamore@opensolaris.org for (i = 0; i < block->gprseqlen; i++) 19999860Sgdamore@opensolaris.org write_gpr(dnetp, block->gprseq[i]); 20009860Sgdamore@opensolaris.org } 20019860Sgdamore@opensolaris.org 20029860Sgdamore@opensolaris.org /* This has possibly caused a PHY to reset. Let MII know */ 20039860Sgdamore@opensolaris.org if (dnetp->phyaddr != -1) 20049860Sgdamore@opensolaris.org /* XXX function return value ignored */ 20059860Sgdamore@opensolaris.org (void) mii_sync(dnetp->mii, dnetp->phyaddr); 20069860Sgdamore@opensolaris.org drv_usecwait(5); 20079860Sgdamore@opensolaris.org } 20089860Sgdamore@opensolaris.org 20099860Sgdamore@opensolaris.org /* set_opr() - must be called with intrlock held */ 20109860Sgdamore@opensolaris.org 20119860Sgdamore@opensolaris.org static void 2012*10340Sstallion@opensolaris.org set_opr(struct dnetinstance *dnetp) 20139860Sgdamore@opensolaris.org { 20149860Sgdamore@opensolaris.org uint32_t fd, mb1, sf; 20159860Sgdamore@opensolaris.org 20169860Sgdamore@opensolaris.org int opnmode_len; 20179860Sgdamore@opensolaris.org uint32_t val; 20189860Sgdamore@opensolaris.org media_block_t *block = dnetp->selected_media_block; 20199860Sgdamore@opensolaris.org 20209860Sgdamore@opensolaris.org ASSERT(block); 20219860Sgdamore@opensolaris.org 20229860Sgdamore@opensolaris.org /* Check for custom "opnmode_reg" property */ 20239860Sgdamore@opensolaris.org opnmode_len = sizeof (val); 20249860Sgdamore@opensolaris.org if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo, 20259860Sgdamore@opensolaris.org PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg", 20269860Sgdamore@opensolaris.org (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS) 20279860Sgdamore@opensolaris.org opnmode_len = 0; 20289860Sgdamore@opensolaris.org 20299860Sgdamore@opensolaris.org /* Some bits exist only on 21140 and greater */ 20309860Sgdamore@opensolaris.org if (dnetp->board_type != DEVICE_ID_21040 && 20319860Sgdamore@opensolaris.org dnetp->board_type != DEVICE_ID_21041) { 20329860Sgdamore@opensolaris.org mb1 = OPN_REG_MB1; 20339860Sgdamore@opensolaris.org sf = STORE_AND_FORWARD; 20349860Sgdamore@opensolaris.org } else { 20359860Sgdamore@opensolaris.org mb1 = sf = 0; 20369860Sgdamore@opensolaris.org mb1 = OPN_REG_MB1; /* Needed for 21040? */ 20379860Sgdamore@opensolaris.org } 20389860Sgdamore@opensolaris.org 20399860Sgdamore@opensolaris.org if (opnmode_len) { 20409860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 20419860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), val); 2042*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 20439860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 20449860Sgdamore@opensolaris.org REG32(dnetp->io_reg, OPN_MODE_REG), val); 20459860Sgdamore@opensolaris.org return; 20469860Sgdamore@opensolaris.org } 20479860Sgdamore@opensolaris.org 20489860Sgdamore@opensolaris.org /* 20499860Sgdamore@opensolaris.org * Set each bit in CSR6 that we want 20509860Sgdamore@opensolaris.org */ 20519860Sgdamore@opensolaris.org 20529860Sgdamore@opensolaris.org /* Always want these bits set */ 20539860Sgdamore@opensolaris.org val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf; 20549860Sgdamore@opensolaris.org 20559860Sgdamore@opensolaris.org /* Promiscuous mode */ 20569860Sgdamore@opensolaris.org val |= dnetp->promisc ? PROM_MODE : 0; 20579860Sgdamore@opensolaris.org 20589860Sgdamore@opensolaris.org /* Scrambler for SYM style media */ 20599860Sgdamore@opensolaris.org val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ? 20609860Sgdamore@opensolaris.org SCRAMBLER_MODE : 0; 20619860Sgdamore@opensolaris.org 20629860Sgdamore@opensolaris.org /* Full duplex */ 20639860Sgdamore@opensolaris.org if (dnetp->mii_up) { 20649860Sgdamore@opensolaris.org fd = dnetp->mii_duplex; 20659860Sgdamore@opensolaris.org } else { 20669860Sgdamore@opensolaris.org /* Rely on media code */ 20679860Sgdamore@opensolaris.org fd = block->media_code == MEDIA_TP_FD || 20689860Sgdamore@opensolaris.org block->media_code == MEDIA_SYM_SCR_FD; 20699860Sgdamore@opensolaris.org } 20709860Sgdamore@opensolaris.org 20719860Sgdamore@opensolaris.org /* Port select (and therefore, heartbeat disable) */ 20729860Sgdamore@opensolaris.org val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0; 20739860Sgdamore@opensolaris.org 20749860Sgdamore@opensolaris.org /* PCS function */ 20759860Sgdamore@opensolaris.org val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0; 20769860Sgdamore@opensolaris.org val |= fd ? FULL_DUPLEX : 0; 20779860Sgdamore@opensolaris.org 20789860Sgdamore@opensolaris.org #ifdef DNETDEBUG 20799860Sgdamore@opensolaris.org if (dnetdebug & DNETREGCFG) 20809860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "OPN: %x", val); 20819860Sgdamore@opensolaris.org #endif 20829860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val); 2083*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 20849860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val); 20859860Sgdamore@opensolaris.org } 20869860Sgdamore@opensolaris.org 20879860Sgdamore@opensolaris.org static void 2088*10340Sstallion@opensolaris.org set_sia(struct dnetinstance *dnetp) 20899860Sgdamore@opensolaris.org { 20909860Sgdamore@opensolaris.org media_block_t *block = dnetp->selected_media_block; 20919860Sgdamore@opensolaris.org 20929860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 20939860Sgdamore@opensolaris.org if (block->type == 2) { 20949860Sgdamore@opensolaris.org int sia_delay; 20959860Sgdamore@opensolaris.org #ifdef DNETDEBUG 20969860Sgdamore@opensolaris.org if (dnetdebug & DNETREGCFG) 20979860Sgdamore@opensolaris.org cmn_err(CE_NOTE, 20989860Sgdamore@opensolaris.org "SIA: CSR13: %x, CSR14: %x, CSR15: %x", 20999860Sgdamore@opensolaris.org block->un.sia.csr13, 21009860Sgdamore@opensolaris.org block->un.sia.csr14, 21019860Sgdamore@opensolaris.org block->un.sia.csr15); 21029860Sgdamore@opensolaris.org #endif 21039860Sgdamore@opensolaris.org sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 21049860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "sia-delay", 10000); 21059860Sgdamore@opensolaris.org 21069860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 21079860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_CONNECT_REG), 0); 21089860Sgdamore@opensolaris.org 21099860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG), 21109860Sgdamore@opensolaris.org block->un.sia.csr14); 21119860Sgdamore@opensolaris.org 21129860Sgdamore@opensolaris.org /* 21139860Sgdamore@opensolaris.org * For '143, we need to write through a copy of the register 21149860Sgdamore@opensolaris.org * to keep the GP half intact 21159860Sgdamore@opensolaris.org */ 21169860Sgdamore@opensolaris.org dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15; 21179860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 21189860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_GENERAL_REG), 21199860Sgdamore@opensolaris.org dnetp->gprsia); 21209860Sgdamore@opensolaris.org 21219860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 21229860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_CONNECT_REG), 21239860Sgdamore@opensolaris.org block->un.sia.csr13); 21249860Sgdamore@opensolaris.org 21259860Sgdamore@opensolaris.org drv_usecwait(sia_delay); 21269860Sgdamore@opensolaris.org 21279860Sgdamore@opensolaris.org } else if (dnetp->board_type != DEVICE_ID_21140) { 21289860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 21299860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_CONNECT_REG), 0); 21309860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 21319860Sgdamore@opensolaris.org REG32(dnetp->io_reg, SIA_TXRX_REG), 0); 21329860Sgdamore@opensolaris.org } 21339860Sgdamore@opensolaris.org } 21349860Sgdamore@opensolaris.org 21359860Sgdamore@opensolaris.org /* 21369860Sgdamore@opensolaris.org * This function (re)allocates the receive and transmit buffers and 21379860Sgdamore@opensolaris.org * descriptors. It can be called more than once per instance, though 21389860Sgdamore@opensolaris.org * currently it is only called from attach. It should only be called 21399860Sgdamore@opensolaris.org * while the device is reset. 21409860Sgdamore@opensolaris.org */ 21419860Sgdamore@opensolaris.org static int 2142*10340Sstallion@opensolaris.org dnet_alloc_bufs(struct dnetinstance *dnetp) 21439860Sgdamore@opensolaris.org { 21449860Sgdamore@opensolaris.org int i; 21459860Sgdamore@opensolaris.org size_t len; 21469860Sgdamore@opensolaris.org int page_size; 21479860Sgdamore@opensolaris.org int realloc = 0; 21489860Sgdamore@opensolaris.org int nrecv_desc_old = 0; 21499860Sgdamore@opensolaris.org ddi_dma_cookie_t cookie; 21509860Sgdamore@opensolaris.org uint_t ncookies; 21519860Sgdamore@opensolaris.org 21529860Sgdamore@opensolaris.org /* 21539860Sgdamore@opensolaris.org * check if we are trying to reallocate with different xmit/recv 21549860Sgdamore@opensolaris.org * descriptor ring sizes. 21559860Sgdamore@opensolaris.org */ 21569860Sgdamore@opensolaris.org if ((dnetp->tx_desc != NULL) && 21579860Sgdamore@opensolaris.org (dnetp->nxmit_desc != dnetp->max_tx_desc)) 21589860Sgdamore@opensolaris.org realloc = 1; 21599860Sgdamore@opensolaris.org 21609860Sgdamore@opensolaris.org if ((dnetp->rx_desc != NULL) && 21619860Sgdamore@opensolaris.org (dnetp->nrecv_desc != dnetp->max_rx_desc)) 21629860Sgdamore@opensolaris.org realloc = 1; 21639860Sgdamore@opensolaris.org 21649860Sgdamore@opensolaris.org /* free up the old buffers if we are reallocating them */ 21659860Sgdamore@opensolaris.org if (realloc) { 21669860Sgdamore@opensolaris.org nrecv_desc_old = dnetp->nrecv_desc; 2167*10340Sstallion@opensolaris.org dnet_free_bufs(dnetp); /* free the old buffers */ 21689860Sgdamore@opensolaris.org } 21699860Sgdamore@opensolaris.org 21709860Sgdamore@opensolaris.org if (dnetp->dma_handle == NULL) 21719860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 21729860Sgdamore@opensolaris.org DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS) 21739860Sgdamore@opensolaris.org return (FAILURE); 21749860Sgdamore@opensolaris.org 21759860Sgdamore@opensolaris.org if (dnetp->dma_handle_tx == NULL) 21769860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx, 21779860Sgdamore@opensolaris.org DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS) 21789860Sgdamore@opensolaris.org return (FAILURE); 21799860Sgdamore@opensolaris.org 21809860Sgdamore@opensolaris.org if (dnetp->dma_handle_txdesc == NULL) 21819860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 21829860Sgdamore@opensolaris.org DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS) 21839860Sgdamore@opensolaris.org return (FAILURE); 21849860Sgdamore@opensolaris.org 21859860Sgdamore@opensolaris.org if (dnetp->dma_handle_setbuf == NULL) 21869860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 21879860Sgdamore@opensolaris.org DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS) 21889860Sgdamore@opensolaris.org return (FAILURE); 21899860Sgdamore@opensolaris.org 21909860Sgdamore@opensolaris.org page_size = ddi_ptob(dnetp->devinfo, 1); 21919860Sgdamore@opensolaris.org 21929860Sgdamore@opensolaris.org dnetp->pgmask = page_size - 1; 21939860Sgdamore@opensolaris.org 21949860Sgdamore@opensolaris.org /* allocate setup buffer if necessary */ 21959860Sgdamore@opensolaris.org if (dnetp->setup_buf_vaddr == NULL) { 21969860Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf, 21979860Sgdamore@opensolaris.org SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING, 21989860Sgdamore@opensolaris.org DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr, 21999860Sgdamore@opensolaris.org &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS) 22009860Sgdamore@opensolaris.org return (FAILURE); 22019860Sgdamore@opensolaris.org 22029860Sgdamore@opensolaris.org if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf, 22039860Sgdamore@opensolaris.org NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE, 22049860Sgdamore@opensolaris.org DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 22059860Sgdamore@opensolaris.org NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 22069860Sgdamore@opensolaris.org return (FAILURE); 22079860Sgdamore@opensolaris.org 22089860Sgdamore@opensolaris.org dnetp->setup_buf_paddr = cookie.dmac_address; 22099860Sgdamore@opensolaris.org bzero(dnetp->setup_buf_vaddr, len); 22109860Sgdamore@opensolaris.org } 22119860Sgdamore@opensolaris.org 22129860Sgdamore@opensolaris.org /* allocate xmit descriptor array of size dnetp->max_tx_desc */ 22139860Sgdamore@opensolaris.org if (dnetp->tx_desc == NULL) { 22149860Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc, 22159860Sgdamore@opensolaris.org sizeof (struct tx_desc_type) * dnetp->max_tx_desc, 22169860Sgdamore@opensolaris.org &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 22179860Sgdamore@opensolaris.org (caddr_t *)&dnetp->tx_desc, &len, 22189860Sgdamore@opensolaris.org &dnetp->tx_desc_acchdl) != DDI_SUCCESS) 22199860Sgdamore@opensolaris.org return (FAILURE); 22209860Sgdamore@opensolaris.org 22219860Sgdamore@opensolaris.org if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc, 22229860Sgdamore@opensolaris.org NULL, (caddr_t)dnetp->tx_desc, 22239860Sgdamore@opensolaris.org sizeof (struct tx_desc_type) * dnetp->max_tx_desc, 22249860Sgdamore@opensolaris.org DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 22259860Sgdamore@opensolaris.org NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 22269860Sgdamore@opensolaris.org return (FAILURE); 22279860Sgdamore@opensolaris.org dnetp->tx_desc_paddr = cookie.dmac_address; 22289860Sgdamore@opensolaris.org bzero(dnetp->tx_desc, len); 22299860Sgdamore@opensolaris.org dnetp->nxmit_desc = dnetp->max_tx_desc; 22309860Sgdamore@opensolaris.org 22319860Sgdamore@opensolaris.org dnetp->tx_msgbufp = 22329860Sgdamore@opensolaris.org kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **), 22339860Sgdamore@opensolaris.org KM_SLEEP); 22349860Sgdamore@opensolaris.org } 22359860Sgdamore@opensolaris.org 22369860Sgdamore@opensolaris.org /* allocate receive descriptor array of size dnetp->max_rx_desc */ 22379860Sgdamore@opensolaris.org if (dnetp->rx_desc == NULL) { 22389860Sgdamore@opensolaris.org int ndesc; 22399860Sgdamore@opensolaris.org 22409860Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(dnetp->dma_handle, 22419860Sgdamore@opensolaris.org sizeof (struct rx_desc_type) * dnetp->max_rx_desc, 22429860Sgdamore@opensolaris.org &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 22439860Sgdamore@opensolaris.org (caddr_t *)&dnetp->rx_desc, &len, 22449860Sgdamore@opensolaris.org &dnetp->rx_desc_acchdl) != DDI_SUCCESS) 22459860Sgdamore@opensolaris.org return (FAILURE); 22469860Sgdamore@opensolaris.org 22479860Sgdamore@opensolaris.org if (ddi_dma_addr_bind_handle(dnetp->dma_handle, 22489860Sgdamore@opensolaris.org NULL, (caddr_t)dnetp->rx_desc, 22499860Sgdamore@opensolaris.org sizeof (struct rx_desc_type) * dnetp->max_rx_desc, 22509860Sgdamore@opensolaris.org DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 22519860Sgdamore@opensolaris.org NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 22529860Sgdamore@opensolaris.org return (FAILURE); 22539860Sgdamore@opensolaris.org 22549860Sgdamore@opensolaris.org dnetp->rx_desc_paddr = cookie.dmac_address; 22559860Sgdamore@opensolaris.org bzero(dnetp->rx_desc, len); 22569860Sgdamore@opensolaris.org dnetp->nrecv_desc = dnetp->max_rx_desc; 22579860Sgdamore@opensolaris.org 22589860Sgdamore@opensolaris.org dnetp->rx_buf_vaddr = 22599860Sgdamore@opensolaris.org kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t), 22609860Sgdamore@opensolaris.org KM_SLEEP); 22619860Sgdamore@opensolaris.org dnetp->rx_buf_paddr = 22629860Sgdamore@opensolaris.org kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t), 22639860Sgdamore@opensolaris.org KM_SLEEP); 22649860Sgdamore@opensolaris.org /* 22659860Sgdamore@opensolaris.org * Allocate or add to the pool of receive buffers. The pool 22669860Sgdamore@opensolaris.org * is shared among all instances of dnet. 22679860Sgdamore@opensolaris.org * 22689860Sgdamore@opensolaris.org * XXX NEEDSWORK 22699860Sgdamore@opensolaris.org * 22709860Sgdamore@opensolaris.org * We arbitrarily allocate twice as many receive buffers as 22719860Sgdamore@opensolaris.org * receive descriptors because we use the buffers for streams 22729860Sgdamore@opensolaris.org * messages to pass the packets up the stream. We should 22739860Sgdamore@opensolaris.org * instead have initialized constants reflecting 22749860Sgdamore@opensolaris.org * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also 22759860Sgdamore@opensolaris.org * probably have a total maximum for the free pool, so that we 22769860Sgdamore@opensolaris.org * don't get out of hand when someone puts in an 8-port board. 22779860Sgdamore@opensolaris.org * The maximum for the entire pool should be the total number 22789860Sgdamore@opensolaris.org * of descriptors for all attached instances together, plus the 22799860Sgdamore@opensolaris.org * total maximum for the free pool. This maximum would only be 22809860Sgdamore@opensolaris.org * reached after some number of instances allocate buffers: 22819860Sgdamore@opensolaris.org * each instance would add (max_rx_buf-max_rx_desc) to the free 22829860Sgdamore@opensolaris.org * pool. 22839860Sgdamore@opensolaris.org */ 22849860Sgdamore@opensolaris.org ndesc = dnetp->max_rx_desc - nrecv_desc_old; 22859860Sgdamore@opensolaris.org if ((ndesc > 0) && 22869860Sgdamore@opensolaris.org (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0)) 22879860Sgdamore@opensolaris.org return (FAILURE); 22889860Sgdamore@opensolaris.org 22899860Sgdamore@opensolaris.org for (i = 0; i < dnetp->max_rx_desc; i++) { 22909860Sgdamore@opensolaris.org struct rbuf_list *rp; 22919860Sgdamore@opensolaris.org 22929860Sgdamore@opensolaris.org rp = dnet_rbuf_alloc(dnetp->devinfo, 1); 22939860Sgdamore@opensolaris.org if (rp == NULL) 22949860Sgdamore@opensolaris.org return (FAILURE); 22959860Sgdamore@opensolaris.org dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr; 22969860Sgdamore@opensolaris.org dnetp->rx_buf_paddr[i] = rp->rbuf_paddr; 22979860Sgdamore@opensolaris.org } 22989860Sgdamore@opensolaris.org } 22999860Sgdamore@opensolaris.org 23009860Sgdamore@opensolaris.org return (SUCCESS); 23019860Sgdamore@opensolaris.org } 23029860Sgdamore@opensolaris.org /* 23039860Sgdamore@opensolaris.org * free descriptors/buffers allocated for this device instance. This routine 23049860Sgdamore@opensolaris.org * should only be called while the device is reset. 23059860Sgdamore@opensolaris.org */ 23069860Sgdamore@opensolaris.org static void 2307*10340Sstallion@opensolaris.org dnet_free_bufs(struct dnetinstance *dnetp) 23089860Sgdamore@opensolaris.org { 23099860Sgdamore@opensolaris.org int i; 23109860Sgdamore@opensolaris.org /* free up any xmit descriptors/buffers */ 23119860Sgdamore@opensolaris.org if (dnetp->tx_desc != NULL) { 23129860Sgdamore@opensolaris.org ddi_dma_mem_free(&dnetp->tx_desc_acchdl); 23139860Sgdamore@opensolaris.org dnetp->tx_desc = NULL; 23149860Sgdamore@opensolaris.org /* we use streams buffers for DMA in xmit process */ 23159860Sgdamore@opensolaris.org if (dnetp->tx_msgbufp != NULL) { 23169860Sgdamore@opensolaris.org /* free up any streams message buffers unclaimed */ 23179860Sgdamore@opensolaris.org for (i = 0; i < dnetp->nxmit_desc; i++) { 23189860Sgdamore@opensolaris.org if (dnetp->tx_msgbufp[i] != NULL) { 23199860Sgdamore@opensolaris.org freemsg(dnetp->tx_msgbufp[i]); 23209860Sgdamore@opensolaris.org } 23219860Sgdamore@opensolaris.org } 23229860Sgdamore@opensolaris.org kmem_free(dnetp->tx_msgbufp, 23239860Sgdamore@opensolaris.org dnetp->nxmit_desc * sizeof (mblk_t **)); 23249860Sgdamore@opensolaris.org dnetp->tx_msgbufp = NULL; 23259860Sgdamore@opensolaris.org } 23269860Sgdamore@opensolaris.org dnetp->nxmit_desc = 0; 23279860Sgdamore@opensolaris.org } 23289860Sgdamore@opensolaris.org 23299860Sgdamore@opensolaris.org /* free up any receive descriptors/buffers */ 23309860Sgdamore@opensolaris.org if (dnetp->rx_desc != NULL) { 23319860Sgdamore@opensolaris.org ddi_dma_mem_free(&dnetp->rx_desc_acchdl); 23329860Sgdamore@opensolaris.org dnetp->rx_desc = NULL; 23339860Sgdamore@opensolaris.org if (dnetp->rx_buf_vaddr != NULL) { 23349860Sgdamore@opensolaris.org /* free up the attached rbufs if any */ 23359860Sgdamore@opensolaris.org for (i = 0; i < dnetp->nrecv_desc; i++) { 23369860Sgdamore@opensolaris.org if (dnetp->rx_buf_vaddr[i]) 23379860Sgdamore@opensolaris.org dnet_rbuf_free( 23389860Sgdamore@opensolaris.org (caddr_t)dnetp->rx_buf_vaddr[i]); 23399860Sgdamore@opensolaris.org } 23409860Sgdamore@opensolaris.org kmem_free(dnetp->rx_buf_vaddr, 23419860Sgdamore@opensolaris.org dnetp->nrecv_desc * sizeof (caddr_t)); 23429860Sgdamore@opensolaris.org kmem_free(dnetp->rx_buf_paddr, 23439860Sgdamore@opensolaris.org dnetp->nrecv_desc * sizeof (uint32_t)); 23449860Sgdamore@opensolaris.org dnetp->rx_buf_vaddr = NULL; 23459860Sgdamore@opensolaris.org dnetp->rx_buf_paddr = NULL; 23469860Sgdamore@opensolaris.org } 23479860Sgdamore@opensolaris.org dnetp->nrecv_desc = 0; 23489860Sgdamore@opensolaris.org } 23499860Sgdamore@opensolaris.org 23509860Sgdamore@opensolaris.org if (dnetp->setup_buf_vaddr != NULL) { 23519860Sgdamore@opensolaris.org ddi_dma_mem_free(&dnetp->setup_buf_acchdl); 23529860Sgdamore@opensolaris.org dnetp->setup_buf_vaddr = NULL; 23539860Sgdamore@opensolaris.org } 23549860Sgdamore@opensolaris.org 23559860Sgdamore@opensolaris.org if (dnetp->dma_handle != NULL) { 23569860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle); 23579860Sgdamore@opensolaris.org ddi_dma_free_handle(&dnetp->dma_handle); 23589860Sgdamore@opensolaris.org dnetp->dma_handle = NULL; 23599860Sgdamore@opensolaris.org } 23609860Sgdamore@opensolaris.org 23619860Sgdamore@opensolaris.org if (dnetp->dma_handle_tx != NULL) { 23629860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 23639860Sgdamore@opensolaris.org ddi_dma_free_handle(&dnetp->dma_handle_tx); 23649860Sgdamore@opensolaris.org dnetp->dma_handle_tx = NULL; 23659860Sgdamore@opensolaris.org } 23669860Sgdamore@opensolaris.org 23679860Sgdamore@opensolaris.org if (dnetp->dma_handle_txdesc != NULL) { 23689860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc); 23699860Sgdamore@opensolaris.org ddi_dma_free_handle(&dnetp->dma_handle_txdesc); 23709860Sgdamore@opensolaris.org dnetp->dma_handle_txdesc = NULL; 23719860Sgdamore@opensolaris.org } 23729860Sgdamore@opensolaris.org 23739860Sgdamore@opensolaris.org if (dnetp->dma_handle_setbuf != NULL) { 23749860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf); 23759860Sgdamore@opensolaris.org ddi_dma_free_handle(&dnetp->dma_handle_setbuf); 23769860Sgdamore@opensolaris.org dnetp->dma_handle_setbuf = NULL; 23779860Sgdamore@opensolaris.org } 23789860Sgdamore@opensolaris.org 23799860Sgdamore@opensolaris.org } 23809860Sgdamore@opensolaris.org 23819860Sgdamore@opensolaris.org /* 23829860Sgdamore@opensolaris.org * Initialize transmit and receive descriptors. 23839860Sgdamore@opensolaris.org */ 23849860Sgdamore@opensolaris.org static void 2385*10340Sstallion@opensolaris.org dnet_init_txrx_bufs(struct dnetinstance *dnetp) 23869860Sgdamore@opensolaris.org { 23879860Sgdamore@opensolaris.org int i; 23889860Sgdamore@opensolaris.org 23899860Sgdamore@opensolaris.org /* 23909860Sgdamore@opensolaris.org * Initilize all the Tx descriptors 23919860Sgdamore@opensolaris.org */ 23929860Sgdamore@opensolaris.org for (i = 0; i < dnetp->nxmit_desc; i++) { 23939860Sgdamore@opensolaris.org /* 23949860Sgdamore@opensolaris.org * We may be resetting the device due to errors, 23959860Sgdamore@opensolaris.org * so free up any streams message buffer unclaimed. 23969860Sgdamore@opensolaris.org */ 23979860Sgdamore@opensolaris.org if (dnetp->tx_msgbufp[i] != NULL) { 23989860Sgdamore@opensolaris.org freemsg(dnetp->tx_msgbufp[i]); 23999860Sgdamore@opensolaris.org dnetp->tx_msgbufp[i] = NULL; 24009860Sgdamore@opensolaris.org } 24019860Sgdamore@opensolaris.org *(uint32_t *)&dnetp->tx_desc[i].desc0 = 0; 24029860Sgdamore@opensolaris.org *(uint32_t *)&dnetp->tx_desc[i].desc1 = 0; 24039860Sgdamore@opensolaris.org dnetp->tx_desc[i].buffer1 = 0; 24049860Sgdamore@opensolaris.org dnetp->tx_desc[i].buffer2 = 0; 24059860Sgdamore@opensolaris.org } 24069860Sgdamore@opensolaris.org dnetp->tx_desc[i - 1].desc1.end_of_ring = 1; 24079860Sgdamore@opensolaris.org 24089860Sgdamore@opensolaris.org /* 24099860Sgdamore@opensolaris.org * Initialize the Rx descriptors 24109860Sgdamore@opensolaris.org */ 24119860Sgdamore@opensolaris.org for (i = 0; i < dnetp->nrecv_desc; i++) { 24129860Sgdamore@opensolaris.org uint32_t end_paddr; 24139860Sgdamore@opensolaris.org *(uint32_t *)&dnetp->rx_desc[i].desc0 = 0; 24149860Sgdamore@opensolaris.org *(uint32_t *)&dnetp->rx_desc[i].desc1 = 0; 24159860Sgdamore@opensolaris.org dnetp->rx_desc[i].desc0.own = 1; 24169860Sgdamore@opensolaris.org dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size; 24179860Sgdamore@opensolaris.org dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i]; 24189860Sgdamore@opensolaris.org dnetp->rx_desc[i].buffer2 = 0; 24199860Sgdamore@opensolaris.org end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1; 24209860Sgdamore@opensolaris.org 24219860Sgdamore@opensolaris.org if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) != 24229860Sgdamore@opensolaris.org (end_paddr & ~dnetp->pgmask)) { 24239860Sgdamore@opensolaris.org /* discontiguous */ 24249860Sgdamore@opensolaris.org dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask; 24259860Sgdamore@opensolaris.org dnetp->rx_desc[i].desc1.buffer_size2 = 24269860Sgdamore@opensolaris.org (end_paddr & dnetp->pgmask) + 1; 24279860Sgdamore@opensolaris.org dnetp->rx_desc[i].desc1.buffer_size1 = 24289860Sgdamore@opensolaris.org rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2; 24299860Sgdamore@opensolaris.org } 24309860Sgdamore@opensolaris.org } 24319860Sgdamore@opensolaris.org dnetp->rx_desc[i - 1].desc1.end_of_ring = 1; 24329860Sgdamore@opensolaris.org } 24339860Sgdamore@opensolaris.org 24349860Sgdamore@opensolaris.org static int 2435*10340Sstallion@opensolaris.org alloc_descriptor(struct dnetinstance *dnetp) 24369860Sgdamore@opensolaris.org { 24379860Sgdamore@opensolaris.org int index; 24389860Sgdamore@opensolaris.org struct tx_desc_type *ring = dnetp->tx_desc; 24399860Sgdamore@opensolaris.org 24409860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 24419860Sgdamore@opensolaris.org alloctop: 24429860Sgdamore@opensolaris.org mutex_enter(&dnetp->txlock); 24439860Sgdamore@opensolaris.org index = dnetp->tx_current_desc; 24449860Sgdamore@opensolaris.org 2445*10340Sstallion@opensolaris.org dnet_reclaim_Tx_desc(dnetp); 24469860Sgdamore@opensolaris.org 24479860Sgdamore@opensolaris.org /* we do have free descriptors, right? */ 24489860Sgdamore@opensolaris.org if (dnetp->free_desc <= 0) { 24499860Sgdamore@opensolaris.org #ifdef DNETDEBUG 24509860Sgdamore@opensolaris.org if (dnetdebug & DNETRECV) 24519860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "dnet: Ring buffer is full"); 24529860Sgdamore@opensolaris.org #endif 24539860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 24549860Sgdamore@opensolaris.org return (FAILURE); 24559860Sgdamore@opensolaris.org } 24569860Sgdamore@opensolaris.org 24579860Sgdamore@opensolaris.org /* sanity, make sure the next descriptor is free for use (should be) */ 24589860Sgdamore@opensolaris.org if (ring[index].desc0.own) { 24599860Sgdamore@opensolaris.org #ifdef DNETDEBUG 24609860Sgdamore@opensolaris.org if (dnetdebug & DNETRECV) 24619860Sgdamore@opensolaris.org cmn_err(CE_WARN, 24629860Sgdamore@opensolaris.org "dnet: next descriptor is not free for use"); 24639860Sgdamore@opensolaris.org #endif 24649860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 24659860Sgdamore@opensolaris.org return (FAILURE); 24669860Sgdamore@opensolaris.org } 24679860Sgdamore@opensolaris.org if (dnetp->need_saddr) { 24689860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 24699860Sgdamore@opensolaris.org /* XXX function return value ignored */ 24709860Sgdamore@opensolaris.org if (!dnetp->suspended) 2471*10340Sstallion@opensolaris.org (void) dnet_set_addr(dnetp); 24729860Sgdamore@opensolaris.org goto alloctop; 24739860Sgdamore@opensolaris.org } 24749860Sgdamore@opensolaris.org 24759860Sgdamore@opensolaris.org *(uint32_t *)&ring[index].desc0 = 0; /* init descs */ 24769860Sgdamore@opensolaris.org *(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING; 24779860Sgdamore@opensolaris.org 24789860Sgdamore@opensolaris.org /* hardware will own this descriptor when poll activated */ 24799860Sgdamore@opensolaris.org dnetp->free_desc--; 24809860Sgdamore@opensolaris.org 24819860Sgdamore@opensolaris.org /* point to next free descriptor to be used */ 24829860Sgdamore@opensolaris.org dnetp->tx_current_desc = NextTXIndex(index); 24839860Sgdamore@opensolaris.org 24849860Sgdamore@opensolaris.org #ifdef DNET_NOISY 24859860Sgdamore@opensolaris.org cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x", 24869860Sgdamore@opensolaris.org dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc); 24879860Sgdamore@opensolaris.org #endif 24889860Sgdamore@opensolaris.org mutex_exit(&dnetp->txlock); 24899860Sgdamore@opensolaris.org return (SUCCESS); 24909860Sgdamore@opensolaris.org } 24919860Sgdamore@opensolaris.org 24929860Sgdamore@opensolaris.org /* 24939860Sgdamore@opensolaris.org * dnet_reclaim_Tx_desc() - called with txlock held. 24949860Sgdamore@opensolaris.org */ 24959860Sgdamore@opensolaris.org static void 2496*10340Sstallion@opensolaris.org dnet_reclaim_Tx_desc(struct dnetinstance *dnetp) 24979860Sgdamore@opensolaris.org { 24989860Sgdamore@opensolaris.org struct tx_desc_type *desc = dnetp->tx_desc; 24999860Sgdamore@opensolaris.org int index; 25009860Sgdamore@opensolaris.org 25019860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->txlock)); 25029860Sgdamore@opensolaris.org 25039860Sgdamore@opensolaris.org index = dnetp->transmitted_desc; 25049860Sgdamore@opensolaris.org while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) && 25059860Sgdamore@opensolaris.org !(desc[index].desc0.own)) { 25069860Sgdamore@opensolaris.org /* 25079860Sgdamore@opensolaris.org * Check for Tx Error that gets set 25089860Sgdamore@opensolaris.org * in the last desc. 25099860Sgdamore@opensolaris.org */ 25109860Sgdamore@opensolaris.org if (desc[index].desc1.setup_packet == 0 && 25119860Sgdamore@opensolaris.org desc[index].desc1.last_desc && 25129860Sgdamore@opensolaris.org desc[index].desc0.err_summary) 2513*10340Sstallion@opensolaris.org update_tx_stats(dnetp, index); 25149860Sgdamore@opensolaris.org 25159860Sgdamore@opensolaris.org /* 25169860Sgdamore@opensolaris.org * If we have used the streams message buffer for this 25179860Sgdamore@opensolaris.org * descriptor then free up the message now. 25189860Sgdamore@opensolaris.org */ 25199860Sgdamore@opensolaris.org if (dnetp->tx_msgbufp[index] != NULL) { 25209860Sgdamore@opensolaris.org freemsg(dnetp->tx_msgbufp[index]); 25219860Sgdamore@opensolaris.org dnetp->tx_msgbufp[index] = NULL; 25229860Sgdamore@opensolaris.org } 25239860Sgdamore@opensolaris.org dnetp->free_desc++; 25249860Sgdamore@opensolaris.org index = (index+1) % dnetp->max_tx_desc; 25259860Sgdamore@opensolaris.org } 25269860Sgdamore@opensolaris.org 25279860Sgdamore@opensolaris.org dnetp->transmitted_desc = index; 25289860Sgdamore@opensolaris.org } 25299860Sgdamore@opensolaris.org 25309860Sgdamore@opensolaris.org /* 25319860Sgdamore@opensolaris.org * Receive buffer allocation/freeing routines. 25329860Sgdamore@opensolaris.org * 25339860Sgdamore@opensolaris.org * There is a common pool of receive buffers shared by all dnet instances. 25349860Sgdamore@opensolaris.org * 25359860Sgdamore@opensolaris.org * XXX NEEDSWORK 25369860Sgdamore@opensolaris.org * 25379860Sgdamore@opensolaris.org * We arbitrarily allocate twice as many receive buffers as 25389860Sgdamore@opensolaris.org * receive descriptors because we use the buffers for streams 25399860Sgdamore@opensolaris.org * messages to pass the packets up the stream. We should 25409860Sgdamore@opensolaris.org * instead have initialized constants reflecting 25419860Sgdamore@opensolaris.org * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also 25429860Sgdamore@opensolaris.org * probably have a total maximum for the free pool, so that we 25439860Sgdamore@opensolaris.org * don't get out of hand when someone puts in an 8-port board. 25449860Sgdamore@opensolaris.org * The maximum for the entire pool should be the total number 25459860Sgdamore@opensolaris.org * of descriptors for all attached instances together, plus the 25469860Sgdamore@opensolaris.org * total maximum for the free pool. This maximum would only be 25479860Sgdamore@opensolaris.org * reached after some number of instances allocate buffers: 25489860Sgdamore@opensolaris.org * each instance would add (max_rx_buf-max_rx_desc) to the free 25499860Sgdamore@opensolaris.org * pool. 25509860Sgdamore@opensolaris.org */ 25519860Sgdamore@opensolaris.org 25529860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_usedlist_head; 25539860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_freelist_head; 25549860Sgdamore@opensolaris.org static struct rbuf_list *rbuf_usedlist_end; /* last buffer allocated */ 25559860Sgdamore@opensolaris.org 25569860Sgdamore@opensolaris.org static int rbuf_freebufs; /* no. of free buffers in the pool */ 25579860Sgdamore@opensolaris.org static int rbuf_pool_size; /* total no. of buffers in the pool */ 25589860Sgdamore@opensolaris.org 25599860Sgdamore@opensolaris.org /* initialize/add 'nbufs' buffers to the rbuf pool */ 25609860Sgdamore@opensolaris.org /* ARGSUSED */ 25619860Sgdamore@opensolaris.org static int 25629860Sgdamore@opensolaris.org dnet_rbuf_init(dev_info_t *dip, int nbufs) 25639860Sgdamore@opensolaris.org { 25649860Sgdamore@opensolaris.org int i; 25659860Sgdamore@opensolaris.org struct rbuf_list *rp; 25669860Sgdamore@opensolaris.org ddi_dma_cookie_t cookie; 25679860Sgdamore@opensolaris.org uint_t ncookies; 25689860Sgdamore@opensolaris.org size_t len; 25699860Sgdamore@opensolaris.org 25709860Sgdamore@opensolaris.org mutex_enter(&dnet_rbuf_lock); 25719860Sgdamore@opensolaris.org 25729860Sgdamore@opensolaris.org /* allocate buffers and add them to the pool */ 25739860Sgdamore@opensolaris.org for (i = 0; i < nbufs; i++) { 25749860Sgdamore@opensolaris.org /* allocate rbuf_list element */ 25759860Sgdamore@opensolaris.org rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP); 25769860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP, 25779860Sgdamore@opensolaris.org 0, &rp->rbuf_dmahdl) != DDI_SUCCESS) 25789860Sgdamore@opensolaris.org goto fail_kfree; 25799860Sgdamore@opensolaris.org 25809860Sgdamore@opensolaris.org /* allocate dma memory for the buffer */ 25819860Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr, 25829860Sgdamore@opensolaris.org DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 25839860Sgdamore@opensolaris.org &rp->rbuf_vaddr, &len, 25849860Sgdamore@opensolaris.org &rp->rbuf_acchdl) != DDI_SUCCESS) 25859860Sgdamore@opensolaris.org goto fail_freehdl; 25869860Sgdamore@opensolaris.org 25879860Sgdamore@opensolaris.org if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL, 25889860Sgdamore@opensolaris.org rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING, 25899860Sgdamore@opensolaris.org DDI_DMA_SLEEP, NULL, &cookie, 25909860Sgdamore@opensolaris.org &ncookies) != DDI_DMA_MAPPED) 25919860Sgdamore@opensolaris.org goto fail_free; 25929860Sgdamore@opensolaris.org 25939860Sgdamore@opensolaris.org if (ncookies > 2) 25949860Sgdamore@opensolaris.org goto fail_unbind; 25959860Sgdamore@opensolaris.org if (ncookies == 1) { 25969860Sgdamore@opensolaris.org rp->rbuf_endpaddr = 25979860Sgdamore@opensolaris.org cookie.dmac_address + rx_buf_size - 1; 25989860Sgdamore@opensolaris.org } else { 25999860Sgdamore@opensolaris.org ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie); 26009860Sgdamore@opensolaris.org rp->rbuf_endpaddr = 26019860Sgdamore@opensolaris.org cookie.dmac_address + cookie.dmac_size - 1; 26029860Sgdamore@opensolaris.org } 26039860Sgdamore@opensolaris.org rp->rbuf_paddr = cookie.dmac_address; 26049860Sgdamore@opensolaris.org 26059860Sgdamore@opensolaris.org rp->rbuf_next = rbuf_freelist_head; 26069860Sgdamore@opensolaris.org rbuf_freelist_head = rp; 26079860Sgdamore@opensolaris.org rbuf_pool_size++; 26089860Sgdamore@opensolaris.org rbuf_freebufs++; 26099860Sgdamore@opensolaris.org } 26109860Sgdamore@opensolaris.org 26119860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 26129860Sgdamore@opensolaris.org return (0); 26139860Sgdamore@opensolaris.org fail_unbind: 26149860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 26159860Sgdamore@opensolaris.org fail_free: 26169860Sgdamore@opensolaris.org ddi_dma_mem_free(&rp->rbuf_acchdl); 26179860Sgdamore@opensolaris.org fail_freehdl: 26189860Sgdamore@opensolaris.org ddi_dma_free_handle(&rp->rbuf_dmahdl); 26199860Sgdamore@opensolaris.org fail_kfree: 26209860Sgdamore@opensolaris.org kmem_free(rp, sizeof (struct rbuf_list)); 26219860Sgdamore@opensolaris.org 26229860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 26239860Sgdamore@opensolaris.org return (-1); 26249860Sgdamore@opensolaris.org } 26259860Sgdamore@opensolaris.org 26269860Sgdamore@opensolaris.org /* 26279860Sgdamore@opensolaris.org * Try to free up all the rbufs in the pool. Returns 0 if it frees up all 26289860Sgdamore@opensolaris.org * buffers. The buffers in the used list are considered busy so these 26299860Sgdamore@opensolaris.org * buffers are not freed. 26309860Sgdamore@opensolaris.org */ 26319860Sgdamore@opensolaris.org static int 26329860Sgdamore@opensolaris.org dnet_rbuf_destroy() 26339860Sgdamore@opensolaris.org { 26349860Sgdamore@opensolaris.org struct rbuf_list *rp, *next; 26359860Sgdamore@opensolaris.org 26369860Sgdamore@opensolaris.org mutex_enter(&dnet_rbuf_lock); 26379860Sgdamore@opensolaris.org 26389860Sgdamore@opensolaris.org for (rp = rbuf_freelist_head; rp; rp = next) { 26399860Sgdamore@opensolaris.org next = rp->rbuf_next; 26409860Sgdamore@opensolaris.org ddi_dma_mem_free(&rp->rbuf_acchdl); 26419860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 26429860Sgdamore@opensolaris.org kmem_free(rp, sizeof (struct rbuf_list)); 26439860Sgdamore@opensolaris.org rbuf_pool_size--; 26449860Sgdamore@opensolaris.org rbuf_freebufs--; 26459860Sgdamore@opensolaris.org } 26469860Sgdamore@opensolaris.org rbuf_freelist_head = NULL; 26479860Sgdamore@opensolaris.org 26489860Sgdamore@opensolaris.org if (rbuf_pool_size) { /* pool is still not empty */ 26499860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 26509860Sgdamore@opensolaris.org return (-1); 26519860Sgdamore@opensolaris.org } 26529860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 26539860Sgdamore@opensolaris.org return (0); 26549860Sgdamore@opensolaris.org } 26559860Sgdamore@opensolaris.org static struct rbuf_list * 26569860Sgdamore@opensolaris.org dnet_rbuf_alloc(dev_info_t *dip, int cansleep) 26579860Sgdamore@opensolaris.org { 26589860Sgdamore@opensolaris.org struct rbuf_list *rp; 26599860Sgdamore@opensolaris.org size_t len; 26609860Sgdamore@opensolaris.org ddi_dma_cookie_t cookie; 26619860Sgdamore@opensolaris.org uint_t ncookies; 26629860Sgdamore@opensolaris.org 26639860Sgdamore@opensolaris.org mutex_enter(&dnet_rbuf_lock); 26649860Sgdamore@opensolaris.org 26659860Sgdamore@opensolaris.org if (rbuf_freelist_head == NULL) { 26669860Sgdamore@opensolaris.org 26679860Sgdamore@opensolaris.org if (!cansleep) { 26689860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 26699860Sgdamore@opensolaris.org return (NULL); 26709860Sgdamore@opensolaris.org } 26719860Sgdamore@opensolaris.org 26729860Sgdamore@opensolaris.org /* allocate rbuf_list element */ 26739860Sgdamore@opensolaris.org rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP); 26749860Sgdamore@opensolaris.org if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP, 26759860Sgdamore@opensolaris.org 0, &rp->rbuf_dmahdl) != DDI_SUCCESS) 26769860Sgdamore@opensolaris.org goto fail_kfree; 26779860Sgdamore@opensolaris.org 26789860Sgdamore@opensolaris.org /* allocate dma memory for the buffer */ 26799860Sgdamore@opensolaris.org if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr, 26809860Sgdamore@opensolaris.org DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 26819860Sgdamore@opensolaris.org &rp->rbuf_vaddr, &len, 26829860Sgdamore@opensolaris.org &rp->rbuf_acchdl) != DDI_SUCCESS) 26839860Sgdamore@opensolaris.org goto fail_freehdl; 26849860Sgdamore@opensolaris.org 26859860Sgdamore@opensolaris.org if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL, 26869860Sgdamore@opensolaris.org rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING, 26879860Sgdamore@opensolaris.org DDI_DMA_SLEEP, NULL, &cookie, 26889860Sgdamore@opensolaris.org &ncookies) != DDI_DMA_MAPPED) 26899860Sgdamore@opensolaris.org goto fail_free; 26909860Sgdamore@opensolaris.org 26919860Sgdamore@opensolaris.org if (ncookies > 2) 26929860Sgdamore@opensolaris.org goto fail_unbind; 26939860Sgdamore@opensolaris.org if (ncookies == 1) { 26949860Sgdamore@opensolaris.org rp->rbuf_endpaddr = 26959860Sgdamore@opensolaris.org cookie.dmac_address + rx_buf_size - 1; 26969860Sgdamore@opensolaris.org } else { 26979860Sgdamore@opensolaris.org ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie); 26989860Sgdamore@opensolaris.org rp->rbuf_endpaddr = 26999860Sgdamore@opensolaris.org cookie.dmac_address + cookie.dmac_size - 1; 27009860Sgdamore@opensolaris.org } 27019860Sgdamore@opensolaris.org rp->rbuf_paddr = cookie.dmac_address; 27029860Sgdamore@opensolaris.org 27039860Sgdamore@opensolaris.org rbuf_freelist_head = rp; 27049860Sgdamore@opensolaris.org rbuf_pool_size++; 27059860Sgdamore@opensolaris.org rbuf_freebufs++; 27069860Sgdamore@opensolaris.org } 27079860Sgdamore@opensolaris.org 27089860Sgdamore@opensolaris.org /* take the buffer from the head of the free list */ 27099860Sgdamore@opensolaris.org rp = rbuf_freelist_head; 27109860Sgdamore@opensolaris.org rbuf_freelist_head = rbuf_freelist_head->rbuf_next; 27119860Sgdamore@opensolaris.org 27129860Sgdamore@opensolaris.org /* update the used list; put the entry at the end */ 27139860Sgdamore@opensolaris.org if (rbuf_usedlist_head == NULL) 27149860Sgdamore@opensolaris.org rbuf_usedlist_head = rp; 27159860Sgdamore@opensolaris.org else 27169860Sgdamore@opensolaris.org rbuf_usedlist_end->rbuf_next = rp; 27179860Sgdamore@opensolaris.org rp->rbuf_next = NULL; 27189860Sgdamore@opensolaris.org rbuf_usedlist_end = rp; 27199860Sgdamore@opensolaris.org rbuf_freebufs--; 27209860Sgdamore@opensolaris.org 27219860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 27229860Sgdamore@opensolaris.org 27239860Sgdamore@opensolaris.org return (rp); 27249860Sgdamore@opensolaris.org fail_unbind: 27259860Sgdamore@opensolaris.org (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 27269860Sgdamore@opensolaris.org fail_free: 27279860Sgdamore@opensolaris.org ddi_dma_mem_free(&rp->rbuf_acchdl); 27289860Sgdamore@opensolaris.org fail_freehdl: 27299860Sgdamore@opensolaris.org ddi_dma_free_handle(&rp->rbuf_dmahdl); 27309860Sgdamore@opensolaris.org fail_kfree: 27319860Sgdamore@opensolaris.org kmem_free(rp, sizeof (struct rbuf_list)); 27329860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 27339860Sgdamore@opensolaris.org return (NULL); 27349860Sgdamore@opensolaris.org } 27359860Sgdamore@opensolaris.org 27369860Sgdamore@opensolaris.org static void 27379860Sgdamore@opensolaris.org dnet_rbuf_free(caddr_t vaddr) 27389860Sgdamore@opensolaris.org { 27399860Sgdamore@opensolaris.org struct rbuf_list *rp, *prev; 27409860Sgdamore@opensolaris.org 27419860Sgdamore@opensolaris.org ASSERT(vaddr != NULL); 27429860Sgdamore@opensolaris.org ASSERT(rbuf_usedlist_head != NULL); 27439860Sgdamore@opensolaris.org 27449860Sgdamore@opensolaris.org mutex_enter(&dnet_rbuf_lock); 27459860Sgdamore@opensolaris.org 27469860Sgdamore@opensolaris.org /* find the entry in the used list */ 27479860Sgdamore@opensolaris.org for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) { 27489860Sgdamore@opensolaris.org if (rp->rbuf_vaddr == vaddr) 27499860Sgdamore@opensolaris.org break; 27509860Sgdamore@opensolaris.org prev = rp; 27519860Sgdamore@opensolaris.org } 27529860Sgdamore@opensolaris.org 27539860Sgdamore@opensolaris.org if (rp == NULL) { 27549860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p", 27559860Sgdamore@opensolaris.org (void *)vaddr); 27569860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 27579860Sgdamore@opensolaris.org return; 27589860Sgdamore@opensolaris.org } 27599860Sgdamore@opensolaris.org 27609860Sgdamore@opensolaris.org /* update the used list and put the buffer back in the free list */ 27619860Sgdamore@opensolaris.org if (rbuf_usedlist_head != rp) { 27629860Sgdamore@opensolaris.org prev->rbuf_next = rp->rbuf_next; 27639860Sgdamore@opensolaris.org if (rbuf_usedlist_end == rp) 27649860Sgdamore@opensolaris.org rbuf_usedlist_end = prev; 27659860Sgdamore@opensolaris.org } else { 27669860Sgdamore@opensolaris.org rbuf_usedlist_head = rp->rbuf_next; 27679860Sgdamore@opensolaris.org if (rbuf_usedlist_end == rp) 27689860Sgdamore@opensolaris.org rbuf_usedlist_end = NULL; 27699860Sgdamore@opensolaris.org } 27709860Sgdamore@opensolaris.org rp->rbuf_next = rbuf_freelist_head; 27719860Sgdamore@opensolaris.org rbuf_freelist_head = rp; 27729860Sgdamore@opensolaris.org rbuf_freebufs++; 27739860Sgdamore@opensolaris.org 27749860Sgdamore@opensolaris.org mutex_exit(&dnet_rbuf_lock); 27759860Sgdamore@opensolaris.org } 27769860Sgdamore@opensolaris.org 27779860Sgdamore@opensolaris.org /* 27789860Sgdamore@opensolaris.org * Free the receive buffer used in a stream's message block allocated 27799860Sgdamore@opensolaris.org * thru desballoc(). 27809860Sgdamore@opensolaris.org */ 27819860Sgdamore@opensolaris.org static void 27829860Sgdamore@opensolaris.org dnet_freemsg_buf(struct free_ptr *frp) 27839860Sgdamore@opensolaris.org { 27849860Sgdamore@opensolaris.org dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */ 27859860Sgdamore@opensolaris.org kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */ 27869860Sgdamore@opensolaris.org } 27879860Sgdamore@opensolaris.org 27889860Sgdamore@opensolaris.org /* 27899860Sgdamore@opensolaris.org * ========== SROM Read Routines ========== 27909860Sgdamore@opensolaris.org */ 27919860Sgdamore@opensolaris.org 27929860Sgdamore@opensolaris.org /* 27939860Sgdamore@opensolaris.org * The following code gets the SROM information, either by reading it 27949860Sgdamore@opensolaris.org * from the device or, failing that, by reading a property. 27959860Sgdamore@opensolaris.org */ 27969860Sgdamore@opensolaris.org static int 27979860Sgdamore@opensolaris.org dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle, 27989860Sgdamore@opensolaris.org caddr_t io_reg, uchar_t *vi, int maxlen) 27999860Sgdamore@opensolaris.org { 28009860Sgdamore@opensolaris.org int all_ones, zerocheck, i; 28019860Sgdamore@opensolaris.org 28029860Sgdamore@opensolaris.org /* 28039860Sgdamore@opensolaris.org * Load SROM into vendor_info 28049860Sgdamore@opensolaris.org */ 28059860Sgdamore@opensolaris.org if (board_type == DEVICE_ID_21040) 28069860Sgdamore@opensolaris.org dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen); 28079860Sgdamore@opensolaris.org else 28089860Sgdamore@opensolaris.org /* 21041/21140 serial rom */ 28099860Sgdamore@opensolaris.org dnet_read21140srom(io_handle, io_reg, vi, maxlen); 28109860Sgdamore@opensolaris.org /* 28119860Sgdamore@opensolaris.org * If the dumpsrom property is present in the conf file, print 28129860Sgdamore@opensolaris.org * the contents of the SROM to the console 28139860Sgdamore@opensolaris.org */ 28149860Sgdamore@opensolaris.org if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 28159860Sgdamore@opensolaris.org "dumpsrom", 0)) 28169860Sgdamore@opensolaris.org dnet_dumpbin("SROM", vi, 1, maxlen); 28179860Sgdamore@opensolaris.org 28189860Sgdamore@opensolaris.org for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) { 28199860Sgdamore@opensolaris.org zerocheck |= vi[i]; 28209860Sgdamore@opensolaris.org all_ones &= vi[i]; 28219860Sgdamore@opensolaris.org } 28229860Sgdamore@opensolaris.org if (zerocheck == 0 || all_ones == 0xff) { 28239860Sgdamore@opensolaris.org return (get_alternative_srom_image(devinfo, vi, maxlen)); 28249860Sgdamore@opensolaris.org } else { 28259860Sgdamore@opensolaris.org #ifdef BUG_4010796 28269860Sgdamore@opensolaris.org set_alternative_srom_image(devinfo, vi, maxlen); 28279860Sgdamore@opensolaris.org #endif 28289860Sgdamore@opensolaris.org return (0); /* Primary */ 28299860Sgdamore@opensolaris.org } 28309860Sgdamore@opensolaris.org } 28319860Sgdamore@opensolaris.org 28329860Sgdamore@opensolaris.org /* 28339860Sgdamore@opensolaris.org * The function reads the ethernet address of the 21040 adapter 28349860Sgdamore@opensolaris.org */ 28359860Sgdamore@opensolaris.org static void 28369860Sgdamore@opensolaris.org dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg, 28379860Sgdamore@opensolaris.org uchar_t *addr, int *len) 28389860Sgdamore@opensolaris.org { 28399860Sgdamore@opensolaris.org uint32_t val; 28409860Sgdamore@opensolaris.org int i; 28419860Sgdamore@opensolaris.org 28429860Sgdamore@opensolaris.org /* No point reading more than the ethernet address */ 28439860Sgdamore@opensolaris.org *len = ddi_getprop(DDI_DEV_T_ANY, dip, 28449860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL; 28459860Sgdamore@opensolaris.org 28469860Sgdamore@opensolaris.org /* Reset ROM pointer */ 28479860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0); 28489860Sgdamore@opensolaris.org for (i = 0; i < *len; i++) { 28499860Sgdamore@opensolaris.org do { 28509860Sgdamore@opensolaris.org val = ddi_get32(io_handle, 28519860Sgdamore@opensolaris.org REG32(io_reg, ETHER_ROM_REG)); 28529860Sgdamore@opensolaris.org } while (val & 0x80000000); 28539860Sgdamore@opensolaris.org addr[i] = val & 0xFF; 28549860Sgdamore@opensolaris.org } 28559860Sgdamore@opensolaris.org } 28569860Sgdamore@opensolaris.org 28579860Sgdamore@opensolaris.org #define drv_nsecwait(x) drv_usecwait(((x)+999)/1000) /* XXX */ 28589860Sgdamore@opensolaris.org 28599860Sgdamore@opensolaris.org /* 28609860Sgdamore@opensolaris.org * The function reads the SROM of the 21140 adapter 28619860Sgdamore@opensolaris.org */ 28629860Sgdamore@opensolaris.org static void 28639860Sgdamore@opensolaris.org dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr, 28649860Sgdamore@opensolaris.org int maxlen) 28659860Sgdamore@opensolaris.org { 28669860Sgdamore@opensolaris.org uint32_t i, j; 28679860Sgdamore@opensolaris.org uint32_t dout; 28689860Sgdamore@opensolaris.org uint16_t word; 28699860Sgdamore@opensolaris.org uint8_t rom_addr; 28709860Sgdamore@opensolaris.org uint8_t bit; 28719860Sgdamore@opensolaris.org 28729860Sgdamore@opensolaris.org 28739860Sgdamore@opensolaris.org rom_addr = 0; 28749860Sgdamore@opensolaris.org for (i = 0; i < maxlen; i += 2) { 28759860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28769860Sgdamore@opensolaris.org READ_OP | SEL_ROM); 28779860Sgdamore@opensolaris.org drv_nsecwait(30); 28789860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28799860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP); 28809860Sgdamore@opensolaris.org drv_nsecwait(50); 28819860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28829860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 28839860Sgdamore@opensolaris.org drv_nsecwait(250); 28849860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28859860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP); 28869860Sgdamore@opensolaris.org drv_nsecwait(100); 28879860Sgdamore@opensolaris.org 28889860Sgdamore@opensolaris.org /* command */ 28899860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28909860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 28919860Sgdamore@opensolaris.org drv_nsecwait(150); 28929860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28939860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK); 28949860Sgdamore@opensolaris.org drv_nsecwait(250); 28959860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28969860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 28979860Sgdamore@opensolaris.org drv_nsecwait(250); 28989860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 28999860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK); 29009860Sgdamore@opensolaris.org drv_nsecwait(250); 29019860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29029860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 29039860Sgdamore@opensolaris.org drv_nsecwait(100); 29049860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29059860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP); 29069860Sgdamore@opensolaris.org drv_nsecwait(150); 29079860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29089860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 29099860Sgdamore@opensolaris.org drv_nsecwait(250); 29109860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29119860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP); 29129860Sgdamore@opensolaris.org drv_nsecwait(100); 29139860Sgdamore@opensolaris.org 29149860Sgdamore@opensolaris.org /* Address */ 29159860Sgdamore@opensolaris.org for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) { 29169860Sgdamore@opensolaris.org bit = (rom_addr & j) ? DATA_IN : 0; 29179860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29189860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | bit); 29199860Sgdamore@opensolaris.org drv_nsecwait(150); 29209860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29219860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK); 29229860Sgdamore@opensolaris.org drv_nsecwait(250); 29239860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29249860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | bit); 29259860Sgdamore@opensolaris.org drv_nsecwait(100); 29269860Sgdamore@opensolaris.org } 29279860Sgdamore@opensolaris.org drv_nsecwait(150); 29289860Sgdamore@opensolaris.org 29299860Sgdamore@opensolaris.org /* Data */ 29309860Sgdamore@opensolaris.org word = 0; 29319860Sgdamore@opensolaris.org for (j = 0x8000; j >= 1; j >>= 1) { 29329860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29339860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 29349860Sgdamore@opensolaris.org drv_nsecwait(100); 29359860Sgdamore@opensolaris.org dout = ddi_get32(io_handle, 29369860Sgdamore@opensolaris.org REG32(io_reg, ETHER_ROM_REG)); 29379860Sgdamore@opensolaris.org drv_nsecwait(150); 29389860Sgdamore@opensolaris.org if (dout & DATA_OUT) 29399860Sgdamore@opensolaris.org word |= j; 29409860Sgdamore@opensolaris.org ddi_put32(io_handle, 29419860Sgdamore@opensolaris.org REG32(io_reg, ETHER_ROM_REG), 29429860Sgdamore@opensolaris.org READ_OP | SEL_ROM | SEL_CHIP); 29439860Sgdamore@opensolaris.org drv_nsecwait(250); 29449860Sgdamore@opensolaris.org } 29459860Sgdamore@opensolaris.org addr[i] = (word & 0x0000FF); 29469860Sgdamore@opensolaris.org addr[i + 1] = (word >> 8); 29479860Sgdamore@opensolaris.org rom_addr++; 29489860Sgdamore@opensolaris.org ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 29499860Sgdamore@opensolaris.org READ_OP | SEL_ROM); 29509860Sgdamore@opensolaris.org drv_nsecwait(100); 29519860Sgdamore@opensolaris.org } 29529860Sgdamore@opensolaris.org } 29539860Sgdamore@opensolaris.org 29549860Sgdamore@opensolaris.org 29559860Sgdamore@opensolaris.org /* 29569860Sgdamore@opensolaris.org * XXX NEEDSWORK 29579860Sgdamore@opensolaris.org * 29589860Sgdamore@opensolaris.org * Some lame multiport cards have only one SROM, which can be accessed 29599860Sgdamore@opensolaris.org * only from the "first" 21x4x chip, whichever that one is. If we can't 29609860Sgdamore@opensolaris.org * get at our SROM, we look for its contents in a property instead, which 29619860Sgdamore@opensolaris.org * we rely on the bootstrap to have properly set. 29629860Sgdamore@opensolaris.org * #ifdef BUG_4010796 29639860Sgdamore@opensolaris.org * We also have a hack to try to set it ourselves, when the "first" port 29649860Sgdamore@opensolaris.org * attaches, if it has not already been properly set. However, this method 29659860Sgdamore@opensolaris.org * is not reliable, since it makes the unwarrented assumption that the 29669860Sgdamore@opensolaris.org * "first" port will attach first. 29679860Sgdamore@opensolaris.org * #endif 29689860Sgdamore@opensolaris.org */ 29699860Sgdamore@opensolaris.org 29709860Sgdamore@opensolaris.org static int 29719860Sgdamore@opensolaris.org get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len) 29729860Sgdamore@opensolaris.org { 29739860Sgdamore@opensolaris.org int l = len; 29749860Sgdamore@opensolaris.org 29759860Sgdamore@opensolaris.org if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 29769860Sgdamore@opensolaris.org "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS && 29779860Sgdamore@opensolaris.org (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY, 29789860Sgdamore@opensolaris.org ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM", 29799860Sgdamore@opensolaris.org (caddr_t)vi, &len) != DDI_PROP_SUCCESS) 29809860Sgdamore@opensolaris.org return (-1); /* Can't find it! */ 29819860Sgdamore@opensolaris.org 29829860Sgdamore@opensolaris.org /* 29839860Sgdamore@opensolaris.org * The return value from this routine specifies which port number 29849860Sgdamore@opensolaris.org * we are. The primary port is denoted port 0. On a QUAD card we 29859860Sgdamore@opensolaris.org * should return 1, 2, and 3 from this routine. The return value 29869860Sgdamore@opensolaris.org * is used to modify the ethernet address from the SROM data. 29879860Sgdamore@opensolaris.org */ 29889860Sgdamore@opensolaris.org 29899860Sgdamore@opensolaris.org #ifdef BUG_4010796 29909860Sgdamore@opensolaris.org { 29919860Sgdamore@opensolaris.org /* 29929860Sgdamore@opensolaris.org * For the present, we remember the device number of our primary 29939860Sgdamore@opensolaris.org * sibling and hope we and our other siblings are consecutively 29949860Sgdamore@opensolaris.org * numbered up from there. In the future perhaps the bootstrap 29959860Sgdamore@opensolaris.org * will pass us the necessary information telling us which physical 29969860Sgdamore@opensolaris.org * port we really are. 29979860Sgdamore@opensolaris.org */ 29989860Sgdamore@opensolaris.org pci_regspec_t *assignp; 29999860Sgdamore@opensolaris.org int assign_len; 30009860Sgdamore@opensolaris.org int devnum; 30019860Sgdamore@opensolaris.org int primary_devnum; 30029860Sgdamore@opensolaris.org 30039860Sgdamore@opensolaris.org primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0, 30049860Sgdamore@opensolaris.org "DNET_DEVNUM", -1); 30059860Sgdamore@opensolaris.org if (primary_devnum == -1) 30069860Sgdamore@opensolaris.org return (1); /* XXX NEEDSWORK -- We have no better idea */ 30079860Sgdamore@opensolaris.org 30089860Sgdamore@opensolaris.org if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 30099860Sgdamore@opensolaris.org "assigned-addresses", (caddr_t)&assignp, 30109860Sgdamore@opensolaris.org &assign_len)) != DDI_PROP_SUCCESS) 30119860Sgdamore@opensolaris.org return (1); /* XXX NEEDSWORK -- We have no better idea */ 30129860Sgdamore@opensolaris.org 30139860Sgdamore@opensolaris.org devnum = PCI_REG_DEV_G(assignp->pci_phys_hi); 30149860Sgdamore@opensolaris.org kmem_free(assignp, assign_len); 30159860Sgdamore@opensolaris.org return (devnum - primary_devnum); 30169860Sgdamore@opensolaris.org } 30179860Sgdamore@opensolaris.org #else 30189860Sgdamore@opensolaris.org return (1); /* XXX NEEDSWORK -- We have no better idea */ 30199860Sgdamore@opensolaris.org #endif 30209860Sgdamore@opensolaris.org } 30219860Sgdamore@opensolaris.org 30229860Sgdamore@opensolaris.org 30239860Sgdamore@opensolaris.org #ifdef BUG_4010796 30249860Sgdamore@opensolaris.org static void 30259860Sgdamore@opensolaris.org set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len) 30269860Sgdamore@opensolaris.org { 30279860Sgdamore@opensolaris.org int proplen; 30289860Sgdamore@opensolaris.org pci_regspec_t *assignp; 30299860Sgdamore@opensolaris.org int assign_len; 30309860Sgdamore@opensolaris.org int devnum; 30319860Sgdamore@opensolaris.org 30329860Sgdamore@opensolaris.org if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 30339860Sgdamore@opensolaris.org "DNET_SROM", &proplen) == DDI_PROP_SUCCESS || 30349860Sgdamore@opensolaris.org ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 30359860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS) 30369860Sgdamore@opensolaris.org return; /* Already done! */ 30379860Sgdamore@opensolaris.org 30389860Sgdamore@opensolaris.org /* function return value ignored */ 30399860Sgdamore@opensolaris.org (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, 30409860Sgdamore@opensolaris.org ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len); 30419860Sgdamore@opensolaris.org (void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo, 30429860Sgdamore@opensolaris.org "DNET_HACK", "hack"); 30439860Sgdamore@opensolaris.org 30449860Sgdamore@opensolaris.org if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 30459860Sgdamore@opensolaris.org "assigned-addresses", (caddr_t)&assignp, 30469860Sgdamore@opensolaris.org &assign_len)) == DDI_PROP_SUCCESS) { 30479860Sgdamore@opensolaris.org devnum = PCI_REG_DEV_G(assignp->pci_phys_hi); 30489860Sgdamore@opensolaris.org kmem_free(assignp, assign_len); 30499860Sgdamore@opensolaris.org /* function return value ignored */ 30509860Sgdamore@opensolaris.org (void) ddi_prop_update_int(DDI_DEV_T_NONE, 30519860Sgdamore@opensolaris.org ddi_get_parent(devinfo), "DNET_DEVNUM", devnum); 30529860Sgdamore@opensolaris.org } 30539860Sgdamore@opensolaris.org } 30549860Sgdamore@opensolaris.org #endif 30559860Sgdamore@opensolaris.org 30569860Sgdamore@opensolaris.org /* 30579860Sgdamore@opensolaris.org * ========== SROM Parsing Routines ========== 30589860Sgdamore@opensolaris.org */ 30599860Sgdamore@opensolaris.org 30609860Sgdamore@opensolaris.org static int 30619860Sgdamore@opensolaris.org check_srom_valid(uchar_t *vi) 30629860Sgdamore@opensolaris.org { 30639860Sgdamore@opensolaris.org int word, bit; 30649860Sgdamore@opensolaris.org uint8_t crc; 30659860Sgdamore@opensolaris.org uint16_t *wvi; /* word16 pointer to vendor info */ 30669860Sgdamore@opensolaris.org uint16_t bitval; 30679860Sgdamore@opensolaris.org 30689860Sgdamore@opensolaris.org /* verify that the number of controllers on the card is within range */ 30699860Sgdamore@opensolaris.org if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS) 30709860Sgdamore@opensolaris.org return (0); 30719860Sgdamore@opensolaris.org 30729860Sgdamore@opensolaris.org /* 30739860Sgdamore@opensolaris.org * version 1 and 3 of this card did not check the id block CRC value 30749860Sgdamore@opensolaris.org * and this can't be changed without retesting every supported card 30759860Sgdamore@opensolaris.org * 30769860Sgdamore@opensolaris.org * however version 4 of the SROM can have this test applied 30779860Sgdamore@opensolaris.org * without fear of breaking something that used to work. 30789860Sgdamore@opensolaris.org * the CRC algorithm is taken from the Intel document 30799860Sgdamore@opensolaris.org * "21x4 Serial ROM Format" 30809860Sgdamore@opensolaris.org * version 4.09 30819860Sgdamore@opensolaris.org * 3-Mar-1999 30829860Sgdamore@opensolaris.org */ 30839860Sgdamore@opensolaris.org 30849860Sgdamore@opensolaris.org switch (vi[SROM_VERSION]) { 30859860Sgdamore@opensolaris.org case 1: 30869860Sgdamore@opensolaris.org /* fallthru */ 30879860Sgdamore@opensolaris.org case 3: 30889860Sgdamore@opensolaris.org return (vi[SROM_MBZ] == 0 && /* must be zero */ 30899860Sgdamore@opensolaris.org vi[SROM_MBZ2] == 0 && /* must be zero */ 30909860Sgdamore@opensolaris.org vi[SROM_MBZ3] == 0); /* must be zero */ 30919860Sgdamore@opensolaris.org 30929860Sgdamore@opensolaris.org case 4: 30939860Sgdamore@opensolaris.org wvi = (uint16_t *)vi; 30949860Sgdamore@opensolaris.org crc = 0xff; 30959860Sgdamore@opensolaris.org for (word = 0; word < 9; word++) 30969860Sgdamore@opensolaris.org for (bit = 15; bit >= 0; bit--) { 30979860Sgdamore@opensolaris.org if (word == 8 && bit == 7) 30989860Sgdamore@opensolaris.org return (crc == vi[16]); 30999860Sgdamore@opensolaris.org bitval = 31009860Sgdamore@opensolaris.org ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1); 31019860Sgdamore@opensolaris.org crc <<= 1; 31029860Sgdamore@opensolaris.org if (bitval == 1) { 31039860Sgdamore@opensolaris.org crc ^= 7; 31049860Sgdamore@opensolaris.org } 31059860Sgdamore@opensolaris.org } 31069860Sgdamore@opensolaris.org 31079860Sgdamore@opensolaris.org default: 31089860Sgdamore@opensolaris.org return (0); 31099860Sgdamore@opensolaris.org } 31109860Sgdamore@opensolaris.org } 31119860Sgdamore@opensolaris.org 31129860Sgdamore@opensolaris.org /* 31139860Sgdamore@opensolaris.org * ========== Active Media Determination Routines ========== 31149860Sgdamore@opensolaris.org */ 31159860Sgdamore@opensolaris.org 31169860Sgdamore@opensolaris.org /* This routine is also called for V3 Compact and extended type 0 SROMs */ 31179860Sgdamore@opensolaris.org static int 31189860Sgdamore@opensolaris.org is_fdmedia(int media) 31199860Sgdamore@opensolaris.org { 31209860Sgdamore@opensolaris.org if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD) 31219860Sgdamore@opensolaris.org return (1); 31229860Sgdamore@opensolaris.org else 31239860Sgdamore@opensolaris.org return (0); 31249860Sgdamore@opensolaris.org } 31259860Sgdamore@opensolaris.org 31269860Sgdamore@opensolaris.org /* 31279860Sgdamore@opensolaris.org * "Linkset" is used to merge media that use the same link test check. So, 31289860Sgdamore@opensolaris.org * if the TP link is added to the linkset, so is the TP Full duplex link. 31299860Sgdamore@opensolaris.org * Used to avoid checking the same link status twice. 31309860Sgdamore@opensolaris.org */ 31319860Sgdamore@opensolaris.org static void 31329860Sgdamore@opensolaris.org linkset_add(uint32_t *set, int media) 31339860Sgdamore@opensolaris.org { 31349860Sgdamore@opensolaris.org if (media == MEDIA_TP_FD || media == MEDIA_TP) 31359860Sgdamore@opensolaris.org *set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP); 31369860Sgdamore@opensolaris.org else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR) 31379860Sgdamore@opensolaris.org *set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR); 31389860Sgdamore@opensolaris.org else *set |= 1UL<<media; 31399860Sgdamore@opensolaris.org } 31409860Sgdamore@opensolaris.org static int 31419860Sgdamore@opensolaris.org linkset_isset(uint32_t linkset, int media) 31429860Sgdamore@opensolaris.org { 31439860Sgdamore@opensolaris.org return (((1UL<<media) & linkset) ? 1:0); 31449860Sgdamore@opensolaris.org } 31459860Sgdamore@opensolaris.org 31469860Sgdamore@opensolaris.org /* 31479860Sgdamore@opensolaris.org * The following code detects which Media is connected for 21041/21140 31489860Sgdamore@opensolaris.org * Expect to change this code to support new 21140 variants. 31499860Sgdamore@opensolaris.org * find_active_media() - called with intrlock held. 31509860Sgdamore@opensolaris.org */ 31519860Sgdamore@opensolaris.org static void 3152*10340Sstallion@opensolaris.org find_active_media(struct dnetinstance *dnetp) 31539860Sgdamore@opensolaris.org { 31549860Sgdamore@opensolaris.org int i; 31559860Sgdamore@opensolaris.org media_block_t *block; 31569860Sgdamore@opensolaris.org media_block_t *best_allowed = NULL; 31579860Sgdamore@opensolaris.org media_block_t *hd_found = NULL; 31589860Sgdamore@opensolaris.org media_block_t *fd_found = NULL; 31599860Sgdamore@opensolaris.org LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf]; 31609860Sgdamore@opensolaris.org uint32_t checked = 0, links_up = 0; 31619860Sgdamore@opensolaris.org 31629860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3163*10340Sstallion@opensolaris.org 31649860Sgdamore@opensolaris.org dnetp->selected_media_block = leaf->default_block; 31659860Sgdamore@opensolaris.org 31669860Sgdamore@opensolaris.org if (dnetp->phyaddr != -1) { 31679860Sgdamore@opensolaris.org dnetp->selected_media_block = leaf->mii_block; 3168*10340Sstallion@opensolaris.org setup_block(dnetp); 31699860Sgdamore@opensolaris.org 31709860Sgdamore@opensolaris.org if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 31719860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "portmon", 1)) { 31729860Sgdamore@opensolaris.org /* XXX return value ignored */ 31739860Sgdamore@opensolaris.org (void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb, 31749860Sgdamore@opensolaris.org &dnetp->intrlock); 31759860Sgdamore@opensolaris.org /* 31769860Sgdamore@opensolaris.org * If the port monitor detects the link is already 31779860Sgdamore@opensolaris.org * up, there is no point going through the rest of the 31789860Sgdamore@opensolaris.org * link sense 31799860Sgdamore@opensolaris.org */ 31809860Sgdamore@opensolaris.org if (dnetp->mii_up) { 31819860Sgdamore@opensolaris.org return; 31829860Sgdamore@opensolaris.org } 31839860Sgdamore@opensolaris.org } 31849860Sgdamore@opensolaris.org } 31859860Sgdamore@opensolaris.org 31869860Sgdamore@opensolaris.org /* 31879860Sgdamore@opensolaris.org * Media is searched for in order of Precedence. This DEC SROM spec 31889860Sgdamore@opensolaris.org * tells us that the first media entry in the SROM is the lowest 31899860Sgdamore@opensolaris.org * precedence and should be checked last. This is why we go to the last 31909860Sgdamore@opensolaris.org * Media block and work back to the beginning. 31919860Sgdamore@opensolaris.org * 31929860Sgdamore@opensolaris.org * However, some older SROMs (Cogent EM110's etc.) have this the wrong 31939860Sgdamore@opensolaris.org * way around. As a result, following the SROM spec would result in a 31949860Sgdamore@opensolaris.org * 10 link being chosen over a 100 link if both media are available. 31959860Sgdamore@opensolaris.org * So we continue trying the media until we have at least tried the 31969860Sgdamore@opensolaris.org * DEFAULT media. 31979860Sgdamore@opensolaris.org */ 31989860Sgdamore@opensolaris.org 31999860Sgdamore@opensolaris.org /* Search for an active medium, and select it */ 32009860Sgdamore@opensolaris.org for (block = leaf->block + leaf->block_count - 1; 32019860Sgdamore@opensolaris.org block >= leaf->block; block--) { 32029860Sgdamore@opensolaris.org int media = block->media_code; 32039860Sgdamore@opensolaris.org 32049860Sgdamore@opensolaris.org /* User settings disallow selection of this block */ 32059860Sgdamore@opensolaris.org if (dnetp->disallowed_media & (1UL<<media)) 32069860Sgdamore@opensolaris.org continue; 32079860Sgdamore@opensolaris.org 32089860Sgdamore@opensolaris.org /* We may not be able to pick the default */ 32099860Sgdamore@opensolaris.org if (best_allowed == NULL || block == leaf->default_block) 32109860Sgdamore@opensolaris.org best_allowed = block; 32119860Sgdamore@opensolaris.org #ifdef DEBUG 32129860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 32139860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "Testing %s medium (block type %d)", 32149860Sgdamore@opensolaris.org media_str[media], block->type); 32159860Sgdamore@opensolaris.org #endif 32169860Sgdamore@opensolaris.org 32179860Sgdamore@opensolaris.org dnetp->selected_media_block = block; 32189860Sgdamore@opensolaris.org switch (block->type) { 32199860Sgdamore@opensolaris.org 32209860Sgdamore@opensolaris.org case 2: /* SIA Media block: Best we can do is send a packet */ 3221*10340Sstallion@opensolaris.org setup_block(dnetp); 3222*10340Sstallion@opensolaris.org if (send_test_packet(dnetp)) { 32239860Sgdamore@opensolaris.org if (!is_fdmedia(media)) 32249860Sgdamore@opensolaris.org return; 32259860Sgdamore@opensolaris.org if (!fd_found) 32269860Sgdamore@opensolaris.org fd_found = block; 32279860Sgdamore@opensolaris.org } 32289860Sgdamore@opensolaris.org break; 32299860Sgdamore@opensolaris.org 32309860Sgdamore@opensolaris.org /* SYM/SCR or TP block: Use the link-sense bits */ 32319860Sgdamore@opensolaris.org case 0: 32329860Sgdamore@opensolaris.org if (!linkset_isset(checked, media)) { 32339860Sgdamore@opensolaris.org linkset_add(&checked, media); 32349860Sgdamore@opensolaris.org if (((media == MEDIA_BNC || 32359860Sgdamore@opensolaris.org media == MEDIA_AUI) && 3236*10340Sstallion@opensolaris.org send_test_packet(dnetp)) || 3237*10340Sstallion@opensolaris.org dnet_link_sense(dnetp)) 32389860Sgdamore@opensolaris.org linkset_add(&links_up, media); 32399860Sgdamore@opensolaris.org } 32409860Sgdamore@opensolaris.org 32419860Sgdamore@opensolaris.org if (linkset_isset(links_up, media)) { 32429860Sgdamore@opensolaris.org /* 32439860Sgdamore@opensolaris.org * Half Duplex is *always* the favoured media. 32449860Sgdamore@opensolaris.org * Full Duplex can be set and forced via the 32459860Sgdamore@opensolaris.org * conf file. 32469860Sgdamore@opensolaris.org */ 32479860Sgdamore@opensolaris.org if (!is_fdmedia(media) && 32489860Sgdamore@opensolaris.org dnetp->selected_media_block == 32499860Sgdamore@opensolaris.org leaf->default_block) { 32509860Sgdamore@opensolaris.org /* 32519860Sgdamore@opensolaris.org * Cogent cards have the media in 32529860Sgdamore@opensolaris.org * opposite order to the spec., 32539860Sgdamore@opensolaris.org * this code forces the media test to 32549860Sgdamore@opensolaris.org * keep going until the default media 32559860Sgdamore@opensolaris.org * is tested. 32569860Sgdamore@opensolaris.org * 32579860Sgdamore@opensolaris.org * In Cogent case, 10, 10FD, 100FD, 100 32589860Sgdamore@opensolaris.org * 100 is the default but 10 could have 32599860Sgdamore@opensolaris.org * been detected and would have been 32609860Sgdamore@opensolaris.org * chosen but now we force it through to 32619860Sgdamore@opensolaris.org * 100. 32629860Sgdamore@opensolaris.org */ 3263*10340Sstallion@opensolaris.org setup_block(dnetp); 32649860Sgdamore@opensolaris.org return; 32659860Sgdamore@opensolaris.org } else if (!is_fdmedia(media)) { 32669860Sgdamore@opensolaris.org /* 32679860Sgdamore@opensolaris.org * This allows all the others to work 32689860Sgdamore@opensolaris.org * properly by remembering the media 32699860Sgdamore@opensolaris.org * that works and not defaulting to 32709860Sgdamore@opensolaris.org * a FD link. 32719860Sgdamore@opensolaris.org */ 32729860Sgdamore@opensolaris.org if (hd_found == NULL) 32739860Sgdamore@opensolaris.org hd_found = block; 32749860Sgdamore@opensolaris.org } else if (fd_found == NULL) { 32759860Sgdamore@opensolaris.org /* 32769860Sgdamore@opensolaris.org * No media have already been found 32779860Sgdamore@opensolaris.org * so far, this is FD, it works so 32789860Sgdamore@opensolaris.org * remember it and if no others are 32799860Sgdamore@opensolaris.org * detected, use it. 32809860Sgdamore@opensolaris.org */ 32819860Sgdamore@opensolaris.org fd_found = block; 32829860Sgdamore@opensolaris.org } 32839860Sgdamore@opensolaris.org } 32849860Sgdamore@opensolaris.org break; 32859860Sgdamore@opensolaris.org 32869860Sgdamore@opensolaris.org /* 32879860Sgdamore@opensolaris.org * MII block: May take up to a second or so to settle if 32889860Sgdamore@opensolaris.org * setup causes a PHY reset 32899860Sgdamore@opensolaris.org */ 32909860Sgdamore@opensolaris.org case 1: case 3: 3291*10340Sstallion@opensolaris.org setup_block(dnetp); 32929860Sgdamore@opensolaris.org for (i = 0; ; i++) { 32939860Sgdamore@opensolaris.org if (mii_linkup(dnetp->mii, dnetp->phyaddr)) { 32949860Sgdamore@opensolaris.org /* XXX function return value ignored */ 32959860Sgdamore@opensolaris.org (void) mii_getspeed(dnetp->mii, 32969860Sgdamore@opensolaris.org dnetp->phyaddr, 32979860Sgdamore@opensolaris.org &dnetp->mii_speed, 32989860Sgdamore@opensolaris.org &dnetp->mii_duplex); 32999860Sgdamore@opensolaris.org dnetp->mii_up = 1; 33009860Sgdamore@opensolaris.org leaf->mii_block = block; 33019860Sgdamore@opensolaris.org return; 33029860Sgdamore@opensolaris.org } 33039860Sgdamore@opensolaris.org if (i == 10) 33049860Sgdamore@opensolaris.org break; 33059860Sgdamore@opensolaris.org delay(drv_usectohz(150000)); 33069860Sgdamore@opensolaris.org } 33079860Sgdamore@opensolaris.org dnetp->mii_up = 0; 33089860Sgdamore@opensolaris.org break; 33099860Sgdamore@opensolaris.org } 33109860Sgdamore@opensolaris.org } /* for loop */ 33119860Sgdamore@opensolaris.org if (hd_found) { 33129860Sgdamore@opensolaris.org dnetp->selected_media_block = hd_found; 33139860Sgdamore@opensolaris.org } else if (fd_found) { 33149860Sgdamore@opensolaris.org dnetp->selected_media_block = fd_found; 33159860Sgdamore@opensolaris.org } else { 33169860Sgdamore@opensolaris.org if (best_allowed == NULL) 33179860Sgdamore@opensolaris.org best_allowed = leaf->default_block; 33189860Sgdamore@opensolaris.org dnetp->selected_media_block = best_allowed; 33199860Sgdamore@opensolaris.org cmn_err(CE_WARN, "!dnet: Default media selected\n"); 33209860Sgdamore@opensolaris.org } 3321*10340Sstallion@opensolaris.org setup_block(dnetp); 33229860Sgdamore@opensolaris.org } 33239860Sgdamore@opensolaris.org 33249860Sgdamore@opensolaris.org /* 33259860Sgdamore@opensolaris.org * Do anything neccessary to select the selected_media_block. 33269860Sgdamore@opensolaris.org * setup_block() - called with intrlock held. 33279860Sgdamore@opensolaris.org */ 33289860Sgdamore@opensolaris.org static void 3329*10340Sstallion@opensolaris.org setup_block(struct dnetinstance *dnetp) 33309860Sgdamore@opensolaris.org { 3331*10340Sstallion@opensolaris.org dnet_reset_board(dnetp); 3332*10340Sstallion@opensolaris.org dnet_init_board(dnetp); 33339860Sgdamore@opensolaris.org /* XXX function return value ignored */ 3334*10340Sstallion@opensolaris.org (void) dnet_start(dnetp); 33359860Sgdamore@opensolaris.org } 33369860Sgdamore@opensolaris.org 33379860Sgdamore@opensolaris.org /* dnet_link_sense() - called with intrlock held */ 33389860Sgdamore@opensolaris.org static int 3339*10340Sstallion@opensolaris.org dnet_link_sense(struct dnetinstance *dnetp) 33409860Sgdamore@opensolaris.org { 33419860Sgdamore@opensolaris.org /* 33429860Sgdamore@opensolaris.org * This routine makes use of the command word from the srom config. 33439860Sgdamore@opensolaris.org * Details of the auto-sensing information contained in this can 33449860Sgdamore@opensolaris.org * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03" 33459860Sgdamore@opensolaris.org * spec. Section 4.3.2.1, and 4.5.2.1.3 33469860Sgdamore@opensolaris.org */ 33479860Sgdamore@opensolaris.org media_block_t *block = dnetp->selected_media_block; 33489860Sgdamore@opensolaris.org uint32_t link, status, mask, polarity; 33499860Sgdamore@opensolaris.org int settletime, stabletime, waittime, upsamples; 33509860Sgdamore@opensolaris.org int delay_100, delay_10; 33519860Sgdamore@opensolaris.org 33529860Sgdamore@opensolaris.org 33539860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 33549860Sgdamore@opensolaris.org /* Don't autosense if the medium does not support it */ 33559860Sgdamore@opensolaris.org if (block->command & (1 << 15)) { 33569860Sgdamore@opensolaris.org /* This should be the default block */ 33579860Sgdamore@opensolaris.org if (block->command & (1UL<<14)) 33589860Sgdamore@opensolaris.org dnetp->sr.leaf[dnetp->leaf].default_block = block; 33599860Sgdamore@opensolaris.org return (0); 33609860Sgdamore@opensolaris.org } 33619860Sgdamore@opensolaris.org 33629860Sgdamore@opensolaris.org delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 33639860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "autosense-delay-100", 2000); 33649860Sgdamore@opensolaris.org 33659860Sgdamore@opensolaris.org delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 33669860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "autosense-delay-10", 400); 33679860Sgdamore@opensolaris.org 33689860Sgdamore@opensolaris.org /* 33699860Sgdamore@opensolaris.org * Scrambler may need to be disabled for link sensing 33709860Sgdamore@opensolaris.org * to work 33719860Sgdamore@opensolaris.org */ 33729860Sgdamore@opensolaris.org dnetp->disable_scrambler = 1; 3373*10340Sstallion@opensolaris.org setup_block(dnetp); 33749860Sgdamore@opensolaris.org dnetp->disable_scrambler = 0; 33759860Sgdamore@opensolaris.org 33769860Sgdamore@opensolaris.org if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD) 33779860Sgdamore@opensolaris.org settletime = delay_10; 33789860Sgdamore@opensolaris.org else 33799860Sgdamore@opensolaris.org settletime = delay_100; 33809860Sgdamore@opensolaris.org stabletime = settletime / 4; 33819860Sgdamore@opensolaris.org 33829860Sgdamore@opensolaris.org mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1); 33839860Sgdamore@opensolaris.org polarity = block->command & CMD_POL ? 0xffffffff : 0; 33849860Sgdamore@opensolaris.org 33859860Sgdamore@opensolaris.org for (waittime = 0, upsamples = 0; 33869860Sgdamore@opensolaris.org waittime <= settletime + stabletime && upsamples < 8; 33879860Sgdamore@opensolaris.org waittime += stabletime/8) { 33889860Sgdamore@opensolaris.org delay(drv_usectohz(stabletime*1000 / 8)); 33899860Sgdamore@opensolaris.org status = read_gpr(dnetp); 33909860Sgdamore@opensolaris.org link = (status^polarity) & mask; 33919860Sgdamore@opensolaris.org if (link) 33929860Sgdamore@opensolaris.org upsamples++; 33939860Sgdamore@opensolaris.org else 33949860Sgdamore@opensolaris.org upsamples = 0; 33959860Sgdamore@opensolaris.org } 33969860Sgdamore@opensolaris.org #ifdef DNETDEBUG 33979860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 33989860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x " 33999860Sgdamore@opensolaris.org "mask:%x link:%x", 34009860Sgdamore@opensolaris.org upsamples == 8 ? "UP":"DOWN", 34019860Sgdamore@opensolaris.org upsamples, status, polarity, mask, link); 34029860Sgdamore@opensolaris.org #endif 34039860Sgdamore@opensolaris.org if (upsamples == 8) 34049860Sgdamore@opensolaris.org return (1); 34059860Sgdamore@opensolaris.org return (0); 34069860Sgdamore@opensolaris.org } 34079860Sgdamore@opensolaris.org 34089860Sgdamore@opensolaris.org static int 3409*10340Sstallion@opensolaris.org send_test_packet(struct dnetinstance *dnetp) 34109860Sgdamore@opensolaris.org { 34119860Sgdamore@opensolaris.org int packet_delay; 34129860Sgdamore@opensolaris.org struct tx_desc_type *desc; 34139860Sgdamore@opensolaris.org int bufindex; 34149860Sgdamore@opensolaris.org int media_code = dnetp->selected_media_block->media_code; 34159860Sgdamore@opensolaris.org uint32_t del; 34169860Sgdamore@opensolaris.org 34179860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 34189860Sgdamore@opensolaris.org /* 34199860Sgdamore@opensolaris.org * For a successful test packet, the card must have settled into 34209860Sgdamore@opensolaris.org * its current setting. Almost all cards we've tested manage to 34219860Sgdamore@opensolaris.org * do this with all media within 50ms. However, the SMC 8432 34229860Sgdamore@opensolaris.org * requires 300ms to settle into BNC mode. We now only do this 34239860Sgdamore@opensolaris.org * from attach, and we do sleeping delay() instead of drv_usecwait() 34249860Sgdamore@opensolaris.org * so we hope this .2 second delay won't cause too much suffering. 34259860Sgdamore@opensolaris.org * ALSO: with an autonegotiating hub, an aditional 1 second delay is 34269860Sgdamore@opensolaris.org * required. This is done if the media type is TP 34279860Sgdamore@opensolaris.org */ 34289860Sgdamore@opensolaris.org if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) { 34299860Sgdamore@opensolaris.org packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 34309860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000); 34319860Sgdamore@opensolaris.org } else { 34329860Sgdamore@opensolaris.org packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 34339860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "test_packet_delay", 300000); 34349860Sgdamore@opensolaris.org } 34359860Sgdamore@opensolaris.org delay(drv_usectohz(packet_delay)); 34369860Sgdamore@opensolaris.org 34379860Sgdamore@opensolaris.org desc = dnetp->tx_desc; 34389860Sgdamore@opensolaris.org 34399860Sgdamore@opensolaris.org bufindex = dnetp->tx_current_desc; 3440*10340Sstallion@opensolaris.org if (alloc_descriptor(dnetp) == FAILURE) { 34419860Sgdamore@opensolaris.org cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor" 34429860Sgdamore@opensolaris.org "failed"); 34439860Sgdamore@opensolaris.org return (0); 34449860Sgdamore@opensolaris.org } 34459860Sgdamore@opensolaris.org 34469860Sgdamore@opensolaris.org /* 34479860Sgdamore@opensolaris.org * use setup buffer as the buffer for the test packet 34489860Sgdamore@opensolaris.org * instead of allocating one. 34499860Sgdamore@opensolaris.org */ 34509860Sgdamore@opensolaris.org 34519860Sgdamore@opensolaris.org ASSERT(dnetp->setup_buf_vaddr != NULL); 34529860Sgdamore@opensolaris.org /* Put something decent in dest address so we don't annoy other cards */ 34539860Sgdamore@opensolaris.org BCOPY((caddr_t)dnetp->curr_macaddr, 34549860Sgdamore@opensolaris.org (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL); 34559860Sgdamore@opensolaris.org BCOPY((caddr_t)dnetp->curr_macaddr, 34569860Sgdamore@opensolaris.org (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL); 34579860Sgdamore@opensolaris.org 34589860Sgdamore@opensolaris.org desc[bufindex].buffer1 = dnetp->setup_buf_paddr; 34599860Sgdamore@opensolaris.org desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE; 34609860Sgdamore@opensolaris.org desc[bufindex].buffer2 = (uint32_t)(0); 34619860Sgdamore@opensolaris.org desc[bufindex].desc1.first_desc = 1; 34629860Sgdamore@opensolaris.org desc[bufindex].desc1.last_desc = 1; 34639860Sgdamore@opensolaris.org desc[bufindex].desc1.int_on_comp = 1; 34649860Sgdamore@opensolaris.org desc[bufindex].desc0.own = 1; 34659860Sgdamore@opensolaris.org 34669860Sgdamore@opensolaris.org ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG), 34679860Sgdamore@opensolaris.org TX_POLL_DEMAND); 34689860Sgdamore@opensolaris.org 34699860Sgdamore@opensolaris.org /* 34709860Sgdamore@opensolaris.org * Give enough time for the chip to transmit the packet 34719860Sgdamore@opensolaris.org */ 34729860Sgdamore@opensolaris.org #if 1 34739860Sgdamore@opensolaris.org del = 1000; 34749860Sgdamore@opensolaris.org while (desc[bufindex].desc0.own && --del) 34759860Sgdamore@opensolaris.org drv_usecwait(10); /* quickly wait up to 10ms */ 34769860Sgdamore@opensolaris.org if (desc[bufindex].desc0.own) 34779860Sgdamore@opensolaris.org delay(drv_usectohz(200000)); /* nicely wait a longer time */ 34789860Sgdamore@opensolaris.org #else 34799860Sgdamore@opensolaris.org del = 0x10000; 34809860Sgdamore@opensolaris.org while (desc[bufindex].desc0.own && --del) 34819860Sgdamore@opensolaris.org drv_usecwait(10); 34829860Sgdamore@opensolaris.org #endif 34839860Sgdamore@opensolaris.org 34849860Sgdamore@opensolaris.org #ifdef DNETDEBUG 34859860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 34869860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u", 34879860Sgdamore@opensolaris.org desc[bufindex].desc0.own, 34889860Sgdamore@opensolaris.org desc[bufindex].desc0.err_summary, 34899860Sgdamore@opensolaris.org desc[bufindex].desc0.carrier_loss, 34909860Sgdamore@opensolaris.org desc[bufindex].desc0.no_carrier, 34919860Sgdamore@opensolaris.org desc[bufindex].desc0.late_collision, 34929860Sgdamore@opensolaris.org desc[bufindex].desc0.link_fail); 34939860Sgdamore@opensolaris.org #endif 34949860Sgdamore@opensolaris.org if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */ 34959860Sgdamore@opensolaris.org return (0); 34969860Sgdamore@opensolaris.org 34979860Sgdamore@opensolaris.org return (!desc[bufindex].desc0.err_summary); 34989860Sgdamore@opensolaris.org } 34999860Sgdamore@opensolaris.org 35009860Sgdamore@opensolaris.org /* enable_interrupts - called with intrlock held */ 35019860Sgdamore@opensolaris.org static void 3502*10340Sstallion@opensolaris.org enable_interrupts(struct dnetinstance *dnetp) 35039860Sgdamore@opensolaris.org { 35049860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 35059860Sgdamore@opensolaris.org /* Don't enable interrupts if they have been forced off */ 35069860Sgdamore@opensolaris.org if (dnetp->interrupts_disabled) 35079860Sgdamore@opensolaris.org return; 35089860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 3509*10340Sstallion@opensolaris.org ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK | 35109860Sgdamore@opensolaris.org (dnetp->timer.cb ? GPTIMER_INTR : 0) | 3511*10340Sstallion@opensolaris.org RX_INTERRUPT_MASK | 3512*10340Sstallion@opensolaris.org TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK); 35139860Sgdamore@opensolaris.org } 35149860Sgdamore@opensolaris.org 35159860Sgdamore@opensolaris.org /* 35169860Sgdamore@opensolaris.org * Some older multiport cards are non-PCI compliant in their interrupt routing. 35179860Sgdamore@opensolaris.org * Second and subsequent devices are incorrectly configured by the BIOS 35189860Sgdamore@opensolaris.org * (either in their ILINE configuration or the MP Configuration Table for PC+MP 35199860Sgdamore@opensolaris.org * systems). 3520*10340Sstallion@opensolaris.org * The hack stops registering the interrupt routine for the FIRST 3521*10340Sstallion@opensolaris.org * device on the adapter, and registers its own. It builds up a table 3522*10340Sstallion@opensolaris.org * of dnetp structures for each device, and the new interrupt routine 3523*10340Sstallion@opensolaris.org * calls dnet_intr for each of them. 35249860Sgdamore@opensolaris.org * Known cards that suffer from this problem are: 35259860Sgdamore@opensolaris.org * All Cogent multiport cards; 35269860Sgdamore@opensolaris.org * Znyx 314; 35279860Sgdamore@opensolaris.org * Znyx 315. 35289860Sgdamore@opensolaris.org * 35299860Sgdamore@opensolaris.org * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This 35309860Sgdamore@opensolaris.org * hack relies on the fact that the offending cards will have only one SROM. 35319860Sgdamore@opensolaris.org * It uses this fact to identify devices that are on the same multiport 35329860Sgdamore@opensolaris.org * adapter, as opposed to multiple devices from the same vendor (as 35339860Sgdamore@opensolaris.org * indicated by "secondary") 35349860Sgdamore@opensolaris.org */ 35359860Sgdamore@opensolaris.org static int 3536*10340Sstallion@opensolaris.org dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary) 35379860Sgdamore@opensolaris.org { 35389860Sgdamore@opensolaris.org int i; 35399860Sgdamore@opensolaris.org struct hackintr_inf *hackintr_inf; 35409860Sgdamore@opensolaris.org dev_info_t *devinfo = dnetp->devinfo; 35419860Sgdamore@opensolaris.org uint32_t oui = 0; /* Organizationally Unique ID */ 35429860Sgdamore@opensolaris.org 35439860Sgdamore@opensolaris.org if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 35449860Sgdamore@opensolaris.org "no_INTA_workaround", 0) != 0) 35459860Sgdamore@opensolaris.org return (0); 35469860Sgdamore@opensolaris.org 35479860Sgdamore@opensolaris.org for (i = 0; i < 3; i++) 35489860Sgdamore@opensolaris.org oui = (oui << 8) | dnetp->vendor_addr[i]; 35499860Sgdamore@opensolaris.org 35509860Sgdamore@opensolaris.org /* Check wheather or not we need to implement the hack */ 35519860Sgdamore@opensolaris.org 35529860Sgdamore@opensolaris.org switch (oui) { 35539860Sgdamore@opensolaris.org case ZNYX_ETHER: 35549860Sgdamore@opensolaris.org /* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */ 35559860Sgdamore@opensolaris.org if (dnetp->board_type != DEVICE_ID_21040) 35569860Sgdamore@opensolaris.org return (0); 35579860Sgdamore@opensolaris.org break; 35589860Sgdamore@opensolaris.org 35599860Sgdamore@opensolaris.org case COGENT_ETHER: 35609860Sgdamore@opensolaris.org /* All known Cogent multiport cards */ 35619860Sgdamore@opensolaris.org break; 35629860Sgdamore@opensolaris.org 35639860Sgdamore@opensolaris.org case ADAPTEC_ETHER: 35649860Sgdamore@opensolaris.org /* Adaptec multiport cards */ 35659860Sgdamore@opensolaris.org break; 35669860Sgdamore@opensolaris.org 35679860Sgdamore@opensolaris.org default: 35689860Sgdamore@opensolaris.org /* Other cards work correctly */ 35699860Sgdamore@opensolaris.org return (0); 35709860Sgdamore@opensolaris.org } 35719860Sgdamore@opensolaris.org 35729860Sgdamore@opensolaris.org /* card is (probably) non-PCI compliant in its interrupt routing */ 35739860Sgdamore@opensolaris.org 35749860Sgdamore@opensolaris.org 35759860Sgdamore@opensolaris.org if (!secondary) { 35769860Sgdamore@opensolaris.org 35779860Sgdamore@opensolaris.org /* 35789860Sgdamore@opensolaris.org * If we have already registered a hacked interrupt, and 35799860Sgdamore@opensolaris.org * this is also a 'primary' adapter, then this is NOT part of 35809860Sgdamore@opensolaris.org * a multiport card, but a second card on the same PCI bus. 35819860Sgdamore@opensolaris.org * BUGID: 4057747 35829860Sgdamore@opensolaris.org */ 35839860Sgdamore@opensolaris.org if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 35849860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, hackintr_propname, 0) != 0) 35859860Sgdamore@opensolaris.org return (0); 35869860Sgdamore@opensolaris.org /* ... Primary not part of a multiport device */ 35879860Sgdamore@opensolaris.org 35889860Sgdamore@opensolaris.org #ifdef DNETDEBUG 35899860Sgdamore@opensolaris.org if (dnetdebug & DNETTRACE) 35909860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "dnet: Implementing hardware " 35919860Sgdamore@opensolaris.org "interrupt flaw workaround"); 35929860Sgdamore@opensolaris.org #endif 35939860Sgdamore@opensolaris.org dnetp->hackintr_inf = hackintr_inf = 35949860Sgdamore@opensolaris.org kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP); 35959860Sgdamore@opensolaris.org if (hackintr_inf == NULL) 35969860Sgdamore@opensolaris.org goto fail; 35979860Sgdamore@opensolaris.org 3598*10340Sstallion@opensolaris.org hackintr_inf->dnetps[0] = dnetp; 35999860Sgdamore@opensolaris.org hackintr_inf->devinfo = devinfo; 36009860Sgdamore@opensolaris.org 36019860Sgdamore@opensolaris.org /* 36029860Sgdamore@opensolaris.org * Add a property to allow successive attaches to find the 36039860Sgdamore@opensolaris.org * table 36049860Sgdamore@opensolaris.org */ 36059860Sgdamore@opensolaris.org 36069860Sgdamore@opensolaris.org if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, 36079860Sgdamore@opensolaris.org ddi_get_parent(devinfo), hackintr_propname, 36089860Sgdamore@opensolaris.org (uchar_t *)&dnetp->hackintr_inf, 36099860Sgdamore@opensolaris.org sizeof (void *)) != DDI_PROP_SUCCESS) 36109860Sgdamore@opensolaris.org goto fail; 36119860Sgdamore@opensolaris.org 36129860Sgdamore@opensolaris.org 36139860Sgdamore@opensolaris.org /* Register our hacked interrupt routine */ 3614*10340Sstallion@opensolaris.org if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL, 36159860Sgdamore@opensolaris.org (uint_t (*)(char *))dnet_hack_intr, 36169860Sgdamore@opensolaris.org (caddr_t)hackintr_inf) != DDI_SUCCESS) { 36179860Sgdamore@opensolaris.org /* XXX function return value ignored */ 36189860Sgdamore@opensolaris.org (void) ddi_prop_remove(DDI_DEV_T_NONE, 36199860Sgdamore@opensolaris.org ddi_get_parent(devinfo), 36209860Sgdamore@opensolaris.org hackintr_propname); 36219860Sgdamore@opensolaris.org goto fail; 36229860Sgdamore@opensolaris.org } 36239860Sgdamore@opensolaris.org 36249860Sgdamore@opensolaris.org /* 36259860Sgdamore@opensolaris.org * Mutex required to ensure interrupt routine has completed 36269860Sgdamore@opensolaris.org * when detaching devices 36279860Sgdamore@opensolaris.org */ 36289860Sgdamore@opensolaris.org mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER, 3629*10340Sstallion@opensolaris.org dnetp->icookie); 36309860Sgdamore@opensolaris.org 36319860Sgdamore@opensolaris.org /* Stop GLD registering an interrupt */ 36329860Sgdamore@opensolaris.org return (-1); 36339860Sgdamore@opensolaris.org } else { 36349860Sgdamore@opensolaris.org 3635*10340Sstallion@opensolaris.org /* Add the dnetp for this secondary device to the table */ 36369860Sgdamore@opensolaris.org 36379860Sgdamore@opensolaris.org hackintr_inf = (struct hackintr_inf *)(uintptr_t) 36389860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 36399860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, hackintr_propname, 0); 36409860Sgdamore@opensolaris.org 36419860Sgdamore@opensolaris.org if (hackintr_inf == NULL) 36429860Sgdamore@opensolaris.org goto fail; 36439860Sgdamore@opensolaris.org 36449860Sgdamore@opensolaris.org /* Find an empty slot */ 36459860Sgdamore@opensolaris.org for (i = 0; i < MAX_INST; i++) 3646*10340Sstallion@opensolaris.org if (hackintr_inf->dnetps[i] == NULL) 36479860Sgdamore@opensolaris.org break; 36489860Sgdamore@opensolaris.org 36499860Sgdamore@opensolaris.org /* More than 8 ports on adapter ?! */ 36509860Sgdamore@opensolaris.org if (i == MAX_INST) 36519860Sgdamore@opensolaris.org goto fail; 36529860Sgdamore@opensolaris.org 3653*10340Sstallion@opensolaris.org hackintr_inf->dnetps[i] = dnetp; 36549860Sgdamore@opensolaris.org 36559860Sgdamore@opensolaris.org /* 36569860Sgdamore@opensolaris.org * Allow GLD to register a handler for this 36579860Sgdamore@opensolaris.org * device. If the card is actually broken, as we suspect, this 36589860Sgdamore@opensolaris.org * handler will never get called. However, by registering the 36599860Sgdamore@opensolaris.org * interrupt handler, we can copy gracefully with new multiport 36609860Sgdamore@opensolaris.org * Cogent cards that decide to fix the hardware problem 36619860Sgdamore@opensolaris.org */ 36629860Sgdamore@opensolaris.org return (0); 36639860Sgdamore@opensolaris.org } 36649860Sgdamore@opensolaris.org 36659860Sgdamore@opensolaris.org fail: 36669860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt" 36679860Sgdamore@opensolaris.org " routing problem"); 36689860Sgdamore@opensolaris.org return (0); 36699860Sgdamore@opensolaris.org } 36709860Sgdamore@opensolaris.org 36719860Sgdamore@opensolaris.org /* 3672*10340Sstallion@opensolaris.org * Call dnet_intr for all adapters on a multiport card 36739860Sgdamore@opensolaris.org */ 36749860Sgdamore@opensolaris.org static uint_t 36759860Sgdamore@opensolaris.org dnet_hack_intr(struct hackintr_inf *hackintr_inf) 36769860Sgdamore@opensolaris.org { 36779860Sgdamore@opensolaris.org int i; 36789860Sgdamore@opensolaris.org int claimed = DDI_INTR_UNCLAIMED; 36799860Sgdamore@opensolaris.org 36809860Sgdamore@opensolaris.org /* Stop detaches while processing interrupts */ 36819860Sgdamore@opensolaris.org mutex_enter(&hackintr_inf->lock); 36829860Sgdamore@opensolaris.org 36839860Sgdamore@opensolaris.org for (i = 0; i < MAX_INST; i++) { 3684*10340Sstallion@opensolaris.org if (hackintr_inf->dnetps[i] && 3685*10340Sstallion@opensolaris.org dnet_intr((caddr_t)hackintr_inf->dnetps[i]) == 3686*10340Sstallion@opensolaris.org DDI_INTR_CLAIMED) { 36879860Sgdamore@opensolaris.org claimed = DDI_INTR_CLAIMED; 3688*10340Sstallion@opensolaris.org } 36899860Sgdamore@opensolaris.org } 36909860Sgdamore@opensolaris.org mutex_exit(&hackintr_inf->lock); 36919860Sgdamore@opensolaris.org return (claimed); 36929860Sgdamore@opensolaris.org } 36939860Sgdamore@opensolaris.org 36949860Sgdamore@opensolaris.org /* 36959860Sgdamore@opensolaris.org * This removes the detaching device from the table procesed by the hacked 36969860Sgdamore@opensolaris.org * interrupt routine. Because the interrupts from all devices come in to the 36979860Sgdamore@opensolaris.org * same interrupt handler, ALL devices must stop interrupting once the 36989860Sgdamore@opensolaris.org * primary device detaches. This isn't a problem at present, because all 36999860Sgdamore@opensolaris.org * instances of a device are detached when the driver is unloaded. 37009860Sgdamore@opensolaris.org */ 37019860Sgdamore@opensolaris.org static int 37029860Sgdamore@opensolaris.org dnet_detach_hacked_interrupt(dev_info_t *devinfo) 37039860Sgdamore@opensolaris.org { 37049860Sgdamore@opensolaris.org int i; 37059860Sgdamore@opensolaris.org struct hackintr_inf *hackintr_inf; 3706*10340Sstallion@opensolaris.org struct dnetinstance *altdnetp, *dnetp = 3707*10340Sstallion@opensolaris.org ddi_get_driver_private(devinfo); 37089860Sgdamore@opensolaris.org 37099860Sgdamore@opensolaris.org hackintr_inf = (struct hackintr_inf *)(uintptr_t) 37109860Sgdamore@opensolaris.org ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 37119860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, hackintr_propname, 0); 37129860Sgdamore@opensolaris.org 37139860Sgdamore@opensolaris.org /* 37149860Sgdamore@opensolaris.org * No hackintr_inf implies hack was not required or the primary has 37159860Sgdamore@opensolaris.org * detached, and our interrupts are already disabled 37169860Sgdamore@opensolaris.org */ 37179860Sgdamore@opensolaris.org if (!hackintr_inf) { 37189860Sgdamore@opensolaris.org /* remove the interrupt for the non-hacked case */ 3719*10340Sstallion@opensolaris.org ddi_remove_intr(devinfo, 0, dnetp->icookie); 37209860Sgdamore@opensolaris.org return (DDI_SUCCESS); 37219860Sgdamore@opensolaris.org } 37229860Sgdamore@opensolaris.org 37239860Sgdamore@opensolaris.org /* Remove this device from the handled table */ 37249860Sgdamore@opensolaris.org mutex_enter(&hackintr_inf->lock); 37259860Sgdamore@opensolaris.org for (i = 0; i < MAX_INST; i++) { 3726*10340Sstallion@opensolaris.org if (hackintr_inf->dnetps[i] == dnetp) { 3727*10340Sstallion@opensolaris.org hackintr_inf->dnetps[i] = NULL; 37289860Sgdamore@opensolaris.org break; 37299860Sgdamore@opensolaris.org } 37309860Sgdamore@opensolaris.org } 37319860Sgdamore@opensolaris.org 37329860Sgdamore@opensolaris.org mutex_exit(&hackintr_inf->lock); 37339860Sgdamore@opensolaris.org 37349860Sgdamore@opensolaris.org /* Not the primary card, we are done */ 37359860Sgdamore@opensolaris.org if (devinfo != hackintr_inf->devinfo) 37369860Sgdamore@opensolaris.org return (DDI_SUCCESS); 37379860Sgdamore@opensolaris.org 37389860Sgdamore@opensolaris.org /* 37399860Sgdamore@opensolaris.org * This is the primary card. All remaining adapters on this device 37409860Sgdamore@opensolaris.org * must have their interrupts disabled before we remove the handler 37419860Sgdamore@opensolaris.org */ 37429860Sgdamore@opensolaris.org for (i = 0; i < MAX_INST; i++) { 3743*10340Sstallion@opensolaris.org if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) { 37449860Sgdamore@opensolaris.org altdnetp->interrupts_disabled = 1; 37459860Sgdamore@opensolaris.org ddi_put32(altdnetp->io_handle, 37469860Sgdamore@opensolaris.org REG32(altdnetp->io_reg, INT_MASK_REG), 0); 37479860Sgdamore@opensolaris.org } 37489860Sgdamore@opensolaris.org } 37499860Sgdamore@opensolaris.org 37509860Sgdamore@opensolaris.org /* It should now be safe to remove the interrupt handler */ 37519860Sgdamore@opensolaris.org 3752*10340Sstallion@opensolaris.org ddi_remove_intr(devinfo, 0, dnetp->icookie); 37539860Sgdamore@opensolaris.org mutex_destroy(&hackintr_inf->lock); 37549860Sgdamore@opensolaris.org /* XXX function return value ignored */ 37559860Sgdamore@opensolaris.org (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 37569860Sgdamore@opensolaris.org hackintr_propname); 37579860Sgdamore@opensolaris.org kmem_free(hackintr_inf, sizeof (struct hackintr_inf)); 37589860Sgdamore@opensolaris.org return (DDI_SUCCESS); 37599860Sgdamore@opensolaris.org } 37609860Sgdamore@opensolaris.org 37619860Sgdamore@opensolaris.org /* do_phy() - called with intrlock held */ 37629860Sgdamore@opensolaris.org static void 3763*10340Sstallion@opensolaris.org do_phy(struct dnetinstance *dnetp) 37649860Sgdamore@opensolaris.org { 37659860Sgdamore@opensolaris.org dev_info_t *dip; 37669860Sgdamore@opensolaris.org LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf; 37679860Sgdamore@opensolaris.org media_block_t *block; 37689860Sgdamore@opensolaris.org int phy; 37699860Sgdamore@opensolaris.org 37709860Sgdamore@opensolaris.org dip = dnetp->devinfo; 37719860Sgdamore@opensolaris.org 37729860Sgdamore@opensolaris.org /* 37739860Sgdamore@opensolaris.org * Find and configure the PHY media block. If NO PHY blocks are 37749860Sgdamore@opensolaris.org * found on the SROM, but a PHY device is present, we assume the card 37759860Sgdamore@opensolaris.org * is a legacy device, and that there is ONLY a PHY interface on the 37769860Sgdamore@opensolaris.org * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY 37779860Sgdamore@opensolaris.org */ 37789860Sgdamore@opensolaris.org 37799860Sgdamore@opensolaris.org for (block = leaf->block + leaf->block_count -1; 37809860Sgdamore@opensolaris.org block >= leaf->block; block --) { 37819860Sgdamore@opensolaris.org if (block->type == 3 || block->type == 1) { 37829860Sgdamore@opensolaris.org leaf->mii_block = block; 37839860Sgdamore@opensolaris.org break; 37849860Sgdamore@opensolaris.org } 37859860Sgdamore@opensolaris.org } 37869860Sgdamore@opensolaris.org 37879860Sgdamore@opensolaris.org /* 37889860Sgdamore@opensolaris.org * If no MII block, select default, and hope this configuration will 37899860Sgdamore@opensolaris.org * allow the phy to be read/written if it is present 37909860Sgdamore@opensolaris.org */ 37919860Sgdamore@opensolaris.org dnetp->selected_media_block = leaf->mii_block ? 37929860Sgdamore@opensolaris.org leaf->mii_block : leaf->default_block; 37939860Sgdamore@opensolaris.org 3794*10340Sstallion@opensolaris.org setup_block(dnetp); 37959860Sgdamore@opensolaris.org /* XXX function return value ignored */ 37969860Sgdamore@opensolaris.org (void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii); 37979860Sgdamore@opensolaris.org 37989860Sgdamore@opensolaris.org /* 37999860Sgdamore@opensolaris.org * We try PHY 0 LAST because it is less likely to be connected 38009860Sgdamore@opensolaris.org */ 38019860Sgdamore@opensolaris.org for (phy = 1; phy < 33; phy++) 38029860Sgdamore@opensolaris.org if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS && 38039860Sgdamore@opensolaris.org mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) { 38049860Sgdamore@opensolaris.org #ifdef DNETDEBUG 38059860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 38069860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "dnet: " 38079860Sgdamore@opensolaris.org "PHY at address %d", phy % 32); 38089860Sgdamore@opensolaris.org #endif 38099860Sgdamore@opensolaris.org dnetp->phyaddr = phy % 32; 38109860Sgdamore@opensolaris.org if (!leaf->mii_block) { 38119860Sgdamore@opensolaris.org /* Legacy card, change the leaf node */ 38129860Sgdamore@opensolaris.org set_leaf(&dnetp->sr, &leaf_phylegacy); 38139860Sgdamore@opensolaris.org } 38149860Sgdamore@opensolaris.org return; 38159860Sgdamore@opensolaris.org } 38169860Sgdamore@opensolaris.org #ifdef DNETDEBUG 38179860Sgdamore@opensolaris.org if (dnetdebug & DNETSENSE) 38189860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "dnet: No PHY found"); 38199860Sgdamore@opensolaris.org #endif 38209860Sgdamore@opensolaris.org } 38219860Sgdamore@opensolaris.org 38229860Sgdamore@opensolaris.org static ushort_t 38239860Sgdamore@opensolaris.org dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num) 38249860Sgdamore@opensolaris.org { 38259860Sgdamore@opensolaris.org struct dnetinstance *dnetp; 38269860Sgdamore@opensolaris.org 38279860Sgdamore@opensolaris.org uint32_t command_word; 38289860Sgdamore@opensolaris.org uint32_t tmp; 38299860Sgdamore@opensolaris.org uint32_t data = 0; 38309860Sgdamore@opensolaris.org int i; 38319860Sgdamore@opensolaris.org int bits_in_ushort = ((sizeof (ushort_t))*8); 38329860Sgdamore@opensolaris.org int turned_around = 0; 38339860Sgdamore@opensolaris.org 3834*10340Sstallion@opensolaris.org dnetp = ddi_get_driver_private(dip); 38359860Sgdamore@opensolaris.org 38369860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 38379860Sgdamore@opensolaris.org /* Write Preamble */ 38389860Sgdamore@opensolaris.org write_mii(dnetp, MII_PRE, 2*bits_in_ushort); 38399860Sgdamore@opensolaris.org 38409860Sgdamore@opensolaris.org /* Prepare command word */ 38419860Sgdamore@opensolaris.org command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN; 38429860Sgdamore@opensolaris.org command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN; 38439860Sgdamore@opensolaris.org command_word |= MII_READ_FRAME; 38449860Sgdamore@opensolaris.org 38459860Sgdamore@opensolaris.org write_mii(dnetp, command_word, bits_in_ushort-2); 38469860Sgdamore@opensolaris.org 38479860Sgdamore@opensolaris.org mii_tristate(dnetp); 38489860Sgdamore@opensolaris.org 38499860Sgdamore@opensolaris.org /* Check that the PHY generated a zero bit the 2nd clock */ 38509860Sgdamore@opensolaris.org tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG)); 38519860Sgdamore@opensolaris.org 38529860Sgdamore@opensolaris.org turned_around = (tmp & MII_DATA_IN) ? 0 : 1; 38539860Sgdamore@opensolaris.org 38549860Sgdamore@opensolaris.org /* read data WORD */ 38559860Sgdamore@opensolaris.org for (i = 0; i < bits_in_ushort; i++) { 38569860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 38579860Sgdamore@opensolaris.org REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ); 38589860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 38599860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 38609860Sgdamore@opensolaris.org REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK); 38619860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 38629860Sgdamore@opensolaris.org tmp = ddi_get32(dnetp->io_handle, 38639860Sgdamore@opensolaris.org REG32(dnetp->io_reg, ETHER_ROM_REG)); 38649860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 38659860Sgdamore@opensolaris.org data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001; 38669860Sgdamore@opensolaris.org } 38679860Sgdamore@opensolaris.org 38689860Sgdamore@opensolaris.org mii_tristate(dnetp); 38699860Sgdamore@opensolaris.org return (turned_around ? data: -1); 38709860Sgdamore@opensolaris.org } 38719860Sgdamore@opensolaris.org 38729860Sgdamore@opensolaris.org static void 38739860Sgdamore@opensolaris.org dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat) 38749860Sgdamore@opensolaris.org { 38759860Sgdamore@opensolaris.org struct dnetinstance *dnetp; 38769860Sgdamore@opensolaris.org uint32_t command_word; 38779860Sgdamore@opensolaris.org int bits_in_ushort = ((sizeof (ushort_t))*8); 38789860Sgdamore@opensolaris.org 3879*10340Sstallion@opensolaris.org dnetp = ddi_get_driver_private(dip); 38809860Sgdamore@opensolaris.org 38819860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 38829860Sgdamore@opensolaris.org write_mii(dnetp, MII_PRE, 2*bits_in_ushort); 38839860Sgdamore@opensolaris.org 38849860Sgdamore@opensolaris.org /* Prepare command word */ 38859860Sgdamore@opensolaris.org command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN); 38869860Sgdamore@opensolaris.org command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN); 38879860Sgdamore@opensolaris.org command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat); 38889860Sgdamore@opensolaris.org 38899860Sgdamore@opensolaris.org write_mii(dnetp, command_word, 2*bits_in_ushort); 38909860Sgdamore@opensolaris.org mii_tristate(dnetp); 38919860Sgdamore@opensolaris.org } 38929860Sgdamore@opensolaris.org 38939860Sgdamore@opensolaris.org /* 38949860Sgdamore@opensolaris.org * Write data size bits from mii_data to the MII control lines. 38959860Sgdamore@opensolaris.org */ 38969860Sgdamore@opensolaris.org static void 38979860Sgdamore@opensolaris.org write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size) 38989860Sgdamore@opensolaris.org { 38999860Sgdamore@opensolaris.org int i; 39009860Sgdamore@opensolaris.org uint32_t dbit; 39019860Sgdamore@opensolaris.org 39029860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 39039860Sgdamore@opensolaris.org for (i = data_size; i > 0; i--) { 39049860Sgdamore@opensolaris.org dbit = ((mii_data >> 39059860Sgdamore@opensolaris.org (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA); 39069860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 39079860Sgdamore@opensolaris.org REG32(dnetp->io_reg, ETHER_ROM_REG), 39089860Sgdamore@opensolaris.org MII_WRITE | dbit); 39099860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 39109860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, 39119860Sgdamore@opensolaris.org REG32(dnetp->io_reg, ETHER_ROM_REG), 39129860Sgdamore@opensolaris.org MII_WRITE | MII_CLOCK | dbit); 39139860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 39149860Sgdamore@opensolaris.org mii_data <<= 1; 39159860Sgdamore@opensolaris.org } 39169860Sgdamore@opensolaris.org } 39179860Sgdamore@opensolaris.org 39189860Sgdamore@opensolaris.org /* 39199860Sgdamore@opensolaris.org * Put the MDIO port in tri-state for the turn around bits 39209860Sgdamore@opensolaris.org * in MII read and at end of MII management sequence. 39219860Sgdamore@opensolaris.org */ 39229860Sgdamore@opensolaris.org static void 39239860Sgdamore@opensolaris.org mii_tristate(struct dnetinstance *dnetp) 39249860Sgdamore@opensolaris.org { 39259860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 39269860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG), 39279860Sgdamore@opensolaris.org MII_WRITE_TS); 39289860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 39299860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG), 39309860Sgdamore@opensolaris.org MII_WRITE_TS | MII_CLOCK); 39319860Sgdamore@opensolaris.org drv_usecwait(MII_DELAY); 39329860Sgdamore@opensolaris.org } 39339860Sgdamore@opensolaris.org 39349860Sgdamore@opensolaris.org 39359860Sgdamore@opensolaris.org static void 39369860Sgdamore@opensolaris.org set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf) 39379860Sgdamore@opensolaris.org { 39389860Sgdamore@opensolaris.org if (sr->leaf && !sr->leaf->is_static) 39399860Sgdamore@opensolaris.org kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT)); 39409860Sgdamore@opensolaris.org sr->leaf = leaf; 39419860Sgdamore@opensolaris.org } 39429860Sgdamore@opensolaris.org 39439860Sgdamore@opensolaris.org /* 39449860Sgdamore@opensolaris.org * Callback from MII module. Makes sure that the CSR registers are 39459860Sgdamore@opensolaris.org * configured properly if the PHY changes mode. 39469860Sgdamore@opensolaris.org */ 39479860Sgdamore@opensolaris.org /* ARGSUSED */ 39489860Sgdamore@opensolaris.org /* dnet_mii_link_cb - called with intrlock held */ 39499860Sgdamore@opensolaris.org static void 39509860Sgdamore@opensolaris.org dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state) 39519860Sgdamore@opensolaris.org { 3952*10340Sstallion@opensolaris.org struct dnetinstance *dnetp = ddi_get_driver_private(dip); 39539860Sgdamore@opensolaris.org LEAF_FORMAT *leaf; 39549860Sgdamore@opensolaris.org 39559860Sgdamore@opensolaris.org ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3956*10340Sstallion@opensolaris.org 39579860Sgdamore@opensolaris.org leaf = dnetp->sr.leaf + dnetp->leaf; 39589860Sgdamore@opensolaris.org if (state == phy_state_linkup) { 39599860Sgdamore@opensolaris.org dnetp->mii_up = 1; 3960*10340Sstallion@opensolaris.org 3961*10340Sstallion@opensolaris.org (void) mii_getspeed(dnetp->mii, dnetp->phyaddr, 3962*10340Sstallion@opensolaris.org &dnetp->mii_speed, &dnetp->mii_duplex); 3963*10340Sstallion@opensolaris.org 39649860Sgdamore@opensolaris.org dnetp->selected_media_block = leaf->mii_block; 3965*10340Sstallion@opensolaris.org setup_block(dnetp); 39669860Sgdamore@opensolaris.org } else { 39679860Sgdamore@opensolaris.org /* NEEDSWORK: Probably can call find_active_media here */ 39689860Sgdamore@opensolaris.org dnetp->mii_up = 0; 3969*10340Sstallion@opensolaris.org 3970*10340Sstallion@opensolaris.org if (leaf->default_block->media_code == MEDIA_MII) 3971*10340Sstallion@opensolaris.org dnetp->selected_media_block = leaf->default_block; 3972*10340Sstallion@opensolaris.org setup_block(dnetp); 3973*10340Sstallion@opensolaris.org } 3974*10340Sstallion@opensolaris.org dnet_mii_link_up(dnetp); 3975*10340Sstallion@opensolaris.org } 3976*10340Sstallion@opensolaris.org 3977*10340Sstallion@opensolaris.org static void 3978*10340Sstallion@opensolaris.org dnet_mii_link_up(struct dnetinstance *dnetp) 3979*10340Sstallion@opensolaris.org { 3980*10340Sstallion@opensolaris.org if (!dnetp->running) { 3981*10340Sstallion@opensolaris.org return; 3982*10340Sstallion@opensolaris.org } 3983*10340Sstallion@opensolaris.org 3984*10340Sstallion@opensolaris.org if (dnetp->mii_up) { 3985*10340Sstallion@opensolaris.org (void) mii_getspeed(dnetp->mii, dnetp->phyaddr, 3986*10340Sstallion@opensolaris.org &dnetp->mii_speed, &dnetp->mii_duplex); 3987*10340Sstallion@opensolaris.org 3988*10340Sstallion@opensolaris.org mac_link_update(dnetp->mac_handle, LINK_STATE_UP); 3989*10340Sstallion@opensolaris.org 3990*10340Sstallion@opensolaris.org } else { 39919860Sgdamore@opensolaris.org dnetp->mii_speed = 0; 39929860Sgdamore@opensolaris.org dnetp->mii_duplex = 0; 3993*10340Sstallion@opensolaris.org 3994*10340Sstallion@opensolaris.org mac_link_update(dnetp->mac_handle, LINK_STATE_DOWN); 39959860Sgdamore@opensolaris.org } 39969860Sgdamore@opensolaris.org } 39979860Sgdamore@opensolaris.org 39989860Sgdamore@opensolaris.org /* 39999860Sgdamore@opensolaris.org * SROM parsing routines. 40009860Sgdamore@opensolaris.org * Refer to the Digital 3.03 SROM spec while reading this! (references refer 40019860Sgdamore@opensolaris.org * to this document) 40029860Sgdamore@opensolaris.org * Where possible ALL vendor specific changes should be localised here. The 40039860Sgdamore@opensolaris.org * SROM data should be capable of describing any programmatic irregularities 40049860Sgdamore@opensolaris.org * of DNET cards (via SIA or GP registers, in particular), so vendor specific 40059860Sgdamore@opensolaris.org * code elsewhere should not be required 40069860Sgdamore@opensolaris.org */ 40079860Sgdamore@opensolaris.org static void 40089860Sgdamore@opensolaris.org dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi) 40099860Sgdamore@opensolaris.org { 40109860Sgdamore@opensolaris.org uint32_t ether_mfg = 0; 40119860Sgdamore@opensolaris.org int i; 40129860Sgdamore@opensolaris.org uchar_t *p; 40139860Sgdamore@opensolaris.org 40149860Sgdamore@opensolaris.org if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 40159860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, "no_sromconfig", 0)) 40169860Sgdamore@opensolaris.org dnetp->sr.init_from_srom = check_srom_valid(vi); 40179860Sgdamore@opensolaris.org 40189860Sgdamore@opensolaris.org if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) { 40199860Sgdamore@opensolaris.org /* Section 2/3: General SROM Format/ ID Block */ 40209860Sgdamore@opensolaris.org p = vi+18; 40219860Sgdamore@opensolaris.org sr->version = *p++; 40229860Sgdamore@opensolaris.org sr->adapters = *p++; 40239860Sgdamore@opensolaris.org 40249860Sgdamore@opensolaris.org sr->leaf = 40259860Sgdamore@opensolaris.org kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP); 40269860Sgdamore@opensolaris.org for (i = 0; i < 6; i++) 40279860Sgdamore@opensolaris.org sr->netaddr[i] = *p++; 40289860Sgdamore@opensolaris.org 40299860Sgdamore@opensolaris.org for (i = 0; i < sr->adapters; i++) { 40309860Sgdamore@opensolaris.org uchar_t devno = *p++; 40319860Sgdamore@opensolaris.org uint16_t offset = *p++; 40329860Sgdamore@opensolaris.org offset |= *p++ << 8; 40339860Sgdamore@opensolaris.org sr->leaf[i].device_number = devno; 40349860Sgdamore@opensolaris.org parse_controller_leaf(dnetp, sr->leaf+i, vi+offset); 40359860Sgdamore@opensolaris.org } 40369860Sgdamore@opensolaris.org /* 40379860Sgdamore@opensolaris.org * 'Orrible hack for cogent cards. The 6911A board seems to 40389860Sgdamore@opensolaris.org * have an incorrect SROM. (From the OEMDEMO program 40399860Sgdamore@opensolaris.org * supplied by cogent, it seems that the ROM matches a setup 40409860Sgdamore@opensolaris.org * or a board with a QSI or ICS PHY. 40419860Sgdamore@opensolaris.org */ 40429860Sgdamore@opensolaris.org for (i = 0; i < 3; i++) 40439860Sgdamore@opensolaris.org ether_mfg = (ether_mfg << 8) | sr->netaddr[i]; 40449860Sgdamore@opensolaris.org 40459860Sgdamore@opensolaris.org if (ether_mfg == ADAPTEC_ETHER) { 40469860Sgdamore@opensolaris.org static uint16_t cogent_gprseq[] = {0x821, 0}; 40479860Sgdamore@opensolaris.org switch (vi[COGENT_SROM_ID]) { 40489860Sgdamore@opensolaris.org case COGENT_ANA6911A_C: 40499860Sgdamore@opensolaris.org case COGENT_ANA6911AC_C: 40509860Sgdamore@opensolaris.org #ifdef DNETDEBUG 40519860Sgdamore@opensolaris.org if (dnetdebug & DNETTRACE) 40529860Sgdamore@opensolaris.org cmn_err(CE_WARN, 40539860Sgdamore@opensolaris.org "Suspected bad GPR sequence." 40549860Sgdamore@opensolaris.org " Making a guess (821,0)"); 40559860Sgdamore@opensolaris.org #endif 40569860Sgdamore@opensolaris.org 40579860Sgdamore@opensolaris.org /* XXX function return value ignored */ 40589860Sgdamore@opensolaris.org (void) ddi_prop_update_byte_array( 40599860Sgdamore@opensolaris.org DDI_DEV_T_NONE, dnetp->devinfo, 40609860Sgdamore@opensolaris.org "gpr-sequence", (uchar_t *)cogent_gprseq, 40619860Sgdamore@opensolaris.org sizeof (cogent_gprseq)); 40629860Sgdamore@opensolaris.org break; 40639860Sgdamore@opensolaris.org } 40649860Sgdamore@opensolaris.org } 40659860Sgdamore@opensolaris.org } else { 40669860Sgdamore@opensolaris.org /* 40679860Sgdamore@opensolaris.org * Adhoc SROM, check for some cards which need special handling 40689860Sgdamore@opensolaris.org * Assume vendor info contains ether address in first six bytes 40699860Sgdamore@opensolaris.org */ 40709860Sgdamore@opensolaris.org 40719860Sgdamore@opensolaris.org uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 40729860Sgdamore@opensolaris.org DDI_PROP_DONTPASS, macoffset_propname, 0); 40739860Sgdamore@opensolaris.org 40749860Sgdamore@opensolaris.org for (i = 0; i < 6; i++) 40759860Sgdamore@opensolaris.org sr->netaddr[i] = mac[i]; 40769860Sgdamore@opensolaris.org 40779860Sgdamore@opensolaris.org if (dnetp->board_type == DEVICE_ID_21140) { 40789860Sgdamore@opensolaris.org for (i = 0; i < 3; i++) 40799860Sgdamore@opensolaris.org ether_mfg = (ether_mfg << 8) | mac[i]; 40809860Sgdamore@opensolaris.org 40819860Sgdamore@opensolaris.org switch (ether_mfg) { 40829860Sgdamore@opensolaris.org case ASANTE_ETHER: 40839860Sgdamore@opensolaris.org dnetp->vendor_21140 = ASANTE_TYPE; 40849860Sgdamore@opensolaris.org dnetp->vendor_revision = 0; 40859860Sgdamore@opensolaris.org set_leaf(sr, &leaf_asante); 40869860Sgdamore@opensolaris.org sr->adapters = 1; 40879860Sgdamore@opensolaris.org break; 40889860Sgdamore@opensolaris.org 40899860Sgdamore@opensolaris.org case COGENT_ETHER: 40909860Sgdamore@opensolaris.org case ADAPTEC_ETHER: 40919860Sgdamore@opensolaris.org dnetp->vendor_21140 = COGENT_EM_TYPE; 40929860Sgdamore@opensolaris.org dnetp->vendor_revision = 40939860Sgdamore@opensolaris.org vi[VENDOR_REVISION_OFFSET]; 40949860Sgdamore@opensolaris.org set_leaf(sr, &leaf_cogent_100); 40959860Sgdamore@opensolaris.org sr->adapters = 1; 40969860Sgdamore@opensolaris.org break; 40979860Sgdamore@opensolaris.org 40989860Sgdamore@opensolaris.org default: 40999860Sgdamore@opensolaris.org dnetp->vendor_21140 = DEFAULT_TYPE; 41009860Sgdamore@opensolaris.org dnetp->vendor_revision = 0; 41019860Sgdamore@opensolaris.org set_leaf(sr, &leaf_default_100); 41029860Sgdamore@opensolaris.org sr->adapters = 1; 41039860Sgdamore@opensolaris.org break; 41049860Sgdamore@opensolaris.org } 41059860Sgdamore@opensolaris.org } else if (dnetp->board_type == DEVICE_ID_21041) { 41069860Sgdamore@opensolaris.org set_leaf(sr, &leaf_21041); 41079860Sgdamore@opensolaris.org } else if (dnetp->board_type == DEVICE_ID_21040) { 41089860Sgdamore@opensolaris.org set_leaf(sr, &leaf_21040); 41099860Sgdamore@opensolaris.org } 41109860Sgdamore@opensolaris.org } 41119860Sgdamore@opensolaris.org } 41129860Sgdamore@opensolaris.org 41139860Sgdamore@opensolaris.org /* Section 4.2, 4.3, 4.4, 4.5 */ 41149860Sgdamore@opensolaris.org static void 41159860Sgdamore@opensolaris.org parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf, 41169860Sgdamore@opensolaris.org uchar_t *vi) 41179860Sgdamore@opensolaris.org { 41189860Sgdamore@opensolaris.org int i; 41199860Sgdamore@opensolaris.org 41209860Sgdamore@opensolaris.org leaf->selected_contype = *vi++; 41219860Sgdamore@opensolaris.org leaf->selected_contype |= *vi++ << 8; 41229860Sgdamore@opensolaris.org 41239860Sgdamore@opensolaris.org if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */ 41249860Sgdamore@opensolaris.org leaf->gpr = *vi++; 41259860Sgdamore@opensolaris.org 41269860Sgdamore@opensolaris.org leaf->block_count = *vi++; 41279860Sgdamore@opensolaris.org 41289860Sgdamore@opensolaris.org if (leaf->block_count > MAX_MEDIA) { 41299860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet: Too many media in SROM!"); 41309860Sgdamore@opensolaris.org leaf->block_count = 1; 41319860Sgdamore@opensolaris.org } 41329860Sgdamore@opensolaris.org for (i = 0; i <= leaf->block_count; i++) { 41339860Sgdamore@opensolaris.org vi = parse_media_block(dnetp, leaf->block + i, vi); 41349860Sgdamore@opensolaris.org if (leaf->block[i].command & CMD_DEFAULT_MEDIUM) 41359860Sgdamore@opensolaris.org leaf->default_block = leaf->block+i; 41369860Sgdamore@opensolaris.org } 41379860Sgdamore@opensolaris.org /* No explicit default block: use last in the ROM */ 41389860Sgdamore@opensolaris.org if (leaf->default_block == NULL) 41399860Sgdamore@opensolaris.org leaf->default_block = leaf->block + leaf->block_count -1; 41409860Sgdamore@opensolaris.org 41419860Sgdamore@opensolaris.org } 41429860Sgdamore@opensolaris.org 41439860Sgdamore@opensolaris.org static uchar_t * 41449860Sgdamore@opensolaris.org parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi) 41459860Sgdamore@opensolaris.org { 41469860Sgdamore@opensolaris.org int i; 41479860Sgdamore@opensolaris.org 41489860Sgdamore@opensolaris.org /* 41499860Sgdamore@opensolaris.org * There are three kinds of media block we need to worry about: 41509860Sgdamore@opensolaris.org * The 21041 blocks. 41519860Sgdamore@opensolaris.org * 21140 blocks from a version 1 SROM 41529860Sgdamore@opensolaris.org * 2114[023] block from a version 3 SROM 41539860Sgdamore@opensolaris.org */ 41549860Sgdamore@opensolaris.org 41559860Sgdamore@opensolaris.org if (dnetp->board_type == DEVICE_ID_21041) { 41569860Sgdamore@opensolaris.org /* Section 4.2 */ 41579860Sgdamore@opensolaris.org block->media_code = *vi & 0x3f; 41589860Sgdamore@opensolaris.org block->type = 2; 41599860Sgdamore@opensolaris.org if (*vi++ & 0x40) { 41609860Sgdamore@opensolaris.org block->un.sia.csr13 = *vi++; 41619860Sgdamore@opensolaris.org block->un.sia.csr13 |= *vi++ << 8; 41629860Sgdamore@opensolaris.org block->un.sia.csr14 = *vi++; 41639860Sgdamore@opensolaris.org block->un.sia.csr14 |= *vi++ << 8; 41649860Sgdamore@opensolaris.org block->un.sia.csr15 = *vi++; 41659860Sgdamore@opensolaris.org block->un.sia.csr15 |= *vi++ << 8; 41669860Sgdamore@opensolaris.org } else { 41679860Sgdamore@opensolaris.org /* No media data (csrs 13,14,15). Insert defaults */ 41689860Sgdamore@opensolaris.org switch (block->media_code) { 41699860Sgdamore@opensolaris.org case MEDIA_TP: 41709860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef01; 41719860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3f; 41729860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 41739860Sgdamore@opensolaris.org break; 41749860Sgdamore@opensolaris.org case MEDIA_TP_FD: 41759860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef01; 41769860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3d; 41779860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 41789860Sgdamore@opensolaris.org break; 41799860Sgdamore@opensolaris.org case MEDIA_BNC: 41809860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef09; 41819860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 41829860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0006; 41839860Sgdamore@opensolaris.org break; 41849860Sgdamore@opensolaris.org case MEDIA_AUI: 41859860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef09; 41869860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 41879860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x000e; 41889860Sgdamore@opensolaris.org break; 41899860Sgdamore@opensolaris.org } 41909860Sgdamore@opensolaris.org } 41919860Sgdamore@opensolaris.org } else if (*vi & 0x80) { /* Extended format: Section 4.3.2.2 */ 41929860Sgdamore@opensolaris.org int blocklen = *vi++ & 0x7f; 41939860Sgdamore@opensolaris.org block->type = *vi++; 41949860Sgdamore@opensolaris.org switch (block->type) { 41959860Sgdamore@opensolaris.org case 0: /* "non-MII": Section 4.3.2.2.1 */ 41969860Sgdamore@opensolaris.org block->media_code = (*vi++) & 0x3f; 41979860Sgdamore@opensolaris.org block->gprseqlen = 1; 41989860Sgdamore@opensolaris.org block->gprseq[0] = *vi++; 41999860Sgdamore@opensolaris.org block->command = *vi++; 42009860Sgdamore@opensolaris.org block->command |= *vi++ << 8; 42019860Sgdamore@opensolaris.org break; 42029860Sgdamore@opensolaris.org 42039860Sgdamore@opensolaris.org case 1: /* MII/PHY: Section 4.3.2.2.2 */ 42049860Sgdamore@opensolaris.org block->command = CMD_PS; 42059860Sgdamore@opensolaris.org block->media_code = MEDIA_MII; 42069860Sgdamore@opensolaris.org /* This is whats needed in CSR6 */ 42079860Sgdamore@opensolaris.org 42089860Sgdamore@opensolaris.org block->un.mii.phy_num = *vi++; 42099860Sgdamore@opensolaris.org block->gprseqlen = *vi++; 42109860Sgdamore@opensolaris.org 42119860Sgdamore@opensolaris.org for (i = 0; i < block->gprseqlen; i++) 42129860Sgdamore@opensolaris.org block->gprseq[i] = *vi++; 42139860Sgdamore@opensolaris.org block->rstseqlen = *vi++; 42149860Sgdamore@opensolaris.org for (i = 0; i < block->rstseqlen; i++) 42159860Sgdamore@opensolaris.org block->rstseq[i] = *vi++; 42169860Sgdamore@opensolaris.org 42179860Sgdamore@opensolaris.org block->un.mii.mediacaps = *vi++; 42189860Sgdamore@opensolaris.org block->un.mii.mediacaps |= *vi++ << 8; 42199860Sgdamore@opensolaris.org block->un.mii.nwayadvert = *vi++; 42209860Sgdamore@opensolaris.org block->un.mii.nwayadvert |= *vi++ << 8; 42219860Sgdamore@opensolaris.org block->un.mii.fdxmask = *vi++; 42229860Sgdamore@opensolaris.org block->un.mii.fdxmask |= *vi++ << 8; 42239860Sgdamore@opensolaris.org block->un.mii.ttmmask = *vi++; 42249860Sgdamore@opensolaris.org block->un.mii.ttmmask |= *vi++ << 8; 42259860Sgdamore@opensolaris.org break; 42269860Sgdamore@opensolaris.org 42279860Sgdamore@opensolaris.org case 2: /* SIA Media: Section 4.4.2.1.1 */ 42289860Sgdamore@opensolaris.org block->media_code = *vi & 0x3f; 42299860Sgdamore@opensolaris.org if (*vi++ & 0x40) { 42309860Sgdamore@opensolaris.org block->un.sia.csr13 = *vi++; 42319860Sgdamore@opensolaris.org block->un.sia.csr13 |= *vi++ << 8; 42329860Sgdamore@opensolaris.org block->un.sia.csr14 = *vi++; 42339860Sgdamore@opensolaris.org block->un.sia.csr14 |= *vi++ << 8; 42349860Sgdamore@opensolaris.org block->un.sia.csr15 = *vi++; 42359860Sgdamore@opensolaris.org block->un.sia.csr15 |= *vi++ << 8; 42369860Sgdamore@opensolaris.org } else { 42379860Sgdamore@opensolaris.org /* 42389860Sgdamore@opensolaris.org * SIA values not provided by SROM; provide 42399860Sgdamore@opensolaris.org * defaults. See appendix D of 2114[23] manuals. 42409860Sgdamore@opensolaris.org */ 42419860Sgdamore@opensolaris.org switch (block->media_code) { 42429860Sgdamore@opensolaris.org case MEDIA_BNC: 42439860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0009; 42449860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 42459860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0000; 42469860Sgdamore@opensolaris.org break; 42479860Sgdamore@opensolaris.org case MEDIA_AUI: 42489860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0009; 42499860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 42509860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 42519860Sgdamore@opensolaris.org break; 42529860Sgdamore@opensolaris.org case MEDIA_TP: 42539860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0001; 42549860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3f; 42559860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0000; 42569860Sgdamore@opensolaris.org break; 42579860Sgdamore@opensolaris.org case MEDIA_TP_FD: 42589860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0001; 42599860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3d; 42609860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0000; 42619860Sgdamore@opensolaris.org break; 42629860Sgdamore@opensolaris.org default: 42639860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0000; 42649860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0000; 42659860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0000; 42669860Sgdamore@opensolaris.org } 42679860Sgdamore@opensolaris.org } 42689860Sgdamore@opensolaris.org 42699860Sgdamore@opensolaris.org /* Treat GP control/data as a GPR sequence */ 42709860Sgdamore@opensolaris.org block->gprseqlen = 2; 42719860Sgdamore@opensolaris.org block->gprseq[0] = *vi++; 42729860Sgdamore@opensolaris.org block->gprseq[0] |= *vi++ << 8; 42739860Sgdamore@opensolaris.org block->gprseq[0] |= GPR_CONTROL_WRITE; 42749860Sgdamore@opensolaris.org block->gprseq[1] = *vi++; 42759860Sgdamore@opensolaris.org block->gprseq[1] |= *vi++ << 8; 42769860Sgdamore@opensolaris.org break; 42779860Sgdamore@opensolaris.org 42789860Sgdamore@opensolaris.org case 3: /* MII/PHY : Section 4.4.2.1.2 */ 42799860Sgdamore@opensolaris.org block->command = CMD_PS; 42809860Sgdamore@opensolaris.org block->media_code = MEDIA_MII; 42819860Sgdamore@opensolaris.org block->un.mii.phy_num = *vi++; 42829860Sgdamore@opensolaris.org 42839860Sgdamore@opensolaris.org block->gprseqlen = *vi++; 42849860Sgdamore@opensolaris.org for (i = 0; i < block->gprseqlen; i++) { 42859860Sgdamore@opensolaris.org block->gprseq[i] = *vi++; 42869860Sgdamore@opensolaris.org block->gprseq[i] |= *vi++ << 8; 42879860Sgdamore@opensolaris.org } 42889860Sgdamore@opensolaris.org 42899860Sgdamore@opensolaris.org block->rstseqlen = *vi++; 42909860Sgdamore@opensolaris.org for (i = 0; i < block->rstseqlen; i++) { 42919860Sgdamore@opensolaris.org block->rstseq[i] = *vi++; 42929860Sgdamore@opensolaris.org block->rstseq[i] |= *vi++ << 8; 42939860Sgdamore@opensolaris.org } 42949860Sgdamore@opensolaris.org block->un.mii.mediacaps = *vi++; 42959860Sgdamore@opensolaris.org block->un.mii.mediacaps |= *vi++ << 8; 42969860Sgdamore@opensolaris.org block->un.mii.nwayadvert = *vi++; 42979860Sgdamore@opensolaris.org block->un.mii.nwayadvert |= *vi++ << 8; 42989860Sgdamore@opensolaris.org block->un.mii.fdxmask = *vi++; 42999860Sgdamore@opensolaris.org block->un.mii.fdxmask |= *vi++ << 8; 43009860Sgdamore@opensolaris.org block->un.mii.ttmmask = *vi++; 43019860Sgdamore@opensolaris.org block->un.mii.ttmmask |= *vi++ << 8; 43029860Sgdamore@opensolaris.org block->un.mii.miiintr |= *vi++; 43039860Sgdamore@opensolaris.org break; 43049860Sgdamore@opensolaris.org 43059860Sgdamore@opensolaris.org case 4: /* SYM Media: 4.5.2.1.3 */ 43069860Sgdamore@opensolaris.org block->media_code = *vi++ & 0x3f; 43079860Sgdamore@opensolaris.org /* Treat GP control and data as a GPR sequence */ 43089860Sgdamore@opensolaris.org block->gprseqlen = 2; 43099860Sgdamore@opensolaris.org block->gprseq[0] = *vi++; 43109860Sgdamore@opensolaris.org block->gprseq[0] |= *vi++ << 8; 43119860Sgdamore@opensolaris.org block->gprseq[0] |= GPR_CONTROL_WRITE; 43129860Sgdamore@opensolaris.org block->gprseq[1] = *vi++; 43139860Sgdamore@opensolaris.org block->gprseq[1] |= *vi++ << 8; 43149860Sgdamore@opensolaris.org block->command = *vi++; 43159860Sgdamore@opensolaris.org block->command |= *vi++ << 8; 43169860Sgdamore@opensolaris.org break; 43179860Sgdamore@opensolaris.org 43189860Sgdamore@opensolaris.org case 5: /* GPR reset sequence: Section 4.5.2.1.4 */ 43199860Sgdamore@opensolaris.org block->rstseqlen = *vi++; 43209860Sgdamore@opensolaris.org for (i = 0; i < block->rstseqlen; i++) 43219860Sgdamore@opensolaris.org block->rstseq[i] = *vi++; 43229860Sgdamore@opensolaris.org break; 43239860Sgdamore@opensolaris.org 43249860Sgdamore@opensolaris.org default: /* Unknown media block. Skip it. */ 43259860Sgdamore@opensolaris.org cmn_err(CE_WARN, "dnet: Unsupported SROM block."); 43269860Sgdamore@opensolaris.org vi += blocklen; 43279860Sgdamore@opensolaris.org break; 43289860Sgdamore@opensolaris.org } 43299860Sgdamore@opensolaris.org } else { /* Compact format (or V1 SROM): Section 4.3.2.1 */ 43309860Sgdamore@opensolaris.org block->type = 0; 43319860Sgdamore@opensolaris.org block->media_code = *vi++ & 0x3f; 43329860Sgdamore@opensolaris.org block->gprseqlen = 1; 43339860Sgdamore@opensolaris.org block->gprseq[0] = *vi++; 43349860Sgdamore@opensolaris.org block->command = *vi++; 43359860Sgdamore@opensolaris.org block->command |= (*vi++) << 8; 43369860Sgdamore@opensolaris.org } 43379860Sgdamore@opensolaris.org return (vi); 43389860Sgdamore@opensolaris.org } 43399860Sgdamore@opensolaris.org 43409860Sgdamore@opensolaris.org 43419860Sgdamore@opensolaris.org /* 43429860Sgdamore@opensolaris.org * An alternative to doing this would be to store the legacy ROMs in binary 43439860Sgdamore@opensolaris.org * format in the conf file, and in read_srom, pick out the data. This would 43449860Sgdamore@opensolaris.org * then allow the parser to continue on as normal. This makes it a little 43459860Sgdamore@opensolaris.org * easier to read. 43469860Sgdamore@opensolaris.org */ 43479860Sgdamore@opensolaris.org static void 43489860Sgdamore@opensolaris.org setup_legacy_blocks() 43499860Sgdamore@opensolaris.org { 43509860Sgdamore@opensolaris.org LEAF_FORMAT *leaf; 43519860Sgdamore@opensolaris.org media_block_t *block; 43529860Sgdamore@opensolaris.org 43539860Sgdamore@opensolaris.org /* Default FAKE SROM */ 43549860Sgdamore@opensolaris.org leaf = &leaf_default_100; 43559860Sgdamore@opensolaris.org leaf->is_static = 1; 43569860Sgdamore@opensolaris.org leaf->default_block = &leaf->block[3]; 43579860Sgdamore@opensolaris.org leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */ 43589860Sgdamore@opensolaris.org block = leaf->block; 43599860Sgdamore@opensolaris.org block->media_code = MEDIA_TP_FD; 43609860Sgdamore@opensolaris.org block->type = 0; 43619860Sgdamore@opensolaris.org block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 43629860Sgdamore@opensolaris.org block++; 43639860Sgdamore@opensolaris.org block->media_code = MEDIA_TP; 43649860Sgdamore@opensolaris.org block->type = 0; 43659860Sgdamore@opensolaris.org block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 43669860Sgdamore@opensolaris.org block++; 43679860Sgdamore@opensolaris.org block->media_code = MEDIA_SYM_SCR_FD; 43689860Sgdamore@opensolaris.org block->type = 0; 43699860Sgdamore@opensolaris.org block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 43709860Sgdamore@opensolaris.org block++; 43719860Sgdamore@opensolaris.org block->media_code = MEDIA_SYM_SCR; 43729860Sgdamore@opensolaris.org block->type = 0; 43739860Sgdamore@opensolaris.org block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 43749860Sgdamore@opensolaris.org 43759860Sgdamore@opensolaris.org /* COGENT FAKE SROM */ 43769860Sgdamore@opensolaris.org leaf = &leaf_cogent_100; 43779860Sgdamore@opensolaris.org leaf->is_static = 1; 43789860Sgdamore@opensolaris.org leaf->default_block = &leaf->block[4]; 43799860Sgdamore@opensolaris.org leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */ 43809860Sgdamore@opensolaris.org block = leaf->block; /* BNC */ 43819860Sgdamore@opensolaris.org block->media_code = MEDIA_BNC; 43829860Sgdamore@opensolaris.org block->type = 0; 43839860Sgdamore@opensolaris.org block->command = 0x8000; /* No media sense, PCS, SCR, PS all off */ 43849860Sgdamore@opensolaris.org block->gprseqlen = 2; 43859860Sgdamore@opensolaris.org block->rstseqlen = 0; 43869860Sgdamore@opensolaris.org block->gprseq[0] = 0x13f; 43879860Sgdamore@opensolaris.org block->gprseq[1] = 1; 43889860Sgdamore@opensolaris.org 43899860Sgdamore@opensolaris.org block++; 43909860Sgdamore@opensolaris.org block->media_code = MEDIA_TP_FD; 43919860Sgdamore@opensolaris.org block->type = 0; 43929860Sgdamore@opensolaris.org block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 43939860Sgdamore@opensolaris.org block->gprseqlen = 2; 43949860Sgdamore@opensolaris.org block->rstseqlen = 0; 43959860Sgdamore@opensolaris.org block->gprseq[0] = 0x13f; 43969860Sgdamore@opensolaris.org block->gprseq[1] = 0x26; 43979860Sgdamore@opensolaris.org 43989860Sgdamore@opensolaris.org block++; /* 10BaseT */ 43999860Sgdamore@opensolaris.org block->media_code = MEDIA_TP; 44009860Sgdamore@opensolaris.org block->type = 0; 44019860Sgdamore@opensolaris.org block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 44029860Sgdamore@opensolaris.org block->gprseqlen = 2; 44039860Sgdamore@opensolaris.org block->rstseqlen = 0; 44049860Sgdamore@opensolaris.org block->gprseq[0] = 0x13f; 44059860Sgdamore@opensolaris.org block->gprseq[1] = 0x3e; 44069860Sgdamore@opensolaris.org 44079860Sgdamore@opensolaris.org block++; /* 100BaseTX-FD */ 44089860Sgdamore@opensolaris.org block->media_code = MEDIA_SYM_SCR_FD; 44099860Sgdamore@opensolaris.org block->type = 0; 44109860Sgdamore@opensolaris.org block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 44119860Sgdamore@opensolaris.org block->gprseqlen = 2; 44129860Sgdamore@opensolaris.org block->rstseqlen = 0; 44139860Sgdamore@opensolaris.org block->gprseq[0] = 0x13f; 44149860Sgdamore@opensolaris.org block->gprseq[1] = 1; 44159860Sgdamore@opensolaris.org 44169860Sgdamore@opensolaris.org block++; /* 100BaseTX */ 44179860Sgdamore@opensolaris.org block->media_code = MEDIA_SYM_SCR; 44189860Sgdamore@opensolaris.org block->type = 0; 44199860Sgdamore@opensolaris.org block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 44209860Sgdamore@opensolaris.org block->gprseqlen = 2; 44219860Sgdamore@opensolaris.org block->rstseqlen = 0; 44229860Sgdamore@opensolaris.org block->gprseq[0] = 0x13f; 44239860Sgdamore@opensolaris.org block->gprseq[1] = 1; 44249860Sgdamore@opensolaris.org 44259860Sgdamore@opensolaris.org /* Generic legacy card with a PHY. */ 44269860Sgdamore@opensolaris.org leaf = &leaf_phylegacy; 44279860Sgdamore@opensolaris.org leaf->block_count = 1; 44289860Sgdamore@opensolaris.org leaf->mii_block = leaf->block; 44299860Sgdamore@opensolaris.org leaf->default_block = &leaf->block[0]; 44309860Sgdamore@opensolaris.org leaf->is_static = 1; 44319860Sgdamore@opensolaris.org block = leaf->block; 44329860Sgdamore@opensolaris.org block->media_code = MEDIA_MII; 44339860Sgdamore@opensolaris.org block->type = 1; /* MII Block type 1 */ 44349860Sgdamore@opensolaris.org block->command = 1; /* Port select */ 44359860Sgdamore@opensolaris.org block->gprseqlen = 0; 44369860Sgdamore@opensolaris.org block->rstseqlen = 0; 44379860Sgdamore@opensolaris.org 44389860Sgdamore@opensolaris.org /* ASANTE FAKE SROM */ 44399860Sgdamore@opensolaris.org leaf = &leaf_asante; 44409860Sgdamore@opensolaris.org leaf->is_static = 1; 44419860Sgdamore@opensolaris.org leaf->default_block = &leaf->block[0]; 44429860Sgdamore@opensolaris.org leaf->block_count = 1; 44439860Sgdamore@opensolaris.org block = leaf->block; 44449860Sgdamore@opensolaris.org block->media_code = MEDIA_MII; 44459860Sgdamore@opensolaris.org block->type = 1; /* MII Block type 1 */ 44469860Sgdamore@opensolaris.org block->command = 1; /* Port select */ 44479860Sgdamore@opensolaris.org block->gprseqlen = 3; 44489860Sgdamore@opensolaris.org block->rstseqlen = 0; 44499860Sgdamore@opensolaris.org block->gprseq[0] = 0x180; 44509860Sgdamore@opensolaris.org block->gprseq[1] = 0x80; 44519860Sgdamore@opensolaris.org block->gprseq[2] = 0x0; 44529860Sgdamore@opensolaris.org 44539860Sgdamore@opensolaris.org /* LEGACY 21041 card FAKE SROM */ 44549860Sgdamore@opensolaris.org leaf = &leaf_21041; 44559860Sgdamore@opensolaris.org leaf->is_static = 1; 44569860Sgdamore@opensolaris.org leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */ 44579860Sgdamore@opensolaris.org leaf->default_block = &leaf->block[3]; 44589860Sgdamore@opensolaris.org 44599860Sgdamore@opensolaris.org block = leaf->block; 44609860Sgdamore@opensolaris.org block->media_code = MEDIA_AUI; 44619860Sgdamore@opensolaris.org block->type = 2; 44629860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef09; 44639860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 44649860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x000e; 44659860Sgdamore@opensolaris.org 44669860Sgdamore@opensolaris.org block++; 44679860Sgdamore@opensolaris.org block->media_code = MEDIA_TP_FD; 44689860Sgdamore@opensolaris.org block->type = 2; 44699860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef01; 44709860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3d; 44719860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 44729860Sgdamore@opensolaris.org 44739860Sgdamore@opensolaris.org block++; 44749860Sgdamore@opensolaris.org block->media_code = MEDIA_BNC; 44759860Sgdamore@opensolaris.org block->type = 2; 44769860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef09; 44779860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 44789860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0006; 44799860Sgdamore@opensolaris.org 44809860Sgdamore@opensolaris.org block++; 44819860Sgdamore@opensolaris.org block->media_code = MEDIA_TP; 44829860Sgdamore@opensolaris.org block->type = 2; 44839860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef01; 44849860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3f; 44859860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 44869860Sgdamore@opensolaris.org 44879860Sgdamore@opensolaris.org /* LEGACY 21040 card FAKE SROM */ 44889860Sgdamore@opensolaris.org leaf = &leaf_21040; 44899860Sgdamore@opensolaris.org leaf->is_static = 1; 44909860Sgdamore@opensolaris.org leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */ 44919860Sgdamore@opensolaris.org block = leaf->block; 44929860Sgdamore@opensolaris.org block->media_code = MEDIA_AUI; 44939860Sgdamore@opensolaris.org block->type = 2; 44949860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x8f09; 44959860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 44969860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x000e; 44979860Sgdamore@opensolaris.org block++; 44989860Sgdamore@opensolaris.org block->media_code = MEDIA_TP_FD; 44999860Sgdamore@opensolaris.org block->type = 2; 45009860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x0f01; 45019860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3d; 45029860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 45039860Sgdamore@opensolaris.org block++; 45049860Sgdamore@opensolaris.org block->media_code = MEDIA_BNC; 45059860Sgdamore@opensolaris.org block->type = 2; 45069860Sgdamore@opensolaris.org block->un.sia.csr13 = 0xef09; 45079860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x0705; 45089860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0006; 45099860Sgdamore@opensolaris.org block++; 45109860Sgdamore@opensolaris.org block->media_code = MEDIA_TP; 45119860Sgdamore@opensolaris.org block->type = 2; 45129860Sgdamore@opensolaris.org block->un.sia.csr13 = 0x8f01; 45139860Sgdamore@opensolaris.org block->un.sia.csr14 = 0x7f3f; 45149860Sgdamore@opensolaris.org block->un.sia.csr15 = 0x0008; 45159860Sgdamore@opensolaris.org } 45169860Sgdamore@opensolaris.org 45179860Sgdamore@opensolaris.org static void 45189860Sgdamore@opensolaris.org dnet_print_srom(SROM_FORMAT *sr) 45199860Sgdamore@opensolaris.org { 45209860Sgdamore@opensolaris.org int i; 45219860Sgdamore@opensolaris.org uchar_t *a = sr->netaddr; 45229860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d," 45239860Sgdamore@opensolaris.org "Addr:%x:%x:%x:%x:%x:%x", 45249860Sgdamore@opensolaris.org sr->init_from_srom, sr->version, sr->adapters, 45259860Sgdamore@opensolaris.org a[0], a[1], a[2], a[3], a[4], a[5]); 45269860Sgdamore@opensolaris.org 45279860Sgdamore@opensolaris.org for (i = 0; i < sr->adapters; i++) 45289860Sgdamore@opensolaris.org dnet_dump_leaf(sr->leaf+i); 45299860Sgdamore@opensolaris.org } 45309860Sgdamore@opensolaris.org 45319860Sgdamore@opensolaris.org static void 45329860Sgdamore@opensolaris.org dnet_dump_leaf(LEAF_FORMAT *leaf) 45339860Sgdamore@opensolaris.org { 45349860Sgdamore@opensolaris.org int i; 45359860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x", 45369860Sgdamore@opensolaris.org leaf->device_number, leaf->block_count, leaf->gpr); 45379860Sgdamore@opensolaris.org for (i = 0; i < leaf->block_count; i++) 45389860Sgdamore@opensolaris.org dnet_dump_block(leaf->block+i); 45399860Sgdamore@opensolaris.org } 45409860Sgdamore@opensolaris.org 45419860Sgdamore@opensolaris.org static void 45429860Sgdamore@opensolaris.org dnet_dump_block(media_block_t *block) 45439860Sgdamore@opensolaris.org { 45449860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ", 45459860Sgdamore@opensolaris.org (void *)block, 45469860Sgdamore@opensolaris.org block->type, media_str[block->media_code], block->command); 45479860Sgdamore@opensolaris.org dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2, 45489860Sgdamore@opensolaris.org block->gprseqlen *2); 45499860Sgdamore@opensolaris.org dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2, 45509860Sgdamore@opensolaris.org block->rstseqlen *2); 45519860Sgdamore@opensolaris.org switch (block->type) { 45529860Sgdamore@opensolaris.org case 1: case 3: 45539860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx" 45549860Sgdamore@opensolaris.org "%x, ttm %x, mediacap %x", 45559860Sgdamore@opensolaris.org block->un.mii.phy_num, block->un.mii.nwayadvert, 45569860Sgdamore@opensolaris.org block->un.mii.fdxmask, block->un.mii.ttmmask, 45579860Sgdamore@opensolaris.org block->un.mii.mediacaps); 45589860Sgdamore@opensolaris.org break; 45599860Sgdamore@opensolaris.org case 2: 45609860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x", 45619860Sgdamore@opensolaris.org block->un.sia.csr13, block->un.sia.csr14, 45629860Sgdamore@opensolaris.org block->un.sia.csr15); 45639860Sgdamore@opensolaris.org break; 45649860Sgdamore@opensolaris.org } 45659860Sgdamore@opensolaris.org } 45669860Sgdamore@opensolaris.org 45679860Sgdamore@opensolaris.org 45689860Sgdamore@opensolaris.org /* Utility to print out binary info dumps. Handy for SROMs, etc */ 45699860Sgdamore@opensolaris.org 45709860Sgdamore@opensolaris.org static int 45719860Sgdamore@opensolaris.org hexcode(unsigned val) 45729860Sgdamore@opensolaris.org { 45739860Sgdamore@opensolaris.org if (val <= 9) 45749860Sgdamore@opensolaris.org return (val +'0'); 45759860Sgdamore@opensolaris.org if (val <= 15) 45769860Sgdamore@opensolaris.org return (val + 'a' - 10); 45779860Sgdamore@opensolaris.org return (-1); 45789860Sgdamore@opensolaris.org } 45799860Sgdamore@opensolaris.org 45809860Sgdamore@opensolaris.org static void 45819860Sgdamore@opensolaris.org dnet_dumpbin(char *msg, unsigned char *data, int size, int len) 45829860Sgdamore@opensolaris.org { 45839860Sgdamore@opensolaris.org char hex[128], *p = hex; 45849860Sgdamore@opensolaris.org char ascii[128], *q = ascii; 45859860Sgdamore@opensolaris.org int i, j; 45869860Sgdamore@opensolaris.org 45879860Sgdamore@opensolaris.org if (!len) 45889860Sgdamore@opensolaris.org return; 45899860Sgdamore@opensolaris.org 45909860Sgdamore@opensolaris.org for (i = 0; i < len; i += size) { 45919860Sgdamore@opensolaris.org for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */ 45929860Sgdamore@opensolaris.org *p++ = hexcode(data[i+j] >> 4); 45939860Sgdamore@opensolaris.org *p++ = hexcode(data[i+j] & 0xf); 45949860Sgdamore@opensolaris.org *q++ = (data[i+j] < 32 || data[i+j] > 127) ? 45959860Sgdamore@opensolaris.org '.' : data[i]; 45969860Sgdamore@opensolaris.org } 45979860Sgdamore@opensolaris.org *p++ = ' '; 45989860Sgdamore@opensolaris.org if (q-ascii >= 8) { 45999860Sgdamore@opensolaris.org *p = *q = 0; 46009860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii); 46019860Sgdamore@opensolaris.org p = hex; 46029860Sgdamore@opensolaris.org q = ascii; 46039860Sgdamore@opensolaris.org } 46049860Sgdamore@opensolaris.org } 46059860Sgdamore@opensolaris.org if (p != hex) { 46069860Sgdamore@opensolaris.org while ((p - hex) < 8*3) 46079860Sgdamore@opensolaris.org *p++ = ' '; 46089860Sgdamore@opensolaris.org *p = *q = 0; 46099860Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii); 46109860Sgdamore@opensolaris.org } 46119860Sgdamore@opensolaris.org } 46129860Sgdamore@opensolaris.org 46139860Sgdamore@opensolaris.org #ifdef DNETDEBUG 46149860Sgdamore@opensolaris.org void 46159860Sgdamore@opensolaris.org dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin, 46169860Sgdamore@opensolaris.org timercb_t cback) 46179860Sgdamore@opensolaris.org { 46189860Sgdamore@opensolaris.org mutex_enter(&dnetp->intrlock); 46199860Sgdamore@opensolaris.org dnetp->timer.start_ticks = (usecs * 100) / 8192; 46209860Sgdamore@opensolaris.org dnetp->timer.cb = cback; 46219860Sgdamore@opensolaris.org ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG), 46229860Sgdamore@opensolaris.org dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0)); 46239860Sgdamore@opensolaris.org if (dnetp->timer.cb) 4624*10340Sstallion@opensolaris.org enable_interrupts(dnetp); 46259860Sgdamore@opensolaris.org mutex_exit(&dnetp->intrlock); 46269860Sgdamore@opensolaris.org } 46279860Sgdamore@opensolaris.org 46289860Sgdamore@opensolaris.org uint32_t 46299860Sgdamore@opensolaris.org dnet_usecelapsed(struct dnetinstance *dnetp) 46309860Sgdamore@opensolaris.org { 46319860Sgdamore@opensolaris.org uint32_t ticks = dnetp->timer.start_ticks - 46329860Sgdamore@opensolaris.org (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) & 46339860Sgdamore@opensolaris.org 0xffff); 46349860Sgdamore@opensolaris.org return ((ticks * 8192) / 100); 46359860Sgdamore@opensolaris.org } 46369860Sgdamore@opensolaris.org 46379860Sgdamore@opensolaris.org /* ARGSUSED */ 46389860Sgdamore@opensolaris.org void 46399860Sgdamore@opensolaris.org dnet_timestamp(struct dnetinstance *dnetp, char *buf) 46409860Sgdamore@opensolaris.org { 46419860Sgdamore@opensolaris.org uint32_t elapsed = dnet_usecelapsed(dnetp); 46429860Sgdamore@opensolaris.org char loc[32], *p = loc; 46439860Sgdamore@opensolaris.org int firstdigit = 1; 46449860Sgdamore@opensolaris.org uint32_t divisor; 46459860Sgdamore@opensolaris.org 46469860Sgdamore@opensolaris.org while (*p++ = *buf++) 46479860Sgdamore@opensolaris.org ; 46489860Sgdamore@opensolaris.org p--; 46499860Sgdamore@opensolaris.org 46509860Sgdamore@opensolaris.org for (divisor = 1000000000; divisor /= 10; ) { 46519860Sgdamore@opensolaris.org int digit = (elapsed / divisor); 46529860Sgdamore@opensolaris.org elapsed -= digit * divisor; 46539860Sgdamore@opensolaris.org if (!firstdigit || digit) { 46549860Sgdamore@opensolaris.org *p++ = digit + '0'; 46559860Sgdamore@opensolaris.org firstdigit = 0; 46569860Sgdamore@opensolaris.org } 46579860Sgdamore@opensolaris.org 46589860Sgdamore@opensolaris.org } 46599860Sgdamore@opensolaris.org 46609860Sgdamore@opensolaris.org /* Actual zero, output it */ 46619860Sgdamore@opensolaris.org if (firstdigit) 46629860Sgdamore@opensolaris.org *p++ = '0'; 46639860Sgdamore@opensolaris.org 46649860Sgdamore@opensolaris.org *p++ = '-'; 46659860Sgdamore@opensolaris.org *p++ = '>'; 46669860Sgdamore@opensolaris.org *p++ = 0; 46679860Sgdamore@opensolaris.org 46689860Sgdamore@opensolaris.org printf(loc); 46699860Sgdamore@opensolaris.org dnet_usectimeout(dnetp, 1000000, 0, 0); 46709860Sgdamore@opensolaris.org } 46719860Sgdamore@opensolaris.org 46729860Sgdamore@opensolaris.org #endif 4673