1bdb9230aSGarrett D'Amore /* 2bdb9230aSGarrett D'Amore * CDDL HEADER START 3bdb9230aSGarrett D'Amore * 4bdb9230aSGarrett D'Amore * The contents of this file are subject to the terms of the 5bdb9230aSGarrett D'Amore * Common Development and Distribution License (the "License"). 6bdb9230aSGarrett D'Amore * You may not use this file except in compliance with the License. 7bdb9230aSGarrett D'Amore * 8bdb9230aSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9bdb9230aSGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 10bdb9230aSGarrett D'Amore * See the License for the specific language governing permissions 11bdb9230aSGarrett D'Amore * and limitations under the License. 12bdb9230aSGarrett D'Amore * 13bdb9230aSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 14bdb9230aSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15bdb9230aSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 16bdb9230aSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 17bdb9230aSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 18bdb9230aSGarrett D'Amore * 19bdb9230aSGarrett D'Amore * CDDL HEADER END 20bdb9230aSGarrett D'Amore */ 21bdb9230aSGarrett D'Amore 22bdb9230aSGarrett D'Amore /* 23*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24bdb9230aSGarrett D'Amore * Use is subject to license terms. 25bdb9230aSGarrett D'Amore */ 26bdb9230aSGarrett D'Amore 27bdb9230aSGarrett D'Amore 28bdb9230aSGarrett D'Amore /* 29bdb9230aSGarrett D'Amore * dnet -- DEC 21x4x 30bdb9230aSGarrett D'Amore * 31bdb9230aSGarrett D'Amore * Currently supports: 32bdb9230aSGarrett D'Amore * 21040, 21041, 21140, 21142, 21143 33bdb9230aSGarrett D'Amore * SROM versions 1, 3, 3.03, 4 34bdb9230aSGarrett D'Amore * TP, AUI, BNC, 100BASETX, 100BASET4 35bdb9230aSGarrett D'Amore * 36bdb9230aSGarrett D'Amore * XXX NEEDSWORK 37bdb9230aSGarrett D'Amore * All media SHOULD work, FX is untested 38bdb9230aSGarrett D'Amore * 3998e8d175SSteven Stallion * Depends on the Generic LAN Driver utility functions in /kernel/misc/mac 40bdb9230aSGarrett D'Amore */ 41bdb9230aSGarrett D'Amore 42bdb9230aSGarrett D'Amore #define BUG_4010796 /* See 4007871, 4010796 */ 43bdb9230aSGarrett D'Amore 44bdb9230aSGarrett D'Amore #include <sys/types.h> 45bdb9230aSGarrett D'Amore #include <sys/errno.h> 46bdb9230aSGarrett D'Amore #include <sys/param.h> 47bdb9230aSGarrett D'Amore #include <sys/stropts.h> 48bdb9230aSGarrett D'Amore #include <sys/stream.h> 49bdb9230aSGarrett D'Amore #include <sys/kmem.h> 50bdb9230aSGarrett D'Amore #include <sys/conf.h> 51bdb9230aSGarrett D'Amore #include <sys/devops.h> 52bdb9230aSGarrett D'Amore #include <sys/ksynch.h> 53bdb9230aSGarrett D'Amore #include <sys/stat.h> 54bdb9230aSGarrett D'Amore #include <sys/modctl.h> 55bdb9230aSGarrett D'Amore #include <sys/debug.h> 56bdb9230aSGarrett D'Amore #include <sys/dlpi.h> 57bdb9230aSGarrett D'Amore #include <sys/ethernet.h> 5898e8d175SSteven Stallion #include <sys/vlan.h> 5998e8d175SSteven Stallion #include <sys/mac.h> 6098e8d175SSteven Stallion #include <sys/mac_ether.h> 6198e8d175SSteven Stallion #include <sys/mac_provider.h> 62bdb9230aSGarrett D'Amore #include <sys/pci.h> 63bdb9230aSGarrett D'Amore #include <sys/ddi.h> 64bdb9230aSGarrett D'Amore #include <sys/sunddi.h> 6598e8d175SSteven Stallion #include <sys/strsun.h> 66bdb9230aSGarrett D'Amore 67bdb9230aSGarrett D'Amore #include "dnet_mii.h" 68bdb9230aSGarrett D'Amore #include "dnet.h" 69bdb9230aSGarrett D'Amore 70bdb9230aSGarrett D'Amore /* 71bdb9230aSGarrett D'Amore * Declarations and Module Linkage 72bdb9230aSGarrett D'Amore */ 73bdb9230aSGarrett D'Amore 74bdb9230aSGarrett D'Amore #define IDENT "DNET 21x4x" 75bdb9230aSGarrett D'Amore 76bdb9230aSGarrett D'Amore /* 77bdb9230aSGarrett D'Amore * #define DNET_NOISY 78bdb9230aSGarrett D'Amore * #define SROMDEBUG 79bdb9230aSGarrett D'Amore * #define SROMDUMPSTRUCTURES 80bdb9230aSGarrett D'Amore */ 81bdb9230aSGarrett D'Amore 82bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 83bdb9230aSGarrett D'Amore #ifdef DNET_NOISY 84bdb9230aSGarrett D'Amore int dnetdebug = -1; 85bdb9230aSGarrett D'Amore #else 86bdb9230aSGarrett D'Amore int dnetdebug = 0; 87bdb9230aSGarrett D'Amore #endif 88bdb9230aSGarrett D'Amore #endif 89bdb9230aSGarrett D'Amore 90bdb9230aSGarrett D'Amore /* used for message allocated using desballoc() */ 91bdb9230aSGarrett D'Amore struct free_ptr { 92bdb9230aSGarrett D'Amore struct free_rtn free_rtn; 93bdb9230aSGarrett D'Amore caddr_t buf; 94bdb9230aSGarrett D'Amore }; 95bdb9230aSGarrett D'Amore 96bdb9230aSGarrett D'Amore struct rbuf_list { 97bdb9230aSGarrett D'Amore struct rbuf_list *rbuf_next; /* next in the list */ 98bdb9230aSGarrett D'Amore caddr_t rbuf_vaddr; /* virual addr of the buf */ 99bdb9230aSGarrett D'Amore uint32_t rbuf_paddr; /* physical addr of the buf */ 100bdb9230aSGarrett D'Amore uint32_t rbuf_endpaddr; /* physical addr at the end */ 101bdb9230aSGarrett D'Amore ddi_dma_handle_t rbuf_dmahdl; /* dma handle */ 102bdb9230aSGarrett D'Amore ddi_acc_handle_t rbuf_acchdl; /* handle for DDI functions */ 103bdb9230aSGarrett D'Amore }; 104bdb9230aSGarrett D'Amore 105bdb9230aSGarrett D'Amore /* Required system entry points */ 10698e8d175SSteven Stallion static int dnet_probe(dev_info_t *); 10798e8d175SSteven Stallion static int dnet_attach(dev_info_t *, ddi_attach_cmd_t); 10898e8d175SSteven Stallion static int dnet_detach(dev_info_t *, ddi_detach_cmd_t); 10998e8d175SSteven Stallion static int dnet_quiesce(dev_info_t *); 110bdb9230aSGarrett D'Amore 11198e8d175SSteven Stallion /* Required driver entry points for GLDv3 */ 11298e8d175SSteven Stallion static int dnet_m_start(void *); 11398e8d175SSteven Stallion static void dnet_m_stop(void *); 11498e8d175SSteven Stallion static int dnet_m_getstat(void *, uint_t, uint64_t *); 11598e8d175SSteven Stallion static int dnet_m_setpromisc(void *, boolean_t); 11698e8d175SSteven Stallion static int dnet_m_multicst(void *, boolean_t, const uint8_t *); 11798e8d175SSteven Stallion static int dnet_m_unicst(void *, const uint8_t *); 11898e8d175SSteven Stallion static mblk_t *dnet_m_tx(void *, mblk_t *); 11998e8d175SSteven Stallion 12098e8d175SSteven Stallion static uint_t dnet_intr(caddr_t); 121bdb9230aSGarrett D'Amore 122bdb9230aSGarrett D'Amore /* Internal functions used by the above entry points */ 123bdb9230aSGarrett D'Amore static void write_gpr(struct dnetinstance *dnetp, uint32_t val); 12498e8d175SSteven Stallion static void dnet_reset_board(struct dnetinstance *); 12598e8d175SSteven Stallion static void dnet_init_board(struct dnetinstance *); 12698e8d175SSteven Stallion static void dnet_chip_init(struct dnetinstance *); 12798e8d175SSteven Stallion static uint32_t hashindex(const uint8_t *); 12898e8d175SSteven Stallion static int dnet_start(struct dnetinstance *); 12998e8d175SSteven Stallion static int dnet_set_addr(struct dnetinstance *); 130bdb9230aSGarrett D'Amore 13198e8d175SSteven Stallion static boolean_t dnet_send(struct dnetinstance *, mblk_t *); 13298e8d175SSteven Stallion 13398e8d175SSteven Stallion static void dnet_getp(struct dnetinstance *); 13498e8d175SSteven Stallion static void update_rx_stats(struct dnetinstance *, int); 13598e8d175SSteven Stallion static void update_tx_stats(struct dnetinstance *, int); 136bdb9230aSGarrett D'Amore 137bdb9230aSGarrett D'Amore /* Media Selection Setup Routines */ 13898e8d175SSteven Stallion static void set_gpr(struct dnetinstance *); 13998e8d175SSteven Stallion static void set_opr(struct dnetinstance *); 14098e8d175SSteven Stallion static void set_sia(struct dnetinstance *); 141bdb9230aSGarrett D'Amore 142bdb9230aSGarrett D'Amore /* Buffer Management Routines */ 14398e8d175SSteven Stallion static int dnet_alloc_bufs(struct dnetinstance *); 14498e8d175SSteven Stallion static void dnet_free_bufs(struct dnetinstance *); 14598e8d175SSteven Stallion static void dnet_init_txrx_bufs(struct dnetinstance *); 14698e8d175SSteven Stallion static int alloc_descriptor(struct dnetinstance *); 14798e8d175SSteven Stallion static void dnet_reclaim_Tx_desc(struct dnetinstance *); 148bdb9230aSGarrett D'Amore static int dnet_rbuf_init(dev_info_t *, int); 149bdb9230aSGarrett D'Amore static int dnet_rbuf_destroy(); 150bdb9230aSGarrett D'Amore static struct rbuf_list *dnet_rbuf_alloc(dev_info_t *, int); 151bdb9230aSGarrett D'Amore static void dnet_rbuf_free(caddr_t); 152bdb9230aSGarrett D'Amore static void dnet_freemsg_buf(struct free_ptr *); 153bdb9230aSGarrett D'Amore 15498e8d175SSteven Stallion static void setup_block(struct dnetinstance *); 155bdb9230aSGarrett D'Amore 156bdb9230aSGarrett D'Amore /* SROM read functions */ 157bdb9230aSGarrett D'Amore static int dnet_read_srom(dev_info_t *, int, ddi_acc_handle_t, caddr_t, 158bdb9230aSGarrett D'Amore uchar_t *, int); 159bdb9230aSGarrett D'Amore static void dnet_read21040addr(dev_info_t *, ddi_acc_handle_t, caddr_t, 160bdb9230aSGarrett D'Amore uchar_t *, int *); 161bdb9230aSGarrett D'Amore static void dnet_read21140srom(ddi_acc_handle_t, caddr_t, uchar_t *, int); 162bdb9230aSGarrett D'Amore static int get_alternative_srom_image(dev_info_t *, uchar_t *, int); 163bdb9230aSGarrett D'Amore static void dnet_print_srom(SROM_FORMAT *sr); 164bdb9230aSGarrett D'Amore static void dnet_dump_leaf(LEAF_FORMAT *leaf); 165bdb9230aSGarrett D'Amore static void dnet_dump_block(media_block_t *block); 166bdb9230aSGarrett D'Amore #ifdef BUG_4010796 167bdb9230aSGarrett D'Amore static void set_alternative_srom_image(dev_info_t *, uchar_t *, int); 16898e8d175SSteven Stallion static int dnet_hack(dev_info_t *); 169bdb9230aSGarrett D'Amore #endif 170bdb9230aSGarrett D'Amore 17198e8d175SSteven Stallion static int dnet_hack_interrupts(struct dnetinstance *, int); 172bdb9230aSGarrett D'Amore static int dnet_detach_hacked_interrupt(dev_info_t *devinfo); 17398e8d175SSteven Stallion static void enable_interrupts(struct dnetinstance *); 174bdb9230aSGarrett D'Amore 175bdb9230aSGarrett D'Amore /* SROM parsing functions */ 176bdb9230aSGarrett D'Amore static void dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, 177bdb9230aSGarrett D'Amore uchar_t *vi); 178bdb9230aSGarrett D'Amore static void parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf, 179bdb9230aSGarrett D'Amore uchar_t *vi); 180bdb9230aSGarrett D'Amore static uchar_t *parse_media_block(struct dnetinstance *dnetp, 181bdb9230aSGarrett D'Amore media_block_t *block, uchar_t *vi); 182bdb9230aSGarrett D'Amore static int check_srom_valid(uchar_t *); 183bdb9230aSGarrett D'Amore static void dnet_dumpbin(char *msg, uchar_t *, int size, int len); 184bdb9230aSGarrett D'Amore static void setup_legacy_blocks(); 185bdb9230aSGarrett D'Amore /* Active Media Determination Routines */ 18698e8d175SSteven Stallion static void find_active_media(struct dnetinstance *); 18798e8d175SSteven Stallion static int send_test_packet(struct dnetinstance *); 18898e8d175SSteven Stallion static int dnet_link_sense(struct dnetinstance *); 189bdb9230aSGarrett D'Amore 190bdb9230aSGarrett D'Amore /* PHY MII Routines */ 191bdb9230aSGarrett D'Amore static ushort_t dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num); 192bdb9230aSGarrett D'Amore static void dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, 193bdb9230aSGarrett D'Amore int reg_dat); 194bdb9230aSGarrett D'Amore static void write_mii(struct dnetinstance *, uint32_t, int); 195bdb9230aSGarrett D'Amore static void mii_tristate(struct dnetinstance *); 19698e8d175SSteven Stallion static void do_phy(struct dnetinstance *); 197bdb9230aSGarrett D'Amore static void dnet_mii_link_cb(dev_info_t *, int, enum mii_phy_state); 198bdb9230aSGarrett D'Amore static void set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf); 199bdb9230aSGarrett D'Amore 200bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 201bdb9230aSGarrett D'Amore uint32_t dnet_usecelapsed(struct dnetinstance *dnetp); 202bdb9230aSGarrett D'Amore void dnet_timestamp(struct dnetinstance *, char *); 203bdb9230aSGarrett D'Amore void dnet_usectimeout(struct dnetinstance *, uint32_t, int, timercb_t); 204bdb9230aSGarrett D'Amore #endif 205bdb9230aSGarrett D'Amore static char *media_str[] = { 206bdb9230aSGarrett D'Amore "10BaseT", 207bdb9230aSGarrett D'Amore "10Base2", 208bdb9230aSGarrett D'Amore "10Base5", 209bdb9230aSGarrett D'Amore "100BaseTX", 210bdb9230aSGarrett D'Amore "10BaseT FD", 211bdb9230aSGarrett D'Amore "100BaseTX FD", 212bdb9230aSGarrett D'Amore "100BaseT4", 213bdb9230aSGarrett D'Amore "100BaseFX", 214bdb9230aSGarrett D'Amore "100BaseFX FD", 215bdb9230aSGarrett D'Amore "MII" 216bdb9230aSGarrett D'Amore }; 217bdb9230aSGarrett D'Amore 218bdb9230aSGarrett D'Amore /* default SROM info for cards with no SROMs */ 219bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_default_100; 220bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_asante; 221bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_phylegacy; 222bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_cogent_100; 223bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_21041; 224bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_21040; 225bdb9230aSGarrett D'Amore 22698e8d175SSteven Stallion /* rx buffer size (rounded up to 4) */ 22798e8d175SSteven Stallion int rx_buf_size = (ETHERMAX + ETHERFCSL + VLAN_TAGSZ + 3) & ~3; 228bdb9230aSGarrett D'Amore 229bdb9230aSGarrett D'Amore int max_rx_desc_21040 = MAX_RX_DESC_21040; 230bdb9230aSGarrett D'Amore int max_rx_desc_21140 = MAX_RX_DESC_21140; 231bdb9230aSGarrett D'Amore int max_tx_desc = MAX_TX_DESC; 232bdb9230aSGarrett D'Amore int dnet_xmit_threshold = MAX_TX_DESC >> 2; /* XXX need tuning? */ 233bdb9230aSGarrett D'Amore 234bdb9230aSGarrett D'Amore static kmutex_t dnet_rbuf_lock; /* mutex to protect rbuf_list data */ 235bdb9230aSGarrett D'Amore 236bdb9230aSGarrett D'Amore /* used for buffers allocated by ddi_dma_mem_alloc() */ 237bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr = { 238bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */ 239bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */ 240bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 241bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */ 242bdb9230aSGarrett D'Amore 4, /* dma_attr_align */ 243bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */ 244bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */ 245bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 246bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 247bdb9230aSGarrett D'Amore 1, /* dma_attr_sgllen */ 248bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */ 249bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */ 250bdb9230aSGarrett D'Amore }; 251bdb9230aSGarrett D'Amore 252bdb9230aSGarrett D'Amore /* used for buffers allocated for rbuf, allow 2 cookies */ 253bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr_rb = { 254bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */ 255bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */ 256bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 257bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */ 258bdb9230aSGarrett D'Amore 4, /* dma_attr_align */ 259bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */ 260bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */ 261bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 262bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 263bdb9230aSGarrett D'Amore 2, /* dma_attr_sgllen */ 264bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */ 265bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */ 266bdb9230aSGarrett D'Amore }; 267bdb9230aSGarrett D'Amore /* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */ 268bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr_tx = { 269bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */ 270bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */ 271bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 272bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */ 273bdb9230aSGarrett D'Amore 1, /* dma_attr_align */ 274bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */ 275bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */ 276bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 277bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */ 278bdb9230aSGarrett D'Amore 0x7FFF, /* dma_attr_sgllen */ 279bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */ 280bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */ 281bdb9230aSGarrett D'Amore }; 282bdb9230aSGarrett D'Amore 283bdb9230aSGarrett D'Amore static ddi_device_acc_attr_t accattr = { 284bdb9230aSGarrett D'Amore DDI_DEVICE_ATTR_V0, 285bdb9230aSGarrett D'Amore DDI_NEVERSWAP_ACC, 286bdb9230aSGarrett D'Amore DDI_STRICTORDER_ACC, 287bdb9230aSGarrett D'Amore }; 288bdb9230aSGarrett D'Amore 289bdb9230aSGarrett D'Amore uchar_t dnet_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 290bdb9230aSGarrett D'Amore 291bdb9230aSGarrett D'Amore /* Standard Module linkage initialization for a Streams driver */ 292bdb9230aSGarrett D'Amore extern struct mod_ops mod_driverops; 293bdb9230aSGarrett D'Amore 29498e8d175SSteven Stallion DDI_DEFINE_STREAM_OPS(dnet_devops, nulldev, dnet_probe, dnet_attach, 29598e8d175SSteven Stallion dnet_detach, nodev, NULL, D_MP, NULL, dnet_quiesce); 296bdb9230aSGarrett D'Amore 29798e8d175SSteven Stallion static struct modldrv dnet_modldrv = { 298bdb9230aSGarrett D'Amore &mod_driverops, /* Type of module. This one is a driver */ 299bdb9230aSGarrett D'Amore IDENT, /* short description */ 30098e8d175SSteven Stallion &dnet_devops /* driver specific ops */ 301bdb9230aSGarrett D'Amore }; 302bdb9230aSGarrett D'Amore 30398e8d175SSteven Stallion static struct modlinkage dnet_modlinkage = { 30498e8d175SSteven Stallion MODREV_1, /* ml_rev */ 30598e8d175SSteven Stallion { &dnet_modldrv, NULL } /* ml_linkage */ 306bdb9230aSGarrett D'Amore }; 307bdb9230aSGarrett D'Amore 30898e8d175SSteven Stallion static mac_callbacks_t dnet_m_callbacks = { 30998e8d175SSteven Stallion 0, /* mc_callbacks */ 31098e8d175SSteven Stallion dnet_m_getstat, /* mc_getstat */ 31198e8d175SSteven Stallion dnet_m_start, /* mc_start */ 31298e8d175SSteven Stallion dnet_m_stop, /* mc_stop */ 31398e8d175SSteven Stallion dnet_m_setpromisc, /* mc_setpromisc */ 31498e8d175SSteven Stallion dnet_m_multicst, /* mc_multicst */ 31598e8d175SSteven Stallion dnet_m_unicst, /* mc_unicst */ 31698e8d175SSteven Stallion dnet_m_tx, /* mc_tx */ 317*0dc2366fSVenugopal Iyer NULL, 31898e8d175SSteven Stallion NULL, /* mc_ioctl */ 31998e8d175SSteven Stallion NULL, /* mc_getcapab */ 32098e8d175SSteven Stallion NULL, /* mc_open */ 32198e8d175SSteven Stallion NULL /* mc_close */ 32298e8d175SSteven Stallion }; 323bdb9230aSGarrett D'Amore 324bdb9230aSGarrett D'Amore /* 325bdb9230aSGarrett D'Amore * Passed to the hacked interrupt for multiport Cogent and ZNYX cards with 326bdb9230aSGarrett D'Amore * dodgy interrupt routing 327bdb9230aSGarrett D'Amore */ 328bdb9230aSGarrett D'Amore #define MAX_INST 8 /* Maximum instances on a multiport adapter. */ 329bdb9230aSGarrett D'Amore struct hackintr_inf 330bdb9230aSGarrett D'Amore { 33198e8d175SSteven Stallion struct dnetinstance *dnetps[MAX_INST]; /* dnetps for each port */ 332bdb9230aSGarrett D'Amore dev_info_t *devinfo; /* Devinfo of the primary device */ 333bdb9230aSGarrett D'Amore kmutex_t lock; 334bdb9230aSGarrett D'Amore /* Ensures the interrupt doesn't get called while detaching */ 335bdb9230aSGarrett D'Amore }; 336bdb9230aSGarrett D'Amore static char hackintr_propname[] = "InterruptData"; 337bdb9230aSGarrett D'Amore static char macoffset_propname[] = "MAC_offset"; 338bdb9230aSGarrett D'Amore static char speed_propname[] = "speed"; 339bdb9230aSGarrett D'Amore static char ofloprob_propname[] = "dmaworkaround"; 340bdb9230aSGarrett D'Amore static char duplex_propname[] = "full-duplex"; /* Must agree with MII */ 341bdb9230aSGarrett D'Amore static char printsrom_propname[] = "print-srom"; 342bdb9230aSGarrett D'Amore 343bdb9230aSGarrett D'Amore static uint_t dnet_hack_intr(struct hackintr_inf *); 344bdb9230aSGarrett D'Amore 345bdb9230aSGarrett D'Amore int 346bdb9230aSGarrett D'Amore _init(void) 347bdb9230aSGarrett D'Amore { 348bdb9230aSGarrett D'Amore int i; 349bdb9230aSGarrett D'Amore 350bdb9230aSGarrett D'Amore /* Configure fake sroms for legacy cards */ 351bdb9230aSGarrett D'Amore mutex_init(&dnet_rbuf_lock, NULL, MUTEX_DRIVER, NULL); 352bdb9230aSGarrett D'Amore setup_legacy_blocks(); 35398e8d175SSteven Stallion 35498e8d175SSteven Stallion mac_init_ops(&dnet_devops, "dnet"); 35598e8d175SSteven Stallion 35698e8d175SSteven Stallion if ((i = mod_install(&dnet_modlinkage)) != 0) { 35798e8d175SSteven Stallion mac_fini_ops(&dnet_devops); 358bdb9230aSGarrett D'Amore mutex_destroy(&dnet_rbuf_lock); 359bdb9230aSGarrett D'Amore } 360bdb9230aSGarrett D'Amore return (i); 361bdb9230aSGarrett D'Amore } 362bdb9230aSGarrett D'Amore 363bdb9230aSGarrett D'Amore int 364bdb9230aSGarrett D'Amore _fini(void) 365bdb9230aSGarrett D'Amore { 366bdb9230aSGarrett D'Amore int i; 36798e8d175SSteven Stallion 36898e8d175SSteven Stallion if ((i = mod_remove(&dnet_modlinkage)) == 0) { 36998e8d175SSteven Stallion mac_fini_ops(&dnet_devops); 37098e8d175SSteven Stallion 371bdb9230aSGarrett D'Amore /* loop until all the receive buffers are freed */ 372bdb9230aSGarrett D'Amore while (dnet_rbuf_destroy() != 0) { 373bdb9230aSGarrett D'Amore delay(drv_usectohz(100000)); 374bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 375bdb9230aSGarrett D'Amore if (dnetdebug & DNETDDI) 376bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet _fini delay"); 377bdb9230aSGarrett D'Amore #endif 378bdb9230aSGarrett D'Amore } 379bdb9230aSGarrett D'Amore mutex_destroy(&dnet_rbuf_lock); 380bdb9230aSGarrett D'Amore } 381bdb9230aSGarrett D'Amore return (i); 382bdb9230aSGarrett D'Amore } 383bdb9230aSGarrett D'Amore 384bdb9230aSGarrett D'Amore int 385bdb9230aSGarrett D'Amore _info(struct modinfo *modinfop) 386bdb9230aSGarrett D'Amore { 38798e8d175SSteven Stallion return (mod_info(&dnet_modlinkage, modinfop)); 388bdb9230aSGarrett D'Amore } 389bdb9230aSGarrett D'Amore 390bdb9230aSGarrett D'Amore /* 391bdb9230aSGarrett D'Amore * probe(9E) -- Determine if a device is present 392bdb9230aSGarrett D'Amore */ 393bdb9230aSGarrett D'Amore static int 39498e8d175SSteven Stallion dnet_probe(dev_info_t *devinfo) 395bdb9230aSGarrett D'Amore { 396bdb9230aSGarrett D'Amore ddi_acc_handle_t handle; 397bdb9230aSGarrett D'Amore uint16_t vendorid; 398bdb9230aSGarrett D'Amore uint16_t deviceid; 399bdb9230aSGarrett D'Amore 400bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 401bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE); 402bdb9230aSGarrett D'Amore 403bdb9230aSGarrett D'Amore vendorid = pci_config_get16(handle, PCI_CONF_VENID); 404bdb9230aSGarrett D'Amore 405bdb9230aSGarrett D'Amore if (vendorid != DEC_VENDOR_ID) { 406bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 407bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE); 408bdb9230aSGarrett D'Amore } 409bdb9230aSGarrett D'Amore 410bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 411bdb9230aSGarrett D'Amore switch (deviceid) { 412bdb9230aSGarrett D'Amore case DEVICE_ID_21040: 413bdb9230aSGarrett D'Amore case DEVICE_ID_21041: 414bdb9230aSGarrett D'Amore case DEVICE_ID_21140: 415bdb9230aSGarrett D'Amore case DEVICE_ID_21143: /* And 142 */ 416bdb9230aSGarrett D'Amore break; 417bdb9230aSGarrett D'Amore default: 418bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 419bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE); 420bdb9230aSGarrett D'Amore } 421bdb9230aSGarrett D'Amore 422bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 423bdb9230aSGarrett D'Amore #ifndef BUG_4010796 424bdb9230aSGarrett D'Amore return (DDI_PROBE_SUCCESS); 425bdb9230aSGarrett D'Amore #else 42698e8d175SSteven Stallion return (dnet_hack(devinfo)); 427bdb9230aSGarrett D'Amore #endif 428bdb9230aSGarrett D'Amore } 429bdb9230aSGarrett D'Amore 430bdb9230aSGarrett D'Amore #ifdef BUG_4010796 431bdb9230aSGarrett D'Amore /* 432bdb9230aSGarrett D'Amore * If we have a device, but we cannot presently access its SROM data, 433bdb9230aSGarrett D'Amore * then we return DDI_PROBE_PARTIAL and hope that sometime later we 434bdb9230aSGarrett D'Amore * will be able to get at the SROM data. This can only happen if we 435bdb9230aSGarrett D'Amore * are a secondary port with no SROM, and the bootstrap failed to set 436bdb9230aSGarrett D'Amore * our DNET_SROM property, and our primary sibling has not yet probed. 437bdb9230aSGarrett D'Amore */ 438bdb9230aSGarrett D'Amore static int 43998e8d175SSteven Stallion dnet_hack(dev_info_t *devinfo) 440bdb9230aSGarrett D'Amore { 441bdb9230aSGarrett D'Amore uchar_t vendor_info[SROM_SIZE]; 442bdb9230aSGarrett D'Amore uint32_t csr; 443bdb9230aSGarrett D'Amore uint16_t deviceid; 444bdb9230aSGarrett D'Amore ddi_acc_handle_t handle; 445bdb9230aSGarrett D'Amore uint32_t retval; 446bdb9230aSGarrett D'Amore int secondary; 447bdb9230aSGarrett D'Amore ddi_acc_handle_t io_handle; 448bdb9230aSGarrett D'Amore caddr_t io_reg; 449bdb9230aSGarrett D'Amore 450bdb9230aSGarrett D'Amore #define DNET_PCI_RNUMBER 1 451bdb9230aSGarrett D'Amore 452bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 453bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE); 454bdb9230aSGarrett D'Amore 455bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 456bdb9230aSGarrett D'Amore 457bdb9230aSGarrett D'Amore /* 458bdb9230aSGarrett D'Amore * Turn on Master Enable and IO Enable bits. 459bdb9230aSGarrett D'Amore */ 460bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_CONF_COMM); 461bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO)); 462bdb9230aSGarrett D'Amore 463bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 464bdb9230aSGarrett D'Amore 465bdb9230aSGarrett D'Amore /* Now map I/O register */ 466bdb9230aSGarrett D'Amore if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, 467bdb9230aSGarrett D'Amore &io_reg, 0, 0, &accattr, &io_handle) != DDI_SUCCESS) { 468bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE); 469bdb9230aSGarrett D'Amore } 470bdb9230aSGarrett D'Amore 471bdb9230aSGarrett D'Amore /* 472bdb9230aSGarrett D'Amore * Reset the chip 473bdb9230aSGarrett D'Amore */ 474bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), SW_RESET); 475bdb9230aSGarrett D'Amore drv_usecwait(3); 476bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), 0); 477bdb9230aSGarrett D'Amore drv_usecwait(8); 478bdb9230aSGarrett D'Amore 479bdb9230aSGarrett D'Amore secondary = dnet_read_srom(devinfo, deviceid, io_handle, 480bdb9230aSGarrett D'Amore io_reg, vendor_info, sizeof (vendor_info)); 481bdb9230aSGarrett D'Amore 482bdb9230aSGarrett D'Amore switch (secondary) { 483bdb9230aSGarrett D'Amore case -1: 484bdb9230aSGarrett D'Amore /* We can't access our SROM data! */ 485bdb9230aSGarrett D'Amore retval = DDI_PROBE_PARTIAL; 486bdb9230aSGarrett D'Amore break; 487bdb9230aSGarrett D'Amore case 0: 488bdb9230aSGarrett D'Amore retval = DDI_PROBE_SUCCESS; 489bdb9230aSGarrett D'Amore break; 490bdb9230aSGarrett D'Amore default: 491bdb9230aSGarrett D'Amore retval = DDI_PROBE_SUCCESS; 492bdb9230aSGarrett D'Amore } 493bdb9230aSGarrett D'Amore 494bdb9230aSGarrett D'Amore ddi_regs_map_free(&io_handle); 495bdb9230aSGarrett D'Amore return (retval); 496bdb9230aSGarrett D'Amore } 497bdb9230aSGarrett D'Amore #endif /* BUG_4010796 */ 498bdb9230aSGarrett D'Amore 499bdb9230aSGarrett D'Amore /* 500bdb9230aSGarrett D'Amore * attach(9E) -- Attach a device to the system 501bdb9230aSGarrett D'Amore * 502bdb9230aSGarrett D'Amore * Called once for each board successfully probed. 503bdb9230aSGarrett D'Amore */ 504bdb9230aSGarrett D'Amore static int 50598e8d175SSteven Stallion dnet_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 506bdb9230aSGarrett D'Amore { 507bdb9230aSGarrett D'Amore uint16_t revid; 508bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; /* Our private device info */ 50998e8d175SSteven Stallion mac_register_t *macp; 510bdb9230aSGarrett D'Amore uchar_t vendor_info[SROM_SIZE]; 511bdb9230aSGarrett D'Amore uint32_t csr; 512bdb9230aSGarrett D'Amore uint16_t deviceid; 513bdb9230aSGarrett D'Amore ddi_acc_handle_t handle; 514bdb9230aSGarrett D'Amore int secondary; 515bdb9230aSGarrett D'Amore 516bdb9230aSGarrett D'Amore #define DNET_PCI_RNUMBER 1 517bdb9230aSGarrett D'Amore 518bdb9230aSGarrett D'Amore switch (cmd) { 519bdb9230aSGarrett D'Amore case DDI_ATTACH: 520bdb9230aSGarrett D'Amore break; 521bdb9230aSGarrett D'Amore 522bdb9230aSGarrett D'Amore case DDI_RESUME: 52398e8d175SSteven Stallion /* Get the driver private (dnetinstance) structure */ 52498e8d175SSteven Stallion dnetp = ddi_get_driver_private(devinfo); 525bdb9230aSGarrett D'Amore 526bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 527bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 52898e8d175SSteven Stallion dnet_reset_board(dnetp); 52998e8d175SSteven Stallion dnet_init_board(dnetp); 530bdb9230aSGarrett D'Amore dnetp->suspended = B_FALSE; 531bdb9230aSGarrett D'Amore 532bdb9230aSGarrett D'Amore if (dnetp->running) { 53398e8d175SSteven Stallion dnetp->need_tx_update = B_FALSE; 534bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 53598e8d175SSteven Stallion (void) dnet_start(dnetp); 536bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 53798e8d175SSteven Stallion mac_tx_update(dnetp->mac_handle); 538bdb9230aSGarrett D'Amore } else { 539bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 540bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 541bdb9230aSGarrett D'Amore } 542bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 543bdb9230aSGarrett D'Amore default: 544bdb9230aSGarrett D'Amore return (DDI_FAILURE); 545bdb9230aSGarrett D'Amore } 54698e8d175SSteven Stallion 547bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS) 548bdb9230aSGarrett D'Amore return (DDI_FAILURE); 549bdb9230aSGarrett D'Amore 550bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID); 551bdb9230aSGarrett D'Amore switch (deviceid) { 552bdb9230aSGarrett D'Amore case DEVICE_ID_21040: 553bdb9230aSGarrett D'Amore case DEVICE_ID_21041: 554bdb9230aSGarrett D'Amore case DEVICE_ID_21140: 555bdb9230aSGarrett D'Amore case DEVICE_ID_21143: /* And 142 */ 556bdb9230aSGarrett D'Amore break; 557bdb9230aSGarrett D'Amore default: 558bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 559bdb9230aSGarrett D'Amore return (DDI_FAILURE); 560bdb9230aSGarrett D'Amore } 561bdb9230aSGarrett D'Amore 562bdb9230aSGarrett D'Amore /* 563bdb9230aSGarrett D'Amore * Turn on Master Enable and IO Enable bits. 564bdb9230aSGarrett D'Amore */ 565bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_CONF_COMM); 566bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO)); 567bdb9230aSGarrett D'Amore 568bdb9230aSGarrett D'Amore /* Make sure the device is not asleep */ 569bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_DNET_CONF_CFDD); 570bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_DNET_CONF_CFDD, 571bdb9230aSGarrett D'Amore csr & ~(CFDD_SLEEP|CFDD_SNOOZE)); 572bdb9230aSGarrett D'Amore 573bdb9230aSGarrett D'Amore revid = pci_config_get8(handle, PCI_CONF_REVID); 574bdb9230aSGarrett D'Amore pci_config_teardown(&handle); 575bdb9230aSGarrett D'Amore 57698e8d175SSteven Stallion dnetp = kmem_zalloc(sizeof (struct dnetinstance), KM_SLEEP); 57798e8d175SSteven Stallion ddi_set_driver_private(devinfo, dnetp); 578bdb9230aSGarrett D'Amore 579bdb9230aSGarrett D'Amore /* Now map I/O register */ 580bdb9230aSGarrett D'Amore if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, &dnetp->io_reg, 581bdb9230aSGarrett D'Amore 0, 0, &accattr, &dnetp->io_handle) != DDI_SUCCESS) { 582bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance)); 583bdb9230aSGarrett D'Amore return (DDI_FAILURE); 584bdb9230aSGarrett D'Amore } 585bdb9230aSGarrett D'Amore 586bdb9230aSGarrett D'Amore dnetp->devinfo = devinfo; 587bdb9230aSGarrett D'Amore dnetp->board_type = deviceid; 588bdb9230aSGarrett D'Amore 589bdb9230aSGarrett D'Amore /* 590bdb9230aSGarrett D'Amore * Get the iblock cookie with which to initialize the mutexes. 591bdb9230aSGarrett D'Amore */ 59298e8d175SSteven Stallion if (ddi_get_iblock_cookie(devinfo, 0, &dnetp->icookie) 593bdb9230aSGarrett D'Amore != DDI_SUCCESS) 594bdb9230aSGarrett D'Amore goto fail; 595bdb9230aSGarrett D'Amore 596bdb9230aSGarrett D'Amore /* 597bdb9230aSGarrett D'Amore * Initialize mutex's for this device. 598bdb9230aSGarrett D'Amore * Do this before registering the interrupt handler to avoid 599bdb9230aSGarrett D'Amore * condition where interrupt handler can try using uninitialized 600bdb9230aSGarrett D'Amore * mutex. 601bdb9230aSGarrett D'Amore * Lock ordering rules: always lock intrlock first before 602bdb9230aSGarrett D'Amore * txlock if both are required. 603bdb9230aSGarrett D'Amore */ 60498e8d175SSteven Stallion mutex_init(&dnetp->txlock, NULL, MUTEX_DRIVER, dnetp->icookie); 60598e8d175SSteven Stallion mutex_init(&dnetp->intrlock, NULL, MUTEX_DRIVER, dnetp->icookie); 606bdb9230aSGarrett D'Amore 607bdb9230aSGarrett D'Amore /* 608bdb9230aSGarrett D'Amore * Get the BNC/TP indicator from the conf file for 21040 609bdb9230aSGarrett D'Amore */ 610bdb9230aSGarrett D'Amore dnetp->bnc_indicator = 611bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 612bdb9230aSGarrett D'Amore "bncaui", -1); 613bdb9230aSGarrett D'Amore 614bdb9230aSGarrett D'Amore /* 615bdb9230aSGarrett D'Amore * For 21140 check the data rate set in the conf file. Default is 616bdb9230aSGarrett D'Amore * 100Mb/s. Disallow connections at settings that would conflict 617bdb9230aSGarrett D'Amore * with what's in the conf file 618bdb9230aSGarrett D'Amore */ 619bdb9230aSGarrett D'Amore dnetp->speed = 620bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 621bdb9230aSGarrett D'Amore speed_propname, 0); 622bdb9230aSGarrett D'Amore dnetp->full_duplex = 623bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 624bdb9230aSGarrett D'Amore duplex_propname, -1); 625bdb9230aSGarrett D'Amore 626bdb9230aSGarrett D'Amore if (dnetp->speed == 100) { 627bdb9230aSGarrett D'Amore dnetp->disallowed_media |= (1UL<<MEDIA_TP) | (1UL<<MEDIA_TP_FD); 628bdb9230aSGarrett D'Amore } else if (dnetp->speed == 10) { 629bdb9230aSGarrett D'Amore dnetp->disallowed_media |= 630bdb9230aSGarrett D'Amore (1UL<<MEDIA_SYM_SCR) | (1UL<<MEDIA_SYM_SCR_FD); 631bdb9230aSGarrett D'Amore } 632bdb9230aSGarrett D'Amore 633bdb9230aSGarrett D'Amore if (dnetp->full_duplex == 1) { 634bdb9230aSGarrett D'Amore dnetp->disallowed_media |= 635bdb9230aSGarrett D'Amore (1UL<<MEDIA_TP) | (1UL<<MEDIA_SYM_SCR); 636bdb9230aSGarrett D'Amore } else if (dnetp->full_duplex == 0) { 637bdb9230aSGarrett D'Amore dnetp->disallowed_media |= 638bdb9230aSGarrett D'Amore (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_SYM_SCR_FD); 639bdb9230aSGarrett D'Amore } 640bdb9230aSGarrett D'Amore 641bdb9230aSGarrett D'Amore if (dnetp->bnc_indicator == 0) /* Disable BNC and AUI media */ 642bdb9230aSGarrett D'Amore dnetp->disallowed_media |= (1UL<<MEDIA_BNC) | (1UL<<MEDIA_AUI); 643bdb9230aSGarrett D'Amore else if (dnetp->bnc_indicator == 1) /* Force BNC only */ 644bdb9230aSGarrett D'Amore dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_BNC); 645bdb9230aSGarrett D'Amore else if (dnetp->bnc_indicator == 2) /* Force AUI only */ 646bdb9230aSGarrett D'Amore dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_AUI); 647bdb9230aSGarrett D'Amore 64898e8d175SSteven Stallion dnet_reset_board(dnetp); 649bdb9230aSGarrett D'Amore 650bdb9230aSGarrett D'Amore secondary = dnet_read_srom(devinfo, dnetp->board_type, dnetp->io_handle, 651bdb9230aSGarrett D'Amore dnetp->io_reg, vendor_info, sizeof (vendor_info)); 652bdb9230aSGarrett D'Amore 653bdb9230aSGarrett D'Amore if (secondary == -1) /* ASSERT (vendor_info not big enough) */ 654bdb9230aSGarrett D'Amore goto fail1; 655bdb9230aSGarrett D'Amore 656bdb9230aSGarrett D'Amore dnet_parse_srom(dnetp, &dnetp->sr, vendor_info); 657bdb9230aSGarrett D'Amore 658bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 659bdb9230aSGarrett D'Amore printsrom_propname, 0)) 660bdb9230aSGarrett D'Amore dnet_print_srom(&dnetp->sr); 661bdb9230aSGarrett D'Amore 662bdb9230aSGarrett D'Amore dnetp->sr.netaddr[ETHERADDRL-1] += secondary; /* unique ether addr */ 663bdb9230aSGarrett D'Amore 664bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->sr.netaddr, 665bdb9230aSGarrett D'Amore (caddr_t)dnetp->vendor_addr, ETHERADDRL); 666bdb9230aSGarrett D'Amore 667bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->sr.netaddr, 668bdb9230aSGarrett D'Amore (caddr_t)dnetp->curr_macaddr, ETHERADDRL); 669bdb9230aSGarrett D'Amore 670bdb9230aSGarrett D'Amore /* 671bdb9230aSGarrett D'Amore * determine whether to implement workaround from DEC 672bdb9230aSGarrett D'Amore * for DMA overrun errata. 673bdb9230aSGarrett D'Amore */ 674bdb9230aSGarrett D'Amore dnetp->overrun_workaround = 675bdb9230aSGarrett D'Amore ((dnetp->board_type == DEVICE_ID_21140 && revid >= 0x20) || 676bdb9230aSGarrett D'Amore (dnetp->board_type == DEVICE_ID_21143 && revid <= 0x30)) ? 1 : 0; 677bdb9230aSGarrett D'Amore 678bdb9230aSGarrett D'Amore dnetp->overrun_workaround = 679bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 680bdb9230aSGarrett D'Amore ofloprob_propname, dnetp->overrun_workaround); 681bdb9230aSGarrett D'Amore 682bdb9230aSGarrett D'Amore /* 683bdb9230aSGarrett D'Amore * Add the interrupt handler if dnet_hack_interrupts() returns 0. 684bdb9230aSGarrett D'Amore * Otherwise dnet_hack_interrupts() itself adds the handler. 685bdb9230aSGarrett D'Amore */ 68698e8d175SSteven Stallion if (!dnet_hack_interrupts(dnetp, secondary)) { 687bdb9230aSGarrett D'Amore (void) ddi_add_intr(devinfo, 0, NULL, 68898e8d175SSteven Stallion NULL, dnet_intr, (caddr_t)dnetp); 689bdb9230aSGarrett D'Amore } 690bdb9230aSGarrett D'Amore 691bdb9230aSGarrett D'Amore dnetp->max_tx_desc = max_tx_desc; 692bdb9230aSGarrett D'Amore dnetp->max_rx_desc = max_rx_desc_21040; 693bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040 && 694bdb9230aSGarrett D'Amore dnetp->board_type != DEVICE_ID_21041 && 695bdb9230aSGarrett D'Amore dnetp->speed != 10) 696bdb9230aSGarrett D'Amore dnetp->max_rx_desc = max_rx_desc_21140; 697bdb9230aSGarrett D'Amore 698bdb9230aSGarrett D'Amore /* Allocate the TX and RX descriptors/buffers. */ 69998e8d175SSteven Stallion if (dnet_alloc_bufs(dnetp) == FAILURE) { 700bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Not enough DMA memory for buffers."); 701bdb9230aSGarrett D'Amore goto fail2; 702bdb9230aSGarrett D'Amore } 703bdb9230aSGarrett D'Amore 704bdb9230aSGarrett D'Amore /* 70598e8d175SSteven Stallion * Register ourselves with the GLDv3 interface 706bdb9230aSGarrett D'Amore */ 70798e8d175SSteven Stallion if ((macp = mac_alloc(MAC_VERSION)) == NULL) 70898e8d175SSteven Stallion goto fail2; 709bdb9230aSGarrett D'Amore 71098e8d175SSteven Stallion macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 71198e8d175SSteven Stallion macp->m_driver = dnetp; 71298e8d175SSteven Stallion macp->m_dip = devinfo; 71398e8d175SSteven Stallion macp->m_src_addr = dnetp->curr_macaddr; 71498e8d175SSteven Stallion macp->m_callbacks = &dnet_m_callbacks; 71598e8d175SSteven Stallion macp->m_min_sdu = 0; 71698e8d175SSteven Stallion macp->m_max_sdu = ETHERMTU; 71798e8d175SSteven Stallion macp->m_margin = VLAN_TAGSZ; 71898e8d175SSteven Stallion 71998e8d175SSteven Stallion if (mac_register(macp, &dnetp->mac_handle) == 0) { 72098e8d175SSteven Stallion mac_free(macp); 72198e8d175SSteven Stallion 722bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 72398e8d175SSteven Stallion 724bdb9230aSGarrett D'Amore dnetp->phyaddr = -1; 725bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140 || 726bdb9230aSGarrett D'Amore dnetp->board_type == DEVICE_ID_21143) 72798e8d175SSteven Stallion do_phy(dnetp); /* Initialize the PHY, if any */ 72898e8d175SSteven Stallion find_active_media(dnetp); 729bdb9230aSGarrett D'Amore 730bdb9230aSGarrett D'Amore /* if the chosen media is non-MII, stop the port monitor */ 731bdb9230aSGarrett D'Amore if (dnetp->selected_media_block->media_code != MEDIA_MII && 732bdb9230aSGarrett D'Amore dnetp->mii != NULL) { 733bdb9230aSGarrett D'Amore mii_destroy(dnetp->mii); 734bdb9230aSGarrett D'Amore dnetp->mii = NULL; 735bdb9230aSGarrett D'Amore dnetp->phyaddr = -1; 736bdb9230aSGarrett D'Amore } 737bdb9230aSGarrett D'Amore 738bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 739bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 740bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: link configured : %s", 741bdb9230aSGarrett D'Amore media_str[dnetp->selected_media_block->media_code]); 742bdb9230aSGarrett D'Amore #endif 743bdb9230aSGarrett D'Amore bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE); 74498e8d175SSteven Stallion 74598e8d175SSteven Stallion dnet_reset_board(dnetp); 74698e8d175SSteven Stallion dnet_init_board(dnetp); 74798e8d175SSteven Stallion 748bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 74998e8d175SSteven Stallion 75098e8d175SSteven Stallion (void) dnet_m_unicst(dnetp, dnetp->curr_macaddr); 75198e8d175SSteven Stallion (void) dnet_m_multicst(dnetp, B_TRUE, dnet_broadcastaddr); 75298e8d175SSteven Stallion 753bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 754bdb9230aSGarrett D'Amore } 75598e8d175SSteven Stallion 75698e8d175SSteven Stallion mac_free(macp); 757bdb9230aSGarrett D'Amore fail2: 758bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 759bdb9230aSGarrett D'Amore /* 760bdb9230aSGarrett D'Amore * dnet_detach_hacked_interrupt() will remove 761bdb9230aSGarrett D'Amore * interrupt for the non-hacked case also. 762bdb9230aSGarrett D'Amore */ 763bdb9230aSGarrett D'Amore (void) dnet_detach_hacked_interrupt(devinfo); 76498e8d175SSteven Stallion dnet_free_bufs(dnetp); 765bdb9230aSGarrett D'Amore fail1: 766bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->txlock); 767bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->intrlock); 768bdb9230aSGarrett D'Amore fail: 769bdb9230aSGarrett D'Amore ddi_regs_map_free(&dnetp->io_handle); 770bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance)); 771bdb9230aSGarrett D'Amore return (DDI_FAILURE); 772bdb9230aSGarrett D'Amore } 773bdb9230aSGarrett D'Amore 774bdb9230aSGarrett D'Amore /* 775bdb9230aSGarrett D'Amore * detach(9E) -- Detach a device from the system 776bdb9230aSGarrett D'Amore */ 777bdb9230aSGarrett D'Amore static int 77898e8d175SSteven Stallion dnet_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 779bdb9230aSGarrett D'Amore { 780bdb9230aSGarrett D'Amore int32_t rc; 781bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; /* Our private device info */ 782bdb9230aSGarrett D'Amore int32_t proplen; 783bdb9230aSGarrett D'Amore 78498e8d175SSteven Stallion /* Get the driver private (dnetinstance) structure */ 78598e8d175SSteven Stallion dnetp = ddi_get_driver_private(devinfo); 786bdb9230aSGarrett D'Amore 787bdb9230aSGarrett D'Amore switch (cmd) { 788bdb9230aSGarrett D'Amore case DDI_DETACH: 789bdb9230aSGarrett D'Amore break; 790bdb9230aSGarrett D'Amore 791bdb9230aSGarrett D'Amore case DDI_SUSPEND: 792bdb9230aSGarrett D'Amore /* 793bdb9230aSGarrett D'Amore * NB: dnetp->suspended can only be modified (marked true) 794bdb9230aSGarrett D'Amore * if both intrlock and txlock are held. This keeps both 795bdb9230aSGarrett D'Amore * tx and rx code paths excluded. 796bdb9230aSGarrett D'Amore */ 797bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 798bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 799bdb9230aSGarrett D'Amore dnetp->suspended = B_TRUE; 80098e8d175SSteven Stallion dnet_reset_board(dnetp); 801bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 802bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 803bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 804bdb9230aSGarrett D'Amore 805bdb9230aSGarrett D'Amore default: 806bdb9230aSGarrett D'Amore return (DDI_FAILURE); 807bdb9230aSGarrett D'Amore } 808bdb9230aSGarrett D'Amore 809bdb9230aSGarrett D'Amore /* 81098e8d175SSteven Stallion * Unregister ourselves from the GLDv3 interface 811bdb9230aSGarrett D'Amore */ 81298e8d175SSteven Stallion if (mac_unregister(dnetp->mac_handle) != 0) 813bdb9230aSGarrett D'Amore return (DDI_FAILURE); 814bdb9230aSGarrett D'Amore 815bdb9230aSGarrett D'Amore /* stop the board if it is running */ 81698e8d175SSteven Stallion dnet_reset_board(dnetp); 817bdb9230aSGarrett D'Amore 818bdb9230aSGarrett D'Amore if ((rc = dnet_detach_hacked_interrupt(devinfo)) != DDI_SUCCESS) 819bdb9230aSGarrett D'Amore return (rc); 820bdb9230aSGarrett D'Amore 821bdb9230aSGarrett D'Amore if (dnetp->mii != NULL) 822bdb9230aSGarrett D'Amore mii_destroy(dnetp->mii); 823bdb9230aSGarrett D'Amore 824bdb9230aSGarrett D'Amore /* Free leaf information */ 825bdb9230aSGarrett D'Amore set_leaf(&dnetp->sr, NULL); 826bdb9230aSGarrett D'Amore 827bdb9230aSGarrett D'Amore ddi_regs_map_free(&dnetp->io_handle); 82898e8d175SSteven Stallion dnet_free_bufs(dnetp); 829bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->txlock); 830bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->intrlock); 831bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance)); 832bdb9230aSGarrett D'Amore 833bdb9230aSGarrett D'Amore #ifdef BUG_4010796 834bdb9230aSGarrett D'Amore if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, 0, 835bdb9230aSGarrett D'Amore "DNET_HACK", &proplen) != DDI_PROP_SUCCESS) 836bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 837bdb9230aSGarrett D'Amore 838bdb9230aSGarrett D'Amore /* 839bdb9230aSGarrett D'Amore * We must remove the properties we added, because if we leave 840bdb9230aSGarrett D'Amore * them in the devinfo nodes and the driver is unloaded, when 841bdb9230aSGarrett D'Amore * the driver is reloaded the info will still be there, causing 842bdb9230aSGarrett D'Amore * nodes which had returned PROBE_PARTIAL the first time to 843bdb9230aSGarrett D'Amore * instead return PROBE_SUCCESS, in turn causing the nodes to be 844bdb9230aSGarrett D'Amore * attached in a different order, causing their PPA numbers to 845bdb9230aSGarrett D'Amore * be different the second time around, which is undesirable. 846bdb9230aSGarrett D'Amore */ 847bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, devinfo, "DNET_HACK"); 848bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 849bdb9230aSGarrett D'Amore "DNET_SROM"); 850bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 851bdb9230aSGarrett D'Amore "DNET_DEVNUM"); 852bdb9230aSGarrett D'Amore #endif 853bdb9230aSGarrett D'Amore 854bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 855bdb9230aSGarrett D'Amore } 856bdb9230aSGarrett D'Amore 85798e8d175SSteven Stallion int 85898e8d175SSteven Stallion dnet_quiesce(dev_info_t *dip) 859bdb9230aSGarrett D'Amore { 86098e8d175SSteven Stallion struct dnetinstance *dnetp = ddi_get_driver_private(dip); 861bdb9230aSGarrett D'Amore 862bdb9230aSGarrett D'Amore /* 86398e8d175SSteven Stallion * Reset chip (disables interrupts). 864bdb9230aSGarrett D'Amore */ 86598e8d175SSteven Stallion ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0); 86698e8d175SSteven Stallion ddi_put32(dnetp->io_handle, 86798e8d175SSteven Stallion REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET); 868bdb9230aSGarrett D'Amore 86998e8d175SSteven Stallion return (DDI_SUCCESS); 870bdb9230aSGarrett D'Amore } 871bdb9230aSGarrett D'Amore 872bdb9230aSGarrett D'Amore static void 87398e8d175SSteven Stallion dnet_reset_board(struct dnetinstance *dnetp) 874bdb9230aSGarrett D'Amore { 875bdb9230aSGarrett D'Amore uint32_t val; 876bdb9230aSGarrett D'Amore 877bdb9230aSGarrett D'Amore /* 878bdb9230aSGarrett D'Amore * before initializing the dnet should be in STOP state 879bdb9230aSGarrett D'Amore */ 880bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 881bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 882bdb9230aSGarrett D'Amore val & ~(START_TRANSMIT | START_RECEIVE)); 883bdb9230aSGarrett D'Amore 884bdb9230aSGarrett D'Amore /* 885bdb9230aSGarrett D'Amore * Reset the chip 886bdb9230aSGarrett D'Amore */ 887bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0); 888bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 889bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET); 890bdb9230aSGarrett D'Amore drv_usecwait(5); 891bdb9230aSGarrett D'Amore } 892bdb9230aSGarrett D'Amore 893bdb9230aSGarrett D'Amore /* 894bdb9230aSGarrett D'Amore * dnet_init_board() -- initialize the specified network board short of 895bdb9230aSGarrett D'Amore * actually starting the board. Call after dnet_reset_board(). 896bdb9230aSGarrett D'Amore * called with intrlock held. 897bdb9230aSGarrett D'Amore */ 898bdb9230aSGarrett D'Amore static void 89998e8d175SSteven Stallion dnet_init_board(struct dnetinstance *dnetp) 900bdb9230aSGarrett D'Amore { 90198e8d175SSteven Stallion set_opr(dnetp); 90298e8d175SSteven Stallion set_gpr(dnetp); 90398e8d175SSteven Stallion set_sia(dnetp); 90498e8d175SSteven Stallion dnet_chip_init(dnetp); 905bdb9230aSGarrett D'Amore } 906bdb9230aSGarrett D'Amore 907bdb9230aSGarrett D'Amore /* dnet_chip_init() - called with intrlock held */ 908bdb9230aSGarrett D'Amore static void 90998e8d175SSteven Stallion dnet_chip_init(struct dnetinstance *dnetp) 910bdb9230aSGarrett D'Amore { 911bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, BUS_MODE_REG), 912bdb9230aSGarrett D'Amore CACHE_ALIGN | BURST_SIZE); /* CSR0 */ 913bdb9230aSGarrett D'Amore 914bdb9230aSGarrett D'Amore /* 915bdb9230aSGarrett D'Amore * Initialize the TX and RX descriptors/buffers 916bdb9230aSGarrett D'Amore */ 91798e8d175SSteven Stallion dnet_init_txrx_bufs(dnetp); 918bdb9230aSGarrett D'Amore 919bdb9230aSGarrett D'Amore /* 920bdb9230aSGarrett D'Amore * Set the base address of the Rx descriptor list in CSR3 921bdb9230aSGarrett D'Amore */ 922bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, RX_BASE_ADDR_REG), 923bdb9230aSGarrett D'Amore dnetp->rx_desc_paddr); 924bdb9230aSGarrett D'Amore 925bdb9230aSGarrett D'Amore /* 926bdb9230aSGarrett D'Amore * Set the base address of the Tx descrptor list in CSR4 927bdb9230aSGarrett D'Amore */ 928bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_BASE_ADDR_REG), 929bdb9230aSGarrett D'Amore dnetp->tx_desc_paddr); 930bdb9230aSGarrett D'Amore 931bdb9230aSGarrett D'Amore dnetp->tx_current_desc = dnetp->rx_current_desc = 0; 932bdb9230aSGarrett D'Amore dnetp->transmitted_desc = 0; 933bdb9230aSGarrett D'Amore dnetp->free_desc = dnetp->max_tx_desc; 93498e8d175SSteven Stallion enable_interrupts(dnetp); 935bdb9230aSGarrett D'Amore } 936bdb9230aSGarrett D'Amore 937bdb9230aSGarrett D'Amore /* 938bdb9230aSGarrett D'Amore * dnet_start() -- start the board receiving and allow transmits. 939bdb9230aSGarrett D'Amore * Called with intrlock held. 940bdb9230aSGarrett D'Amore */ 941bdb9230aSGarrett D'Amore static int 94298e8d175SSteven Stallion dnet_start(struct dnetinstance *dnetp) 943bdb9230aSGarrett D'Amore { 944bdb9230aSGarrett D'Amore uint32_t val; 945bdb9230aSGarrett D'Amore 946bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 947bdb9230aSGarrett D'Amore /* 948bdb9230aSGarrett D'Amore * start the board and enable receiving 949bdb9230aSGarrett D'Amore */ 950bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 951bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 952bdb9230aSGarrett D'Amore val | START_TRANSMIT); 95398e8d175SSteven Stallion (void) dnet_set_addr(dnetp); 954bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 955bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 956bdb9230aSGarrett D'Amore val | START_RECEIVE); 95798e8d175SSteven Stallion enable_interrupts(dnetp); 958bdb9230aSGarrett D'Amore return (0); 959bdb9230aSGarrett D'Amore } 960bdb9230aSGarrett D'Amore 961bdb9230aSGarrett D'Amore static int 96298e8d175SSteven Stallion dnet_m_start(void *arg) 963bdb9230aSGarrett D'Amore { 96498e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 965bdb9230aSGarrett D'Amore 966bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 967bdb9230aSGarrett D'Amore dnetp->running = B_TRUE; 968bdb9230aSGarrett D'Amore /* 969bdb9230aSGarrett D'Amore * start the board and enable receiving 970bdb9230aSGarrett D'Amore */ 971bdb9230aSGarrett D'Amore if (!dnetp->suspended) 97298e8d175SSteven Stallion (void) dnet_start(dnetp); 973bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 974bdb9230aSGarrett D'Amore return (0); 975bdb9230aSGarrett D'Amore } 976bdb9230aSGarrett D'Amore 97798e8d175SSteven Stallion static void 97898e8d175SSteven Stallion dnet_m_stop(void *arg) 979bdb9230aSGarrett D'Amore { 98098e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 981bdb9230aSGarrett D'Amore uint32_t val; 982bdb9230aSGarrett D'Amore 983bdb9230aSGarrett D'Amore /* 984bdb9230aSGarrett D'Amore * stop the board and disable transmit/receive 985bdb9230aSGarrett D'Amore */ 986bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 987bdb9230aSGarrett D'Amore if (!dnetp->suspended) { 988bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, 989bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG)); 990bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), 991bdb9230aSGarrett D'Amore val & ~(START_TRANSMIT | START_RECEIVE)); 992bdb9230aSGarrett D'Amore } 99332607e28SSteven Stallion mac_link_update(dnetp->mac_handle, LINK_STATE_UNKNOWN); 994bdb9230aSGarrett D'Amore dnetp->running = B_FALSE; 995bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 996bdb9230aSGarrett D'Amore } 997bdb9230aSGarrett D'Amore 998bdb9230aSGarrett D'Amore /* 999bdb9230aSGarrett D'Amore * dnet_set_addr() -- set the physical network address on the board 1000bdb9230aSGarrett D'Amore * Called with intrlock held. 1001bdb9230aSGarrett D'Amore */ 1002bdb9230aSGarrett D'Amore static int 100398e8d175SSteven Stallion dnet_set_addr(struct dnetinstance *dnetp) 1004bdb9230aSGarrett D'Amore { 1005bdb9230aSGarrett D'Amore struct tx_desc_type *desc; 1006bdb9230aSGarrett D'Amore int current_desc; 1007bdb9230aSGarrett D'Amore uint32_t val; 1008bdb9230aSGarrett D'Amore 1009bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 1010bdb9230aSGarrett D'Amore 1011bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG)); 1012bdb9230aSGarrett D'Amore if (!(val & START_TRANSMIT)) 1013bdb9230aSGarrett D'Amore return (0); 1014bdb9230aSGarrett D'Amore 1015bdb9230aSGarrett D'Amore current_desc = dnetp->tx_current_desc; 1016bdb9230aSGarrett D'Amore desc = &dnetp->tx_desc[current_desc]; 1017bdb9230aSGarrett D'Amore 1018bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 1019bdb9230aSGarrett D'Amore dnetp->need_saddr = 0; 1020bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 1021bdb9230aSGarrett D'Amore 102298e8d175SSteven Stallion if ((alloc_descriptor(dnetp)) == FAILURE) { 1023bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 1024bdb9230aSGarrett D'Amore dnetp->need_saddr = 1; 1025bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 1026bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 1027bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE) 1028bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET saddr:alloc descriptor failure"); 1029bdb9230aSGarrett D'Amore #endif 1030bdb9230aSGarrett D'Amore return (0); 1031bdb9230aSGarrett D'Amore } 1032bdb9230aSGarrett D'Amore 1033bdb9230aSGarrett D'Amore desc->buffer1 = dnetp->setup_buf_paddr; 1034bdb9230aSGarrett D'Amore desc->buffer2 = 0; 1035bdb9230aSGarrett D'Amore desc->desc1.buffer_size1 = SETUPBUF_SIZE; 1036bdb9230aSGarrett D'Amore desc->desc1.buffer_size2 = 0; 1037bdb9230aSGarrett D'Amore desc->desc1.setup_packet = 1; 1038bdb9230aSGarrett D'Amore desc->desc1.first_desc = 0; 1039bdb9230aSGarrett D'Amore desc->desc1.last_desc = 0; 1040bdb9230aSGarrett D'Amore desc->desc1.filter_type0 = 1; 1041bdb9230aSGarrett D'Amore desc->desc1.filter_type1 = 1; 1042bdb9230aSGarrett D'Amore desc->desc1.int_on_comp = 1; 1043bdb9230aSGarrett D'Amore 1044bdb9230aSGarrett D'Amore desc->desc0.own = 1; 1045bdb9230aSGarrett D'Amore ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG), 1046bdb9230aSGarrett D'Amore TX_POLL_DEMAND); 1047bdb9230aSGarrett D'Amore return (0); 1048bdb9230aSGarrett D'Amore } 1049bdb9230aSGarrett D'Amore 1050bdb9230aSGarrett D'Amore static int 105198e8d175SSteven Stallion dnet_m_unicst(void *arg, const uint8_t *macaddr) 1052bdb9230aSGarrett D'Amore { 105398e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 1054bdb9230aSGarrett D'Amore uint32_t index; 1055bdb9230aSGarrett D'Amore uint32_t *hashp; 1056bdb9230aSGarrett D'Amore 1057bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 1058bdb9230aSGarrett D'Amore 1059bdb9230aSGarrett D'Amore bcopy(macaddr, dnetp->curr_macaddr, ETHERADDRL); 1060bdb9230aSGarrett D'Amore 1061bdb9230aSGarrett D'Amore /* 1062bdb9230aSGarrett D'Amore * As we are using Imperfect filtering, the broadcast address has to 1063bdb9230aSGarrett D'Amore * be set explicitly in the 512 bit hash table. Hence the index into 1064bdb9230aSGarrett D'Amore * the hash table is calculated and the bit set to enable reception 1065bdb9230aSGarrett D'Amore * of broadcast packets. 1066bdb9230aSGarrett D'Amore * 1067bdb9230aSGarrett D'Amore * We also use HASH_ONLY mode, without using the perfect filter for 1068bdb9230aSGarrett D'Amore * our station address, because there appears to be a bug in the 1069bdb9230aSGarrett D'Amore * 21140 where it fails to receive the specified perfect filter 1070bdb9230aSGarrett D'Amore * address. 1071bdb9230aSGarrett D'Amore * 1072bdb9230aSGarrett D'Amore * Since dlsdmult comes through here, it doesn't matter that the count 1073bdb9230aSGarrett D'Amore * is wrong for the two bits that correspond to the cases below. The 1074bdb9230aSGarrett D'Amore * worst that could happen is that we'd leave on a bit for an old 1075bdb9230aSGarrett D'Amore * macaddr, in the case where the macaddr gets changed, which is rare. 1076bdb9230aSGarrett D'Amore * Since filtering is imperfect, it is OK if that happens. 1077bdb9230aSGarrett D'Amore */ 1078bdb9230aSGarrett D'Amore hashp = (uint32_t *)dnetp->setup_buf_vaddr; 107998e8d175SSteven Stallion index = hashindex((uint8_t *)dnet_broadcastaddr); 1080bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16); 1081bdb9230aSGarrett D'Amore 108298e8d175SSteven Stallion index = hashindex((uint8_t *)dnetp->curr_macaddr); 1083bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16); 1084bdb9230aSGarrett D'Amore 1085bdb9230aSGarrett D'Amore if (!dnetp->suspended) 108698e8d175SSteven Stallion (void) dnet_set_addr(dnetp); 1087bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1088bdb9230aSGarrett D'Amore return (0); 1089bdb9230aSGarrett D'Amore } 1090bdb9230aSGarrett D'Amore 1091bdb9230aSGarrett D'Amore static int 109298e8d175SSteven Stallion dnet_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 1093bdb9230aSGarrett D'Amore { 109498e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 1095bdb9230aSGarrett D'Amore uint32_t index; 1096bdb9230aSGarrett D'Amore uint32_t *hashp; 1097bdb9230aSGarrett D'Amore uint32_t retval; 1098bdb9230aSGarrett D'Amore 1099bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 110098e8d175SSteven Stallion index = hashindex(macaddr); 1101bdb9230aSGarrett D'Amore hashp = (uint32_t *)dnetp->setup_buf_vaddr; 110298e8d175SSteven Stallion if (add) { 1103bdb9230aSGarrett D'Amore if (dnetp->multicast_cnt[index]++) { 1104bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1105bdb9230aSGarrett D'Amore return (0); 1106bdb9230aSGarrett D'Amore } 1107bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16); 1108bdb9230aSGarrett D'Amore } else { 1109bdb9230aSGarrett D'Amore if (--dnetp->multicast_cnt[index]) { 1110bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1111bdb9230aSGarrett D'Amore return (0); 1112bdb9230aSGarrett D'Amore } 1113bdb9230aSGarrett D'Amore hashp[ index / 16 ] &= ~ (1 << (index % 16)); 1114bdb9230aSGarrett D'Amore } 1115bdb9230aSGarrett D'Amore if (!dnetp->suspended) 111698e8d175SSteven Stallion retval = dnet_set_addr(dnetp); 1117bdb9230aSGarrett D'Amore else 1118bdb9230aSGarrett D'Amore retval = 0; 1119bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1120bdb9230aSGarrett D'Amore return (retval); 1121bdb9230aSGarrett D'Amore } 1122bdb9230aSGarrett D'Amore 1123bdb9230aSGarrett D'Amore /* 1124bdb9230aSGarrett D'Amore * A hashing function used for setting the 1125bdb9230aSGarrett D'Amore * node address or a multicast address 1126bdb9230aSGarrett D'Amore */ 1127bdb9230aSGarrett D'Amore static uint32_t 112898e8d175SSteven Stallion hashindex(const uint8_t *address) 1129bdb9230aSGarrett D'Amore { 1130bdb9230aSGarrett D'Amore uint32_t crc = (uint32_t)HASH_CRC; 1131bdb9230aSGarrett D'Amore uint32_t const POLY = HASH_POLY; 1132bdb9230aSGarrett D'Amore uint32_t msb; 1133bdb9230aSGarrett D'Amore int32_t byteslength; 1134bdb9230aSGarrett D'Amore uint8_t currentbyte; 1135bdb9230aSGarrett D'Amore uint32_t index; 1136bdb9230aSGarrett D'Amore int32_t bit; 1137bdb9230aSGarrett D'Amore int32_t shift; 1138bdb9230aSGarrett D'Amore 1139bdb9230aSGarrett D'Amore for (byteslength = 0; byteslength < ETHERADDRL; byteslength++) { 1140bdb9230aSGarrett D'Amore currentbyte = address[byteslength]; 1141bdb9230aSGarrett D'Amore for (bit = 0; bit < 8; bit++) { 1142bdb9230aSGarrett D'Amore msb = crc >> 31; 1143bdb9230aSGarrett D'Amore crc <<= 1; 1144bdb9230aSGarrett D'Amore if (msb ^ (currentbyte & 1)) { 1145bdb9230aSGarrett D'Amore crc ^= POLY; 1146bdb9230aSGarrett D'Amore crc |= 0x00000001; 1147bdb9230aSGarrett D'Amore } 1148bdb9230aSGarrett D'Amore currentbyte >>= 1; 1149bdb9230aSGarrett D'Amore } 1150bdb9230aSGarrett D'Amore } 1151bdb9230aSGarrett D'Amore 1152bdb9230aSGarrett D'Amore for (index = 0, bit = 23, shift = 8; shift >= 0; bit++, shift--) { 1153bdb9230aSGarrett D'Amore index |= (((crc >> bit) & 1) << shift); 1154bdb9230aSGarrett D'Amore } 1155bdb9230aSGarrett D'Amore return (index); 1156bdb9230aSGarrett D'Amore } 1157bdb9230aSGarrett D'Amore 1158bdb9230aSGarrett D'Amore static int 115998e8d175SSteven Stallion dnet_m_setpromisc(void *arg, boolean_t on) 1160bdb9230aSGarrett D'Amore { 116198e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 1162bdb9230aSGarrett D'Amore uint32_t val; 1163bdb9230aSGarrett D'Amore 1164bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 1165bdb9230aSGarrett D'Amore if (dnetp->promisc == on) { 1166bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 116798e8d175SSteven Stallion return (0); 1168bdb9230aSGarrett D'Amore } 1169bdb9230aSGarrett D'Amore dnetp->promisc = on; 1170bdb9230aSGarrett D'Amore 1171bdb9230aSGarrett D'Amore if (!dnetp->suspended) { 1172bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, 1173bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG)); 117498e8d175SSteven Stallion if (on) 1175bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1176bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), 1177bdb9230aSGarrett D'Amore val | PROM_MODE); 1178bdb9230aSGarrett D'Amore else 1179bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1180bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), 1181bdb9230aSGarrett D'Amore val & (~PROM_MODE)); 1182bdb9230aSGarrett D'Amore } 1183bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 118498e8d175SSteven Stallion return (0); 1185bdb9230aSGarrett D'Amore } 1186bdb9230aSGarrett D'Amore 1187bdb9230aSGarrett D'Amore static int 118898e8d175SSteven Stallion dnet_m_getstat(void *arg, uint_t stat, uint64_t *val) 1189bdb9230aSGarrett D'Amore { 119098e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 1191bdb9230aSGarrett D'Amore 119298e8d175SSteven Stallion switch (stat) { 119398e8d175SSteven Stallion case MAC_STAT_IFSPEED: 119432607e28SSteven Stallion if (!dnetp->running) { 119532607e28SSteven Stallion *val = 0; 119632607e28SSteven Stallion } else { 119798e8d175SSteven Stallion *val = (dnetp->mii_up ? 119898e8d175SSteven Stallion dnetp->mii_speed : dnetp->speed) * 1000000; 119932607e28SSteven Stallion } 120098e8d175SSteven Stallion break; 120198e8d175SSteven Stallion 120298e8d175SSteven Stallion case MAC_STAT_NORCVBUF: 120398e8d175SSteven Stallion *val = dnetp->stat_norcvbuf; 120498e8d175SSteven Stallion break; 120598e8d175SSteven Stallion 120698e8d175SSteven Stallion case MAC_STAT_IERRORS: 120798e8d175SSteven Stallion *val = dnetp->stat_errrcv; 120898e8d175SSteven Stallion break; 120998e8d175SSteven Stallion 121098e8d175SSteven Stallion case MAC_STAT_OERRORS: 121198e8d175SSteven Stallion *val = dnetp->stat_errxmt; 121298e8d175SSteven Stallion break; 121398e8d175SSteven Stallion 121498e8d175SSteven Stallion case MAC_STAT_COLLISIONS: 121598e8d175SSteven Stallion *val = dnetp->stat_collisions; 121698e8d175SSteven Stallion break; 121798e8d175SSteven Stallion 121898e8d175SSteven Stallion case ETHER_STAT_DEFER_XMTS: 121998e8d175SSteven Stallion *val = dnetp->stat_defer; 122098e8d175SSteven Stallion break; 122198e8d175SSteven Stallion 122298e8d175SSteven Stallion case ETHER_STAT_CARRIER_ERRORS: 122398e8d175SSteven Stallion *val = dnetp->stat_nocarrier; 122498e8d175SSteven Stallion break; 122598e8d175SSteven Stallion 122698e8d175SSteven Stallion case ETHER_STAT_TOOSHORT_ERRORS: 122798e8d175SSteven Stallion *val = dnetp->stat_short; 122898e8d175SSteven Stallion break; 122998e8d175SSteven Stallion 123098e8d175SSteven Stallion case ETHER_STAT_LINK_DUPLEX: 123198e8d175SSteven Stallion if (!dnetp->running) { 123298e8d175SSteven Stallion *val = LINK_DUPLEX_UNKNOWN; 123398e8d175SSteven Stallion 123432607e28SSteven Stallion } else if (dnetp->mii_up) { 123598e8d175SSteven Stallion *val = dnetp->mii_duplex ? 123698e8d175SSteven Stallion LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; 1237bdb9230aSGarrett D'Amore } else { 123898e8d175SSteven Stallion *val = dnetp->full_duplex ? 123998e8d175SSteven Stallion LINK_DUPLEX_FULL : LINK_DUPLEX_HALF; 124098e8d175SSteven Stallion } 124198e8d175SSteven Stallion break; 124298e8d175SSteven Stallion 124398e8d175SSteven Stallion case ETHER_STAT_TX_LATE_COLLISIONS: 124498e8d175SSteven Stallion *val = dnetp->stat_xmtlatecoll; 124598e8d175SSteven Stallion break; 124698e8d175SSteven Stallion 124798e8d175SSteven Stallion case ETHER_STAT_EX_COLLISIONS: 124898e8d175SSteven Stallion *val = dnetp->stat_excoll; 124998e8d175SSteven Stallion break; 125098e8d175SSteven Stallion 125198e8d175SSteven Stallion case MAC_STAT_OVERFLOWS: 125298e8d175SSteven Stallion *val = dnetp->stat_overflow; 125398e8d175SSteven Stallion break; 125498e8d175SSteven Stallion 125598e8d175SSteven Stallion case MAC_STAT_UNDERFLOWS: 125698e8d175SSteven Stallion *val = dnetp->stat_underflow; 125798e8d175SSteven Stallion break; 125898e8d175SSteven Stallion 125998e8d175SSteven Stallion default: 126098e8d175SSteven Stallion return (ENOTSUP); 1261bdb9230aSGarrett D'Amore } 1262bdb9230aSGarrett D'Amore 126398e8d175SSteven Stallion return (0); 1264bdb9230aSGarrett D'Amore } 1265bdb9230aSGarrett D'Amore 1266bdb9230aSGarrett D'Amore #define NextTXIndex(index) (((index)+1) % dnetp->max_tx_desc) 1267bdb9230aSGarrett D'Amore #define PrevTXIndex(index) (((index)-1) < 0 ? dnetp->max_tx_desc - 1: (index)-1) 1268bdb9230aSGarrett D'Amore 126998e8d175SSteven Stallion static mblk_t * 127098e8d175SSteven Stallion dnet_m_tx(void *arg, mblk_t *mp) 1271bdb9230aSGarrett D'Amore { 127298e8d175SSteven Stallion struct dnetinstance *dnetp = arg; 127398e8d175SSteven Stallion 127498e8d175SSteven Stallion mutex_enter(&dnetp->txlock); 127598e8d175SSteven Stallion 127698e8d175SSteven Stallion /* if suspended, drop the packet on the floor, we missed it */ 127798e8d175SSteven Stallion if (dnetp->suspended) { 127898e8d175SSteven Stallion mutex_exit(&dnetp->txlock); 127998e8d175SSteven Stallion freemsg(mp); 128098e8d175SSteven Stallion return (NULL); 128198e8d175SSteven Stallion } 128298e8d175SSteven Stallion 128398e8d175SSteven Stallion if (dnetp->need_saddr) { 128498e8d175SSteven Stallion /* XXX function return value ignored */ 128598e8d175SSteven Stallion mutex_exit(&dnetp->txlock); 128698e8d175SSteven Stallion mutex_enter(&dnetp->intrlock); 128798e8d175SSteven Stallion (void) dnet_set_addr(dnetp); 128898e8d175SSteven Stallion mutex_exit(&dnetp->intrlock); 128998e8d175SSteven Stallion mutex_enter(&dnetp->txlock); 129098e8d175SSteven Stallion } 129198e8d175SSteven Stallion 129298e8d175SSteven Stallion while (mp != NULL) { 129398e8d175SSteven Stallion if (!dnet_send(dnetp, mp)) { 129498e8d175SSteven Stallion mutex_exit(&dnetp->txlock); 129598e8d175SSteven Stallion return (mp); 129698e8d175SSteven Stallion } 129798e8d175SSteven Stallion mp = mp->b_next; 129898e8d175SSteven Stallion } 129998e8d175SSteven Stallion 130098e8d175SSteven Stallion mutex_exit(&dnetp->txlock); 130198e8d175SSteven Stallion 130298e8d175SSteven Stallion /* 130398e8d175SSteven Stallion * Enable xmit interrupt in case we are running out of xmit descriptors 130498e8d175SSteven Stallion * or there are more packets on the queue waiting to be transmitted. 130598e8d175SSteven Stallion */ 130698e8d175SSteven Stallion mutex_enter(&dnetp->intrlock); 130798e8d175SSteven Stallion 130898e8d175SSteven Stallion enable_interrupts(dnetp); 130998e8d175SSteven Stallion 131098e8d175SSteven Stallion /* 131198e8d175SSteven Stallion * Kick the transmitter 131298e8d175SSteven Stallion */ 131398e8d175SSteven Stallion ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_POLL_REG), 131498e8d175SSteven Stallion TX_POLL_DEMAND); 131598e8d175SSteven Stallion 131698e8d175SSteven Stallion mutex_exit(&dnetp->intrlock); 131798e8d175SSteven Stallion 131898e8d175SSteven Stallion return (NULL); 131998e8d175SSteven Stallion } 132098e8d175SSteven Stallion 132198e8d175SSteven Stallion static boolean_t 132298e8d175SSteven Stallion dnet_send(struct dnetinstance *dnetp, mblk_t *mp) 132398e8d175SSteven Stallion { 1324bdb9230aSGarrett D'Amore struct tx_desc_type *ring = dnetp->tx_desc; 1325bdb9230aSGarrett D'Amore int mblen, totlen; 1326bdb9230aSGarrett D'Amore int index, end_index, start_index; 1327bdb9230aSGarrett D'Amore int avail; 1328bdb9230aSGarrett D'Amore int error; 1329bdb9230aSGarrett D'Amore int bufn; 1330bdb9230aSGarrett D'Amore int retval; 1331bdb9230aSGarrett D'Amore mblk_t *bp; 1332bdb9230aSGarrett D'Amore 133398e8d175SSteven Stallion ASSERT(MUTEX_HELD(&dnetp->txlock)); 1334bdb9230aSGarrett D'Amore 1335bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors completed */ 133698e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp); 1337bdb9230aSGarrett D'Amore 1338bdb9230aSGarrett D'Amore /* 1339bdb9230aSGarrett D'Amore * Use the data buffers from the message and construct the 1340bdb9230aSGarrett D'Amore * scatter/gather list by calling ddi_dma_addr_bind_handle(). 1341bdb9230aSGarrett D'Amore */ 134298e8d175SSteven Stallion error = 0; 1343bdb9230aSGarrett D'Amore totlen = 0; 1344bdb9230aSGarrett D'Amore bp = mp; 1345bdb9230aSGarrett D'Amore bufn = 0; 1346bdb9230aSGarrett D'Amore index = start_index = dnetp->tx_current_desc; 1347bdb9230aSGarrett D'Amore avail = dnetp->free_desc; 1348bdb9230aSGarrett D'Amore while (bp != NULL) { 1349bdb9230aSGarrett D'Amore uint_t ncookies; 1350bdb9230aSGarrett D'Amore ddi_dma_cookie_t dma_cookie; 1351bdb9230aSGarrett D'Amore 135298e8d175SSteven Stallion mblen = MBLKL(bp); 1353bdb9230aSGarrett D'Amore 1354bdb9230aSGarrett D'Amore if (!mblen) { /* skip zero-length message blocks */ 1355bdb9230aSGarrett D'Amore bp = bp->b_cont; 1356bdb9230aSGarrett D'Amore continue; 1357bdb9230aSGarrett D'Amore } 1358bdb9230aSGarrett D'Amore 1359bdb9230aSGarrett D'Amore retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL, 1360bdb9230aSGarrett D'Amore (caddr_t)bp->b_rptr, mblen, 1361bdb9230aSGarrett D'Amore DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 1362bdb9230aSGarrett D'Amore &dma_cookie, &ncookies); 1363bdb9230aSGarrett D'Amore 1364bdb9230aSGarrett D'Amore switch (retval) { 1365bdb9230aSGarrett D'Amore case DDI_DMA_MAPPED: 1366bdb9230aSGarrett D'Amore break; /* everything's fine */ 1367bdb9230aSGarrett D'Amore 1368bdb9230aSGarrett D'Amore case DDI_DMA_NORESOURCES: 1369bdb9230aSGarrett D'Amore error = 1; /* allow retry by gld */ 1370bdb9230aSGarrett D'Amore break; 1371bdb9230aSGarrett D'Amore 1372bdb9230aSGarrett D'Amore case DDI_DMA_NOMAPPING: 1373bdb9230aSGarrett D'Amore case DDI_DMA_INUSE: 1374bdb9230aSGarrett D'Amore case DDI_DMA_TOOBIG: 1375bdb9230aSGarrett D'Amore default: 1376bdb9230aSGarrett D'Amore error = 2; /* error, no retry */ 1377bdb9230aSGarrett D'Amore break; 1378bdb9230aSGarrett D'Amore } 1379bdb9230aSGarrett D'Amore 1380bdb9230aSGarrett D'Amore /* 1381bdb9230aSGarrett D'Amore * we can use two cookies per descriptor (i.e buffer1 and 1382bdb9230aSGarrett D'Amore * buffer2) so we need at least (ncookies+1)/2 descriptors. 1383bdb9230aSGarrett D'Amore */ 1384bdb9230aSGarrett D'Amore if (((ncookies + 1) >> 1) > dnetp->free_desc) { 1385bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 1386bdb9230aSGarrett D'Amore error = 1; 1387bdb9230aSGarrett D'Amore break; 1388bdb9230aSGarrett D'Amore } 1389bdb9230aSGarrett D'Amore 1390bdb9230aSGarrett D'Amore /* setup the descriptors for this data buffer */ 1391bdb9230aSGarrett D'Amore while (ncookies) { 1392bdb9230aSGarrett D'Amore end_index = index; 1393bdb9230aSGarrett D'Amore if (bufn % 2) { 1394bdb9230aSGarrett D'Amore ring[index].buffer2 = 1395bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address; 1396bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size2 = 1397bdb9230aSGarrett D'Amore dma_cookie.dmac_size; 1398bdb9230aSGarrett D'Amore index = NextTXIndex(index); /* goto next desc */ 1399bdb9230aSGarrett D'Amore } else { 1400bdb9230aSGarrett D'Amore /* initialize the descriptor */ 1401bdb9230aSGarrett D'Amore ASSERT(ring[index].desc0.own == 0); 1402bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0; 1403bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &= 1404bdb9230aSGarrett D'Amore DNET_END_OF_RING; 1405bdb9230aSGarrett D'Amore ring[index].buffer1 = 1406bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address; 1407bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size1 = 1408bdb9230aSGarrett D'Amore dma_cookie.dmac_size; 1409bdb9230aSGarrett D'Amore ring[index].buffer2 = (uint32_t)(0); 1410bdb9230aSGarrett D'Amore dnetp->free_desc--; 1411bdb9230aSGarrett D'Amore ASSERT(dnetp->free_desc >= 0); 1412bdb9230aSGarrett D'Amore } 1413bdb9230aSGarrett D'Amore totlen += dma_cookie.dmac_size; 1414bdb9230aSGarrett D'Amore bufn++; 1415bdb9230aSGarrett D'Amore if (--ncookies) 1416bdb9230aSGarrett D'Amore ddi_dma_nextcookie(dnetp->dma_handle_tx, 1417bdb9230aSGarrett D'Amore &dma_cookie); 1418bdb9230aSGarrett D'Amore } 1419bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 1420bdb9230aSGarrett D'Amore bp = bp->b_cont; 1421bdb9230aSGarrett D'Amore } 1422bdb9230aSGarrett D'Amore 1423bdb9230aSGarrett D'Amore if (error == 1) { 1424bdb9230aSGarrett D'Amore dnetp->stat_defer++; 1425bdb9230aSGarrett D'Amore dnetp->free_desc = avail; 142698e8d175SSteven Stallion dnetp->need_tx_update = B_TRUE; 142798e8d175SSteven Stallion return (B_FALSE); 1428bdb9230aSGarrett D'Amore } else if (error) { 1429bdb9230aSGarrett D'Amore dnetp->free_desc = avail; 1430bdb9230aSGarrett D'Amore freemsg(mp); 143198e8d175SSteven Stallion return (B_TRUE); /* Drop packet, don't retry */ 1432bdb9230aSGarrett D'Amore } 1433bdb9230aSGarrett D'Amore 143498e8d175SSteven Stallion if (totlen > ETHERMAX + VLAN_TAGSZ) { 1435bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen); 1436bdb9230aSGarrett D'Amore dnetp->free_desc = avail; 1437bdb9230aSGarrett D'Amore freemsg(mp); 143898e8d175SSteven Stallion return (B_TRUE); /* Don't repeat this attempt */ 1439bdb9230aSGarrett D'Amore } 1440bdb9230aSGarrett D'Amore 1441bdb9230aSGarrett D'Amore /* 1442bdb9230aSGarrett D'Amore * Remeber the message buffer pointer to do freemsg() at xmit 1443bdb9230aSGarrett D'Amore * interrupt time. 1444bdb9230aSGarrett D'Amore */ 1445bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[end_index] = mp; 1446bdb9230aSGarrett D'Amore 1447bdb9230aSGarrett D'Amore /* 1448bdb9230aSGarrett D'Amore * Now set the first/last buffer and own bits 1449bdb9230aSGarrett D'Amore * Since the 21040 looks for these bits set in the 1450bdb9230aSGarrett D'Amore * first buffer, work backwards in multiple buffers. 1451bdb9230aSGarrett D'Amore */ 1452bdb9230aSGarrett D'Amore ring[end_index].desc1.last_desc = 1; 1453bdb9230aSGarrett D'Amore ring[end_index].desc1.int_on_comp = 1; 1454bdb9230aSGarrett D'Amore for (index = end_index; index != start_index; 1455bdb9230aSGarrett D'Amore index = PrevTXIndex(index)) 1456bdb9230aSGarrett D'Amore ring[index].desc0.own = 1; 1457bdb9230aSGarrett D'Amore ring[start_index].desc1.first_desc = 1; 1458bdb9230aSGarrett D'Amore ring[start_index].desc0.own = 1; 1459bdb9230aSGarrett D'Amore 1460bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(end_index); 1461bdb9230aSGarrett D'Amore 1462bdb9230aSGarrett D'Amore /* 1463bdb9230aSGarrett D'Amore * Safety check: make sure end-of-ring is set in last desc. 1464bdb9230aSGarrett D'Amore */ 1465bdb9230aSGarrett D'Amore ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0); 1466bdb9230aSGarrett D'Amore 146798e8d175SSteven Stallion return (B_TRUE); 1468bdb9230aSGarrett D'Amore } 1469bdb9230aSGarrett D'Amore 1470bdb9230aSGarrett D'Amore /* 147198e8d175SSteven Stallion * dnet_intr() -- interrupt from board to inform us that a receive or 1472bdb9230aSGarrett D'Amore * transmit has completed. 1473bdb9230aSGarrett D'Amore */ 1474bdb9230aSGarrett D'Amore static uint_t 147598e8d175SSteven Stallion dnet_intr(caddr_t arg) 1476bdb9230aSGarrett D'Amore { 147798e8d175SSteven Stallion struct dnetinstance *dnetp = (struct dnetinstance *)arg; 1478bdb9230aSGarrett D'Amore uint32_t int_status; 1479bdb9230aSGarrett D'Amore 1480bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 148198e8d175SSteven Stallion 1482bdb9230aSGarrett D'Amore if (dnetp->suspended) { 1483bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1484bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED); 1485bdb9230aSGarrett D'Amore } 1486bdb9230aSGarrett D'Amore 1487bdb9230aSGarrett D'Amore int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, 1488bdb9230aSGarrett D'Amore STATUS_REG)); 1489bdb9230aSGarrett D'Amore 1490bdb9230aSGarrett D'Amore /* 1491bdb9230aSGarrett D'Amore * If interrupt was not from this board 1492bdb9230aSGarrett D'Amore */ 1493bdb9230aSGarrett D'Amore if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) { 1494bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1495bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED); 1496bdb9230aSGarrett D'Amore } 1497bdb9230aSGarrett D'Amore 1498bdb9230aSGarrett D'Amore dnetp->stat_intr++; 1499bdb9230aSGarrett D'Amore 1500bdb9230aSGarrett D'Amore if (int_status & GPTIMER_INTR) { 1501bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1502bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR); 1503bdb9230aSGarrett D'Amore if (dnetp->timer.cb) 1504bdb9230aSGarrett D'Amore dnetp->timer.cb(dnetp); 1505bdb9230aSGarrett D'Amore else 1506bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: unhandled timer interrupt"); 1507bdb9230aSGarrett D'Amore } 1508bdb9230aSGarrett D'Amore 1509bdb9230aSGarrett D'Amore if (int_status & TX_INTR) { 1510bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1511bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), TX_INTR); 1512bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 151398e8d175SSteven Stallion if (dnetp->need_tx_update) { 1514bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 1515bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 151698e8d175SSteven Stallion mac_tx_update(dnetp->mac_handle); 1517bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 1518bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 151998e8d175SSteven Stallion dnetp->need_tx_update = B_FALSE; 1520bdb9230aSGarrett D'Amore } 1521bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors that are completed */ 152298e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp); 1523bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 1524bdb9230aSGarrett D'Amore } 1525bdb9230aSGarrett D'Amore 1526bdb9230aSGarrett D'Amore /* 1527bdb9230aSGarrett D'Amore * Check if receive interrupt bit is set 1528bdb9230aSGarrett D'Amore */ 1529bdb9230aSGarrett D'Amore if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) { 1530bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1531bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), 1532bdb9230aSGarrett D'Amore int_status & (RX_INTR | RX_UNAVAIL_INTR)); 153398e8d175SSteven Stallion dnet_getp(dnetp); 1534bdb9230aSGarrett D'Amore } 1535bdb9230aSGarrett D'Amore 1536bdb9230aSGarrett D'Amore if (int_status & ABNORMAL_INTR_SUMM) { 1537bdb9230aSGarrett D'Amore /* 1538bdb9230aSGarrett D'Amore * Check for system error 1539bdb9230aSGarrett D'Amore */ 1540bdb9230aSGarrett D'Amore if (int_status & SYS_ERR) { 1541bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == MASTER_ABORT) 1542bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Master Abort"); 1543bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == TARGET_ABORT) 1544bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Target Abort"); 1545bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == PARITY_ERROR) 1546bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Parity error"); 1547bdb9230aSGarrett D'Amore } 1548bdb9230aSGarrett D'Amore 1549bdb9230aSGarrett D'Amore /* 1550bdb9230aSGarrett D'Amore * If the jabber has timed out then reset the chip 1551bdb9230aSGarrett D'Amore */ 1552bdb9230aSGarrett D'Amore if (int_status & TX_JABBER_TIMEOUT) 1553bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Jabber timeout."); 1554bdb9230aSGarrett D'Amore 1555bdb9230aSGarrett D'Amore /* 1556bdb9230aSGarrett D'Amore * If an underflow has occurred, reset the chip 1557bdb9230aSGarrett D'Amore */ 1558bdb9230aSGarrett D'Amore if (int_status & TX_UNDERFLOW) 1559bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Tx Underflow."); 1560bdb9230aSGarrett D'Amore 1561bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 1562bdb9230aSGarrett D'Amore if (dnetdebug & DNETINT) 1563bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Trying to reset..."); 1564bdb9230aSGarrett D'Amore #endif 156598e8d175SSteven Stallion dnet_reset_board(dnetp); 156698e8d175SSteven Stallion dnet_init_board(dnetp); 1567bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 156898e8d175SSteven Stallion (void) dnet_start(dnetp); 1569bdb9230aSGarrett D'Amore } 1570bdb9230aSGarrett D'Amore 1571bdb9230aSGarrett D'Amore /* 157298e8d175SSteven Stallion * Enable the interrupts. Enable xmit interrupt in case we are 1573bdb9230aSGarrett D'Amore * running out of free descriptors or if there are packets 1574bdb9230aSGarrett D'Amore * in the queue waiting to be transmitted. 1575bdb9230aSGarrett D'Amore */ 157698e8d175SSteven Stallion enable_interrupts(dnetp); 1577bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 1578bdb9230aSGarrett D'Amore return (DDI_INTR_CLAIMED); /* Indicate it was our interrupt */ 1579bdb9230aSGarrett D'Amore } 1580bdb9230aSGarrett D'Amore 1581bdb9230aSGarrett D'Amore static void 158298e8d175SSteven Stallion dnet_getp(struct dnetinstance *dnetp) 1583bdb9230aSGarrett D'Amore { 1584bdb9230aSGarrett D'Amore int packet_length, index; 1585bdb9230aSGarrett D'Amore mblk_t *mp; 1586bdb9230aSGarrett D'Amore caddr_t virtual_address; 1587bdb9230aSGarrett D'Amore struct rx_desc_type *desc = dnetp->rx_desc; 1588bdb9230aSGarrett D'Amore int marker = dnetp->rx_current_desc; 1589bdb9230aSGarrett D'Amore int misses; 1590bdb9230aSGarrett D'Amore 1591bdb9230aSGarrett D'Amore if (!dnetp->overrun_workaround) { 1592bdb9230aSGarrett D'Amore /* 1593bdb9230aSGarrett D'Amore * If the workaround is not in place, we must still update 1594bdb9230aSGarrett D'Amore * the missed frame statistic from the on-chip counter. 1595bdb9230aSGarrett D'Amore */ 1596bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle, 1597bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG)); 1598bdb9230aSGarrett D'Amore dnetp->stat_missed += (misses & MISSED_FRAME_MASK); 1599bdb9230aSGarrett D'Amore } 1600bdb9230aSGarrett D'Amore 1601bdb9230aSGarrett D'Amore /* While host owns the current descriptor */ 1602bdb9230aSGarrett D'Amore while (!(desc[dnetp->rx_current_desc].desc0.own)) { 1603bdb9230aSGarrett D'Amore struct free_ptr *frp; 1604bdb9230aSGarrett D'Amore caddr_t newbuf; 1605bdb9230aSGarrett D'Amore struct rbuf_list *rp; 1606bdb9230aSGarrett D'Amore 1607bdb9230aSGarrett D'Amore index = dnetp->rx_current_desc; 1608bdb9230aSGarrett D'Amore ASSERT(desc[index].desc0.first_desc != 0); 1609bdb9230aSGarrett D'Amore 1610bdb9230aSGarrett D'Amore /* 1611bdb9230aSGarrett D'Amore * DMA overrun errata from DEC: avoid possible bus hangs 1612bdb9230aSGarrett D'Amore * and data corruption 1613bdb9230aSGarrett D'Amore */ 1614bdb9230aSGarrett D'Amore if (dnetp->overrun_workaround && 1615bdb9230aSGarrett D'Amore marker == dnetp->rx_current_desc) { 1616bdb9230aSGarrett D'Amore int opn; 1617bdb9230aSGarrett D'Amore do { 1618bdb9230aSGarrett D'Amore marker = (marker+1) % dnetp->max_rx_desc; 1619bdb9230aSGarrett D'Amore } while (!(dnetp->rx_desc[marker].desc0.own) && 1620bdb9230aSGarrett D'Amore marker != index); 1621bdb9230aSGarrett D'Amore 1622bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle, 1623bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG)); 1624bdb9230aSGarrett D'Amore dnetp->stat_missed += 1625bdb9230aSGarrett D'Amore (misses & MISSED_FRAME_MASK); 1626bdb9230aSGarrett D'Amore if (misses & OVERFLOW_COUNTER_MASK) { 1627bdb9230aSGarrett D'Amore /* 1628bdb9230aSGarrett D'Amore * Overflow(s) have occurred : stop receiver, 1629bdb9230aSGarrett D'Amore * and wait until in stopped state 1630bdb9230aSGarrett D'Amore */ 1631bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle, 1632bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG)); 1633bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1634bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), 1635bdb9230aSGarrett D'Amore opn & ~(START_RECEIVE)); 1636bdb9230aSGarrett D'Amore 1637bdb9230aSGarrett D'Amore do { 1638bdb9230aSGarrett D'Amore drv_usecwait(10); 1639bdb9230aSGarrett D'Amore } while ((ddi_get32(dnetp->io_handle, 1640bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG)) & 1641bdb9230aSGarrett D'Amore RECEIVE_PROCESS_STATE) != 0); 1642bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 1643bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV) 1644bdb9230aSGarrett D'Amore cmn_err(CE_CONT, "^*"); 1645bdb9230aSGarrett D'Amore #endif 1646bdb9230aSGarrett D'Amore /* Discard probably corrupt frames */ 1647bdb9230aSGarrett D'Amore while (!(dnetp->rx_desc[index].desc0.own)) { 1648bdb9230aSGarrett D'Amore dnetp->rx_desc[index].desc0.own = 1; 1649bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_rx_desc; 1650bdb9230aSGarrett D'Amore dnetp->stat_missed++; 1651bdb9230aSGarrett D'Amore } 1652bdb9230aSGarrett D'Amore 1653bdb9230aSGarrett D'Amore /* restart the receiver */ 1654bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle, 1655bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG)); 1656bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1657bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), 1658bdb9230aSGarrett D'Amore opn | START_RECEIVE); 1659bdb9230aSGarrett D'Amore marker = dnetp->rx_current_desc = index; 1660bdb9230aSGarrett D'Amore continue; 1661bdb9230aSGarrett D'Amore } 1662bdb9230aSGarrett D'Amore /* 1663bdb9230aSGarrett D'Amore * At this point, we know that all packets before 1664bdb9230aSGarrett D'Amore * "marker" were received before a dma overrun occurred 1665bdb9230aSGarrett D'Amore */ 1666bdb9230aSGarrett D'Amore } 1667bdb9230aSGarrett D'Amore 1668bdb9230aSGarrett D'Amore /* 1669bdb9230aSGarrett D'Amore * If we get an oversized packet it could span multiple 1670bdb9230aSGarrett D'Amore * descriptors. If this happens an error bit should be set. 1671bdb9230aSGarrett D'Amore */ 1672bdb9230aSGarrett D'Amore while (desc[index].desc0.last_desc == 0) { 1673bdb9230aSGarrett D'Amore index = (index + 1) % dnetp->max_rx_desc; 1674bdb9230aSGarrett D'Amore if (desc[index].desc0.own) 1675bdb9230aSGarrett D'Amore return; /* not done receiving large packet */ 1676bdb9230aSGarrett D'Amore } 1677bdb9230aSGarrett D'Amore while (dnetp->rx_current_desc != index) { 1678bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1; 1679bdb9230aSGarrett D'Amore dnetp->rx_current_desc = 1680bdb9230aSGarrett D'Amore (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc; 1681bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 1682bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV) 1683bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: received large packet"); 1684bdb9230aSGarrett D'Amore #endif 1685bdb9230aSGarrett D'Amore } 1686bdb9230aSGarrett D'Amore 1687bdb9230aSGarrett D'Amore packet_length = desc[index].desc0.frame_len; 1688bdb9230aSGarrett D'Amore 1689bdb9230aSGarrett D'Amore /* 1690bdb9230aSGarrett D'Amore * Remove CRC from received data. This is an artefact of the 1691bdb9230aSGarrett D'Amore * 21x4x chip and should not be passed higher up the network 1692bdb9230aSGarrett D'Amore * stack. 1693bdb9230aSGarrett D'Amore */ 1694bdb9230aSGarrett D'Amore packet_length -= ETHERFCSL; 1695bdb9230aSGarrett D'Amore 1696bdb9230aSGarrett D'Amore /* get the virtual address of the packet received */ 1697bdb9230aSGarrett D'Amore virtual_address = 1698bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index]; 1699bdb9230aSGarrett D'Amore 1700bdb9230aSGarrett D'Amore /* 1701bdb9230aSGarrett D'Amore * If no packet errors then do: 1702bdb9230aSGarrett D'Amore * 1. Allocate a new receive buffer so that we can 1703bdb9230aSGarrett D'Amore * use the current buffer as streams buffer to 1704bdb9230aSGarrett D'Amore * avoid bcopy. 1705bdb9230aSGarrett D'Amore * 2. If we got a new receive buffer then allocate 1706bdb9230aSGarrett D'Amore * an mblk using desballoc(). 1707bdb9230aSGarrett D'Amore * 3. Otherwise use the mblk from allocb() and do 1708bdb9230aSGarrett D'Amore * the bcopy. 1709bdb9230aSGarrett D'Amore */ 1710bdb9230aSGarrett D'Amore frp = NULL; 1711bdb9230aSGarrett D'Amore rp = NULL; 1712bdb9230aSGarrett D'Amore newbuf = NULL; 1713bdb9230aSGarrett D'Amore mp = NULL; 171498e8d175SSteven Stallion if (!desc[index].desc0.err_summary || 171598e8d175SSteven Stallion (desc[index].desc0.frame2long && 171698e8d175SSteven Stallion packet_length < rx_buf_size)) { 1717bdb9230aSGarrett D'Amore ASSERT(packet_length < rx_buf_size); 1718bdb9230aSGarrett D'Amore /* 1719bdb9230aSGarrett D'Amore * Allocate another receive buffer for this descriptor. 1720bdb9230aSGarrett D'Amore * If we fail to allocate then we do the normal bcopy. 1721bdb9230aSGarrett D'Amore */ 1722bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 0); 1723bdb9230aSGarrett D'Amore if (rp != NULL) { 1724bdb9230aSGarrett D'Amore newbuf = rp->rbuf_vaddr; 1725bdb9230aSGarrett D'Amore frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP); 1726bdb9230aSGarrett D'Amore if (frp != NULL) { 1727bdb9230aSGarrett D'Amore frp->free_rtn.free_func = 1728bdb9230aSGarrett D'Amore dnet_freemsg_buf; 1729bdb9230aSGarrett D'Amore frp->free_rtn.free_arg = (char *)frp; 1730bdb9230aSGarrett D'Amore frp->buf = virtual_address; 1731bdb9230aSGarrett D'Amore mp = desballoc( 1732bdb9230aSGarrett D'Amore (uchar_t *)virtual_address, 1733bdb9230aSGarrett D'Amore packet_length, 0, &frp->free_rtn); 1734bdb9230aSGarrett D'Amore if (mp == NULL) { 1735bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp)); 1736bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf); 1737bdb9230aSGarrett D'Amore frp = NULL; 1738bdb9230aSGarrett D'Amore newbuf = NULL; 1739bdb9230aSGarrett D'Amore } 1740bdb9230aSGarrett D'Amore } 1741bdb9230aSGarrett D'Amore } 1742bdb9230aSGarrett D'Amore if (mp == NULL) { 1743bdb9230aSGarrett D'Amore if (newbuf != NULL) 1744bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf); 1745bdb9230aSGarrett D'Amore mp = allocb(packet_length, 0); 1746bdb9230aSGarrett D'Amore } 1747bdb9230aSGarrett D'Amore } 1748bdb9230aSGarrett D'Amore 174998e8d175SSteven Stallion if ((desc[index].desc0.err_summary && 175098e8d175SSteven Stallion packet_length >= rx_buf_size) || mp == NULL) { 1751bdb9230aSGarrett D'Amore 1752bdb9230aSGarrett D'Amore /* Update gld statistics */ 1753bdb9230aSGarrett D'Amore if (desc[index].desc0.err_summary) 175498e8d175SSteven Stallion update_rx_stats(dnetp, index); 1755bdb9230aSGarrett D'Amore else 1756bdb9230aSGarrett D'Amore dnetp->stat_norcvbuf++; 1757bdb9230aSGarrett D'Amore 1758bdb9230aSGarrett D'Amore /* 1759bdb9230aSGarrett D'Amore * Reset ownership of the descriptor. 1760bdb9230aSGarrett D'Amore */ 1761bdb9230aSGarrett D'Amore desc[index].desc0.own = 1; 1762bdb9230aSGarrett D'Amore dnetp->rx_current_desc = 1763bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc; 1764bdb9230aSGarrett D'Amore 1765bdb9230aSGarrett D'Amore /* Demand receive polling by the chip */ 1766bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1767bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND); 1768bdb9230aSGarrett D'Amore 1769bdb9230aSGarrett D'Amore continue; 1770bdb9230aSGarrett D'Amore } 1771bdb9230aSGarrett D'Amore 1772bdb9230aSGarrett D'Amore if (newbuf != NULL) { 1773bdb9230aSGarrett D'Amore uint32_t end_paddr; 1774bdb9230aSGarrett D'Amore /* attach the new buffer to the rx descriptor */ 1775bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index] = newbuf; 1776bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[index] = rp->rbuf_paddr; 1777bdb9230aSGarrett D'Amore desc[index].buffer1 = rp->rbuf_paddr; 1778bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 = rx_buf_size; 1779bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 = 0; 1780bdb9230aSGarrett D'Amore end_paddr = rp->rbuf_endpaddr; 1781bdb9230aSGarrett D'Amore if ((desc[index].buffer1 & ~dnetp->pgmask) != 1782bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) { 1783bdb9230aSGarrett D'Amore /* discontiguous */ 1784bdb9230aSGarrett D'Amore desc[index].buffer2 = end_paddr&~dnetp->pgmask; 1785bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 = 1786bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1; 1787bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 = 1788bdb9230aSGarrett D'Amore rx_buf_size-desc[index].desc1.buffer_size2; 1789bdb9230aSGarrett D'Amore } 1790bdb9230aSGarrett D'Amore } else { 1791bdb9230aSGarrett D'Amore /* couldn't allocate another buffer; copy the data */ 1792bdb9230aSGarrett D'Amore BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr, 1793bdb9230aSGarrett D'Amore packet_length); 1794bdb9230aSGarrett D'Amore } 1795bdb9230aSGarrett D'Amore 1796bdb9230aSGarrett D'Amore mp->b_wptr += packet_length; 1797bdb9230aSGarrett D'Amore 1798bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1; 1799bdb9230aSGarrett D'Amore 1800bdb9230aSGarrett D'Amore /* 1801bdb9230aSGarrett D'Amore * Increment receive desc index. This is for the scan of 1802bdb9230aSGarrett D'Amore * next packet 1803bdb9230aSGarrett D'Amore */ 1804bdb9230aSGarrett D'Amore dnetp->rx_current_desc = 1805bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc; 1806bdb9230aSGarrett D'Amore 1807bdb9230aSGarrett D'Amore /* Demand polling by chip */ 1808bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1809bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND); 1810bdb9230aSGarrett D'Amore 1811bdb9230aSGarrett D'Amore /* send the packet upstream */ 1812bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 181398e8d175SSteven Stallion mac_rx(dnetp->mac_handle, NULL, mp); 1814bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 1815bdb9230aSGarrett D'Amore } 1816bdb9230aSGarrett D'Amore } 1817bdb9230aSGarrett D'Amore /* 1818bdb9230aSGarrett D'Amore * Function to update receive statistics 1819bdb9230aSGarrett D'Amore */ 1820bdb9230aSGarrett D'Amore static void 182198e8d175SSteven Stallion update_rx_stats(struct dnetinstance *dnetp, int index) 1822bdb9230aSGarrett D'Amore { 1823bdb9230aSGarrett D'Amore struct rx_desc_type *descp = &(dnetp->rx_desc[index]); 1824bdb9230aSGarrett D'Amore 1825bdb9230aSGarrett D'Amore /* 1826bdb9230aSGarrett D'Amore * Update gld statistics 1827bdb9230aSGarrett D'Amore */ 1828bdb9230aSGarrett D'Amore dnetp->stat_errrcv++; 1829bdb9230aSGarrett D'Amore 1830bdb9230aSGarrett D'Amore if (descp->desc0.overflow) { 1831bdb9230aSGarrett D'Amore /* FIFO Overrun */ 1832bdb9230aSGarrett D'Amore dnetp->stat_overflow++; 1833bdb9230aSGarrett D'Amore } 1834bdb9230aSGarrett D'Amore 1835bdb9230aSGarrett D'Amore if (descp->desc0.collision) { 1836bdb9230aSGarrett D'Amore /*EMPTY*/ 1837bdb9230aSGarrett D'Amore /* Late Colllision on receive */ 1838bdb9230aSGarrett D'Amore /* no appropriate counter */ 1839bdb9230aSGarrett D'Amore } 1840bdb9230aSGarrett D'Amore 1841bdb9230aSGarrett D'Amore if (descp->desc0.crc) { 1842bdb9230aSGarrett D'Amore /* CRC Error */ 1843bdb9230aSGarrett D'Amore dnetp->stat_crc++; 1844bdb9230aSGarrett D'Amore } 1845bdb9230aSGarrett D'Amore 1846bdb9230aSGarrett D'Amore if (descp->desc0.runt_frame) { 1847bdb9230aSGarrett D'Amore /* Runt Error */ 1848bdb9230aSGarrett D'Amore dnetp->stat_short++; 1849bdb9230aSGarrett D'Amore } 1850bdb9230aSGarrett D'Amore 1851bdb9230aSGarrett D'Amore if (descp->desc0.desc_err) { 1852bdb9230aSGarrett D'Amore /*EMPTY*/ 1853bdb9230aSGarrett D'Amore /* Not enough receive descriptors */ 185498e8d175SSteven Stallion /* This condition is accounted in dnet_intr() */ 1855bdb9230aSGarrett D'Amore } 1856bdb9230aSGarrett D'Amore 1857bdb9230aSGarrett D'Amore if (descp->desc0.frame2long) { 1858bdb9230aSGarrett D'Amore dnetp->stat_frame++; 1859bdb9230aSGarrett D'Amore } 1860bdb9230aSGarrett D'Amore } 1861bdb9230aSGarrett D'Amore 1862bdb9230aSGarrett D'Amore /* 1863bdb9230aSGarrett D'Amore * Function to update transmit statistics 1864bdb9230aSGarrett D'Amore */ 1865bdb9230aSGarrett D'Amore static void 186698e8d175SSteven Stallion update_tx_stats(struct dnetinstance *dnetp, int index) 1867bdb9230aSGarrett D'Amore { 1868bdb9230aSGarrett D'Amore struct tx_desc_type *descp = &(dnetp->tx_desc[index]); 1869bdb9230aSGarrett D'Amore int fd; 1870bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block; 1871bdb9230aSGarrett D'Amore 1872bdb9230aSGarrett D'Amore 1873bdb9230aSGarrett D'Amore /* Update gld statistics */ 1874bdb9230aSGarrett D'Amore dnetp->stat_errxmt++; 1875bdb9230aSGarrett D'Amore 1876bdb9230aSGarrett D'Amore /* If we're in full-duplex don't count collisions or carrier loss. */ 1877bdb9230aSGarrett D'Amore if (dnetp->mii_up) { 1878bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex; 1879bdb9230aSGarrett D'Amore } else { 1880bdb9230aSGarrett D'Amore /* Rely on media code */ 1881bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD || 1882bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD; 1883bdb9230aSGarrett D'Amore } 1884bdb9230aSGarrett D'Amore 1885bdb9230aSGarrett D'Amore if (descp->desc0.collision_count && !fd) { 1886bdb9230aSGarrett D'Amore dnetp->stat_collisions += descp->desc0.collision_count; 1887bdb9230aSGarrett D'Amore } 1888bdb9230aSGarrett D'Amore 1889bdb9230aSGarrett D'Amore if (descp->desc0.late_collision && !fd) { 1890bdb9230aSGarrett D'Amore dnetp->stat_xmtlatecoll++; 1891bdb9230aSGarrett D'Amore } 1892bdb9230aSGarrett D'Amore 1893bdb9230aSGarrett D'Amore if (descp->desc0.excess_collision && !fd) { 1894bdb9230aSGarrett D'Amore dnetp->stat_excoll++; 1895bdb9230aSGarrett D'Amore } 1896bdb9230aSGarrett D'Amore 1897bdb9230aSGarrett D'Amore if (descp->desc0.underflow) { 1898bdb9230aSGarrett D'Amore dnetp->stat_underflow++; 1899bdb9230aSGarrett D'Amore } 1900bdb9230aSGarrett D'Amore 1901bdb9230aSGarrett D'Amore #if 0 1902bdb9230aSGarrett D'Amore if (descp->desc0.tx_jabber_to) { 1903bdb9230aSGarrett D'Amore /* no appropriate counter */ 1904bdb9230aSGarrett D'Amore } 1905bdb9230aSGarrett D'Amore #endif 1906bdb9230aSGarrett D'Amore 1907bdb9230aSGarrett D'Amore if (descp->desc0.carrier_loss && !fd) { 1908bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++; 1909bdb9230aSGarrett D'Amore } 1910bdb9230aSGarrett D'Amore 1911bdb9230aSGarrett D'Amore if (descp->desc0.no_carrier && !fd) { 1912bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++; 1913bdb9230aSGarrett D'Amore } 1914bdb9230aSGarrett D'Amore } 1915bdb9230aSGarrett D'Amore 1916bdb9230aSGarrett D'Amore /* 1917bdb9230aSGarrett D'Amore * ========== Media Selection Setup Routines ========== 1918bdb9230aSGarrett D'Amore */ 1919bdb9230aSGarrett D'Amore 1920bdb9230aSGarrett D'Amore 1921bdb9230aSGarrett D'Amore static void 1922bdb9230aSGarrett D'Amore write_gpr(struct dnetinstance *dnetp, uint32_t val) 1923bdb9230aSGarrett D'Amore { 1924bdb9230aSGarrett D'Amore #ifdef DEBUG 1925bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG) 1926bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "GPR: %x", val); 1927bdb9230aSGarrett D'Amore #endif 1928bdb9230aSGarrett D'Amore switch (dnetp->board_type) { 1929bdb9230aSGarrett D'Amore case DEVICE_ID_21143: 1930bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */ 1931bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE) 1932bdb9230aSGarrett D'Amore val |= CWE_21143, val &= ~GPR_CONTROL_WRITE; 1933bdb9230aSGarrett D'Amore /* Write to upper half of CSR15 */ 1934bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16); 1935bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 1936bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia); 1937bdb9230aSGarrett D'Amore break; 1938bdb9230aSGarrett D'Amore default: 1939bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */ 1940bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE) 1941bdb9230aSGarrett D'Amore val |= CWE_21140, val &= ~GPR_CONTROL_WRITE; 1942bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val); 1943bdb9230aSGarrett D'Amore break; 1944bdb9230aSGarrett D'Amore } 1945bdb9230aSGarrett D'Amore } 1946bdb9230aSGarrett D'Amore 1947bdb9230aSGarrett D'Amore static uint32_t 1948bdb9230aSGarrett D'Amore read_gpr(struct dnetinstance *dnetp) 1949bdb9230aSGarrett D'Amore { 1950bdb9230aSGarrett D'Amore switch (dnetp->board_type) { 1951bdb9230aSGarrett D'Amore case DEVICE_ID_21143: 1952bdb9230aSGarrett D'Amore /* Read upper half of CSR15 */ 1953bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle, 1954bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16); 1955bdb9230aSGarrett D'Amore default: 1956bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle, 1957bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, GP_REG))); 1958bdb9230aSGarrett D'Amore } 1959bdb9230aSGarrett D'Amore } 1960bdb9230aSGarrett D'Amore 1961bdb9230aSGarrett D'Amore static void 196298e8d175SSteven Stallion set_gpr(struct dnetinstance *dnetp) 1963bdb9230aSGarrett D'Amore { 1964bdb9230aSGarrett D'Amore uint32_t *sequence; 1965bdb9230aSGarrett D'Amore int len; 1966bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf]; 1967bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block; 1968bdb9230aSGarrett D'Amore int i; 1969bdb9230aSGarrett D'Amore 1970bdb9230aSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo, 1971bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence, 1972bdb9230aSGarrett D'Amore &len) == DDI_PROP_SUCCESS) { 1973bdb9230aSGarrett D'Amore for (i = 0; i < len / sizeof (uint32_t); i++) 1974bdb9230aSGarrett D'Amore write_gpr(dnetp, sequence[i]); 1975bdb9230aSGarrett D'Amore kmem_free(sequence, len); 1976bdb9230aSGarrett D'Amore } else { 1977bdb9230aSGarrett D'Amore /* 1978bdb9230aSGarrett D'Amore * Write the reset sequence if this is the first time this 1979bdb9230aSGarrett D'Amore * block has been selected. 1980bdb9230aSGarrett D'Amore */ 1981bdb9230aSGarrett D'Amore if (block->rstseqlen) { 1982bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) 1983bdb9230aSGarrett D'Amore write_gpr(dnetp, block->rstseq[i]); 1984bdb9230aSGarrett D'Amore /* 1985bdb9230aSGarrett D'Amore * XXX Legacy blocks do not have reset sequences, so the 1986bdb9230aSGarrett D'Amore * static blocks will never be modified by this 1987bdb9230aSGarrett D'Amore */ 1988bdb9230aSGarrett D'Amore block->rstseqlen = 0; 1989bdb9230aSGarrett D'Amore } 1990bdb9230aSGarrett D'Amore if (leaf->gpr) 1991bdb9230aSGarrett D'Amore write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE); 1992bdb9230aSGarrett D'Amore 1993bdb9230aSGarrett D'Amore /* write GPR sequence each time */ 1994bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++) 1995bdb9230aSGarrett D'Amore write_gpr(dnetp, block->gprseq[i]); 1996bdb9230aSGarrett D'Amore } 1997bdb9230aSGarrett D'Amore 1998bdb9230aSGarrett D'Amore /* This has possibly caused a PHY to reset. Let MII know */ 1999bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1) 2000bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 2001bdb9230aSGarrett D'Amore (void) mii_sync(dnetp->mii, dnetp->phyaddr); 2002bdb9230aSGarrett D'Amore drv_usecwait(5); 2003bdb9230aSGarrett D'Amore } 2004bdb9230aSGarrett D'Amore 2005bdb9230aSGarrett D'Amore /* set_opr() - must be called with intrlock held */ 2006bdb9230aSGarrett D'Amore 2007bdb9230aSGarrett D'Amore static void 200898e8d175SSteven Stallion set_opr(struct dnetinstance *dnetp) 2009bdb9230aSGarrett D'Amore { 2010bdb9230aSGarrett D'Amore uint32_t fd, mb1, sf; 2011bdb9230aSGarrett D'Amore 2012bdb9230aSGarrett D'Amore int opnmode_len; 2013bdb9230aSGarrett D'Amore uint32_t val; 2014bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block; 2015bdb9230aSGarrett D'Amore 2016bdb9230aSGarrett D'Amore ASSERT(block); 2017bdb9230aSGarrett D'Amore 2018bdb9230aSGarrett D'Amore /* Check for custom "opnmode_reg" property */ 2019bdb9230aSGarrett D'Amore opnmode_len = sizeof (val); 2020bdb9230aSGarrett D'Amore if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo, 2021bdb9230aSGarrett D'Amore PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg", 2022bdb9230aSGarrett D'Amore (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS) 2023bdb9230aSGarrett D'Amore opnmode_len = 0; 2024bdb9230aSGarrett D'Amore 2025bdb9230aSGarrett D'Amore /* Some bits exist only on 21140 and greater */ 2026bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040 && 2027bdb9230aSGarrett D'Amore dnetp->board_type != DEVICE_ID_21041) { 2028bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1; 2029bdb9230aSGarrett D'Amore sf = STORE_AND_FORWARD; 2030bdb9230aSGarrett D'Amore } else { 2031bdb9230aSGarrett D'Amore mb1 = sf = 0; 2032bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1; /* Needed for 21040? */ 2033bdb9230aSGarrett D'Amore } 2034bdb9230aSGarrett D'Amore 2035bdb9230aSGarrett D'Amore if (opnmode_len) { 2036bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2037bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val); 203898e8d175SSteven Stallion dnet_reset_board(dnetp); 2039bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2040bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val); 2041bdb9230aSGarrett D'Amore return; 2042bdb9230aSGarrett D'Amore } 2043bdb9230aSGarrett D'Amore 2044bdb9230aSGarrett D'Amore /* 2045bdb9230aSGarrett D'Amore * Set each bit in CSR6 that we want 2046bdb9230aSGarrett D'Amore */ 2047bdb9230aSGarrett D'Amore 2048bdb9230aSGarrett D'Amore /* Always want these bits set */ 2049bdb9230aSGarrett D'Amore val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf; 2050bdb9230aSGarrett D'Amore 2051bdb9230aSGarrett D'Amore /* Promiscuous mode */ 2052bdb9230aSGarrett D'Amore val |= dnetp->promisc ? PROM_MODE : 0; 2053bdb9230aSGarrett D'Amore 2054bdb9230aSGarrett D'Amore /* Scrambler for SYM style media */ 2055bdb9230aSGarrett D'Amore val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ? 2056bdb9230aSGarrett D'Amore SCRAMBLER_MODE : 0; 2057bdb9230aSGarrett D'Amore 2058bdb9230aSGarrett D'Amore /* Full duplex */ 2059bdb9230aSGarrett D'Amore if (dnetp->mii_up) { 2060bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex; 2061bdb9230aSGarrett D'Amore } else { 2062bdb9230aSGarrett D'Amore /* Rely on media code */ 2063bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD || 2064bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD; 2065bdb9230aSGarrett D'Amore } 2066bdb9230aSGarrett D'Amore 2067bdb9230aSGarrett D'Amore /* Port select (and therefore, heartbeat disable) */ 2068bdb9230aSGarrett D'Amore val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0; 2069bdb9230aSGarrett D'Amore 2070bdb9230aSGarrett D'Amore /* PCS function */ 2071bdb9230aSGarrett D'Amore val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0; 2072bdb9230aSGarrett D'Amore val |= fd ? FULL_DUPLEX : 0; 2073bdb9230aSGarrett D'Amore 2074bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 2075bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG) 2076bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "OPN: %x", val); 2077bdb9230aSGarrett D'Amore #endif 2078bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val); 207998e8d175SSteven Stallion dnet_reset_board(dnetp); 2080bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val); 2081bdb9230aSGarrett D'Amore } 2082bdb9230aSGarrett D'Amore 2083bdb9230aSGarrett D'Amore static void 208498e8d175SSteven Stallion set_sia(struct dnetinstance *dnetp) 2085bdb9230aSGarrett D'Amore { 2086bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block; 2087bdb9230aSGarrett D'Amore 2088bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 2089bdb9230aSGarrett D'Amore if (block->type == 2) { 2090bdb9230aSGarrett D'Amore int sia_delay; 2091bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 2092bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG) 2093bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, 2094bdb9230aSGarrett D'Amore "SIA: CSR13: %x, CSR14: %x, CSR15: %x", 2095bdb9230aSGarrett D'Amore block->un.sia.csr13, 2096bdb9230aSGarrett D'Amore block->un.sia.csr14, 2097bdb9230aSGarrett D'Amore block->un.sia.csr15); 2098bdb9230aSGarrett D'Amore #endif 2099bdb9230aSGarrett D'Amore sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 2100bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "sia-delay", 10000); 2101bdb9230aSGarrett D'Amore 2102bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2103bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0); 2104bdb9230aSGarrett D'Amore 2105bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG), 2106bdb9230aSGarrett D'Amore block->un.sia.csr14); 2107bdb9230aSGarrett D'Amore 2108bdb9230aSGarrett D'Amore /* 2109bdb9230aSGarrett D'Amore * For '143, we need to write through a copy of the register 2110bdb9230aSGarrett D'Amore * to keep the GP half intact 2111bdb9230aSGarrett D'Amore */ 2112bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15; 2113bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2114bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG), 2115bdb9230aSGarrett D'Amore dnetp->gprsia); 2116bdb9230aSGarrett D'Amore 2117bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2118bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 2119bdb9230aSGarrett D'Amore block->un.sia.csr13); 2120bdb9230aSGarrett D'Amore 2121bdb9230aSGarrett D'Amore drv_usecwait(sia_delay); 2122bdb9230aSGarrett D'Amore 2123bdb9230aSGarrett D'Amore } else if (dnetp->board_type != DEVICE_ID_21140) { 2124bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2125bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0); 2126bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 2127bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_TXRX_REG), 0); 2128bdb9230aSGarrett D'Amore } 2129bdb9230aSGarrett D'Amore } 2130bdb9230aSGarrett D'Amore 2131bdb9230aSGarrett D'Amore /* 2132bdb9230aSGarrett D'Amore * This function (re)allocates the receive and transmit buffers and 2133bdb9230aSGarrett D'Amore * descriptors. It can be called more than once per instance, though 2134bdb9230aSGarrett D'Amore * currently it is only called from attach. It should only be called 2135bdb9230aSGarrett D'Amore * while the device is reset. 2136bdb9230aSGarrett D'Amore */ 2137bdb9230aSGarrett D'Amore static int 213898e8d175SSteven Stallion dnet_alloc_bufs(struct dnetinstance *dnetp) 2139bdb9230aSGarrett D'Amore { 2140bdb9230aSGarrett D'Amore int i; 2141bdb9230aSGarrett D'Amore size_t len; 2142bdb9230aSGarrett D'Amore int page_size; 2143bdb9230aSGarrett D'Amore int realloc = 0; 2144bdb9230aSGarrett D'Amore int nrecv_desc_old = 0; 2145bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie; 2146bdb9230aSGarrett D'Amore uint_t ncookies; 2147bdb9230aSGarrett D'Amore 2148bdb9230aSGarrett D'Amore /* 2149bdb9230aSGarrett D'Amore * check if we are trying to reallocate with different xmit/recv 2150bdb9230aSGarrett D'Amore * descriptor ring sizes. 2151bdb9230aSGarrett D'Amore */ 2152bdb9230aSGarrett D'Amore if ((dnetp->tx_desc != NULL) && 2153bdb9230aSGarrett D'Amore (dnetp->nxmit_desc != dnetp->max_tx_desc)) 2154bdb9230aSGarrett D'Amore realloc = 1; 2155bdb9230aSGarrett D'Amore 2156bdb9230aSGarrett D'Amore if ((dnetp->rx_desc != NULL) && 2157bdb9230aSGarrett D'Amore (dnetp->nrecv_desc != dnetp->max_rx_desc)) 2158bdb9230aSGarrett D'Amore realloc = 1; 2159bdb9230aSGarrett D'Amore 2160bdb9230aSGarrett D'Amore /* free up the old buffers if we are reallocating them */ 2161bdb9230aSGarrett D'Amore if (realloc) { 2162bdb9230aSGarrett D'Amore nrecv_desc_old = dnetp->nrecv_desc; 216398e8d175SSteven Stallion dnet_free_bufs(dnetp); /* free the old buffers */ 2164bdb9230aSGarrett D'Amore } 2165bdb9230aSGarrett D'Amore 2166bdb9230aSGarrett D'Amore if (dnetp->dma_handle == NULL) 2167bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 2168bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS) 2169bdb9230aSGarrett D'Amore return (FAILURE); 2170bdb9230aSGarrett D'Amore 2171bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx == NULL) 2172bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx, 2173bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS) 2174bdb9230aSGarrett D'Amore return (FAILURE); 2175bdb9230aSGarrett D'Amore 2176bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc == NULL) 2177bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 2178bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS) 2179bdb9230aSGarrett D'Amore return (FAILURE); 2180bdb9230aSGarrett D'Amore 2181bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf == NULL) 2182bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr, 2183bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS) 2184bdb9230aSGarrett D'Amore return (FAILURE); 2185bdb9230aSGarrett D'Amore 2186bdb9230aSGarrett D'Amore page_size = ddi_ptob(dnetp->devinfo, 1); 2187bdb9230aSGarrett D'Amore 2188bdb9230aSGarrett D'Amore dnetp->pgmask = page_size - 1; 2189bdb9230aSGarrett D'Amore 2190bdb9230aSGarrett D'Amore /* allocate setup buffer if necessary */ 2191bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr == NULL) { 2192bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf, 2193bdb9230aSGarrett D'Amore SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING, 2194bdb9230aSGarrett D'Amore DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr, 2195bdb9230aSGarrett D'Amore &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS) 2196bdb9230aSGarrett D'Amore return (FAILURE); 2197bdb9230aSGarrett D'Amore 2198bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf, 2199bdb9230aSGarrett D'Amore NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE, 2200bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 2201bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 2202bdb9230aSGarrett D'Amore return (FAILURE); 2203bdb9230aSGarrett D'Amore 2204bdb9230aSGarrett D'Amore dnetp->setup_buf_paddr = cookie.dmac_address; 2205bdb9230aSGarrett D'Amore bzero(dnetp->setup_buf_vaddr, len); 2206bdb9230aSGarrett D'Amore } 2207bdb9230aSGarrett D'Amore 2208bdb9230aSGarrett D'Amore /* allocate xmit descriptor array of size dnetp->max_tx_desc */ 2209bdb9230aSGarrett D'Amore if (dnetp->tx_desc == NULL) { 2210bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc, 2211bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc, 2212bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 2213bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->tx_desc, &len, 2214bdb9230aSGarrett D'Amore &dnetp->tx_desc_acchdl) != DDI_SUCCESS) 2215bdb9230aSGarrett D'Amore return (FAILURE); 2216bdb9230aSGarrett D'Amore 2217bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc, 2218bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->tx_desc, 2219bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc, 2220bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 2221bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 2222bdb9230aSGarrett D'Amore return (FAILURE); 2223bdb9230aSGarrett D'Amore dnetp->tx_desc_paddr = cookie.dmac_address; 2224bdb9230aSGarrett D'Amore bzero(dnetp->tx_desc, len); 2225bdb9230aSGarrett D'Amore dnetp->nxmit_desc = dnetp->max_tx_desc; 2226bdb9230aSGarrett D'Amore 2227bdb9230aSGarrett D'Amore dnetp->tx_msgbufp = 2228bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **), 2229bdb9230aSGarrett D'Amore KM_SLEEP); 2230bdb9230aSGarrett D'Amore } 2231bdb9230aSGarrett D'Amore 2232bdb9230aSGarrett D'Amore /* allocate receive descriptor array of size dnetp->max_rx_desc */ 2233bdb9230aSGarrett D'Amore if (dnetp->rx_desc == NULL) { 2234bdb9230aSGarrett D'Amore int ndesc; 2235bdb9230aSGarrett D'Amore 2236bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle, 2237bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc, 2238bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 2239bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->rx_desc, &len, 2240bdb9230aSGarrett D'Amore &dnetp->rx_desc_acchdl) != DDI_SUCCESS) 2241bdb9230aSGarrett D'Amore return (FAILURE); 2242bdb9230aSGarrett D'Amore 2243bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle, 2244bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->rx_desc, 2245bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc, 2246bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 2247bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED) 2248bdb9230aSGarrett D'Amore return (FAILURE); 2249bdb9230aSGarrett D'Amore 2250bdb9230aSGarrett D'Amore dnetp->rx_desc_paddr = cookie.dmac_address; 2251bdb9230aSGarrett D'Amore bzero(dnetp->rx_desc, len); 2252bdb9230aSGarrett D'Amore dnetp->nrecv_desc = dnetp->max_rx_desc; 2253bdb9230aSGarrett D'Amore 2254bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr = 2255bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t), 2256bdb9230aSGarrett D'Amore KM_SLEEP); 2257bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr = 2258bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t), 2259bdb9230aSGarrett D'Amore KM_SLEEP); 2260bdb9230aSGarrett D'Amore /* 2261bdb9230aSGarrett D'Amore * Allocate or add to the pool of receive buffers. The pool 2262bdb9230aSGarrett D'Amore * is shared among all instances of dnet. 2263bdb9230aSGarrett D'Amore * 2264bdb9230aSGarrett D'Amore * XXX NEEDSWORK 2265bdb9230aSGarrett D'Amore * 2266bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as 2267bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams 2268bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should 2269bdb9230aSGarrett D'Amore * instead have initialized constants reflecting 2270bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also 2271bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we 2272bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board. 2273bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number 2274bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the 2275bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be 2276bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers: 2277bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free 2278bdb9230aSGarrett D'Amore * pool. 2279bdb9230aSGarrett D'Amore */ 2280bdb9230aSGarrett D'Amore ndesc = dnetp->max_rx_desc - nrecv_desc_old; 2281bdb9230aSGarrett D'Amore if ((ndesc > 0) && 2282bdb9230aSGarrett D'Amore (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0)) 2283bdb9230aSGarrett D'Amore return (FAILURE); 2284bdb9230aSGarrett D'Amore 2285bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->max_rx_desc; i++) { 2286bdb9230aSGarrett D'Amore struct rbuf_list *rp; 2287bdb9230aSGarrett D'Amore 2288bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 1); 2289bdb9230aSGarrett D'Amore if (rp == NULL) 2290bdb9230aSGarrett D'Amore return (FAILURE); 2291bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr; 2292bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[i] = rp->rbuf_paddr; 2293bdb9230aSGarrett D'Amore } 2294bdb9230aSGarrett D'Amore } 2295bdb9230aSGarrett D'Amore 2296bdb9230aSGarrett D'Amore return (SUCCESS); 2297bdb9230aSGarrett D'Amore } 2298bdb9230aSGarrett D'Amore /* 2299bdb9230aSGarrett D'Amore * free descriptors/buffers allocated for this device instance. This routine 2300bdb9230aSGarrett D'Amore * should only be called while the device is reset. 2301bdb9230aSGarrett D'Amore */ 2302bdb9230aSGarrett D'Amore static void 230398e8d175SSteven Stallion dnet_free_bufs(struct dnetinstance *dnetp) 2304bdb9230aSGarrett D'Amore { 2305bdb9230aSGarrett D'Amore int i; 2306bdb9230aSGarrett D'Amore /* free up any xmit descriptors/buffers */ 2307bdb9230aSGarrett D'Amore if (dnetp->tx_desc != NULL) { 2308bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->tx_desc_acchdl); 2309bdb9230aSGarrett D'Amore dnetp->tx_desc = NULL; 2310bdb9230aSGarrett D'Amore /* we use streams buffers for DMA in xmit process */ 2311bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp != NULL) { 2312bdb9230aSGarrett D'Amore /* free up any streams message buffers unclaimed */ 2313bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) { 2314bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) { 2315bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]); 2316bdb9230aSGarrett D'Amore } 2317bdb9230aSGarrett D'Amore } 2318bdb9230aSGarrett D'Amore kmem_free(dnetp->tx_msgbufp, 2319bdb9230aSGarrett D'Amore dnetp->nxmit_desc * sizeof (mblk_t **)); 2320bdb9230aSGarrett D'Amore dnetp->tx_msgbufp = NULL; 2321bdb9230aSGarrett D'Amore } 2322bdb9230aSGarrett D'Amore dnetp->nxmit_desc = 0; 2323bdb9230aSGarrett D'Amore } 2324bdb9230aSGarrett D'Amore 2325bdb9230aSGarrett D'Amore /* free up any receive descriptors/buffers */ 2326bdb9230aSGarrett D'Amore if (dnetp->rx_desc != NULL) { 2327bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->rx_desc_acchdl); 2328bdb9230aSGarrett D'Amore dnetp->rx_desc = NULL; 2329bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr != NULL) { 2330bdb9230aSGarrett D'Amore /* free up the attached rbufs if any */ 2331bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) { 2332bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr[i]) 2333bdb9230aSGarrett D'Amore dnet_rbuf_free( 2334bdb9230aSGarrett D'Amore (caddr_t)dnetp->rx_buf_vaddr[i]); 2335bdb9230aSGarrett D'Amore } 2336bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_vaddr, 2337bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (caddr_t)); 2338bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_paddr, 2339bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (uint32_t)); 2340bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr = NULL; 2341bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr = NULL; 2342bdb9230aSGarrett D'Amore } 2343bdb9230aSGarrett D'Amore dnetp->nrecv_desc = 0; 2344bdb9230aSGarrett D'Amore } 2345bdb9230aSGarrett D'Amore 2346bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr != NULL) { 2347bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->setup_buf_acchdl); 2348bdb9230aSGarrett D'Amore dnetp->setup_buf_vaddr = NULL; 2349bdb9230aSGarrett D'Amore } 2350bdb9230aSGarrett D'Amore 2351bdb9230aSGarrett D'Amore if (dnetp->dma_handle != NULL) { 2352bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle); 2353bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle); 2354bdb9230aSGarrett D'Amore dnetp->dma_handle = NULL; 2355bdb9230aSGarrett D'Amore } 2356bdb9230aSGarrett D'Amore 2357bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx != NULL) { 2358bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx); 2359bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_tx); 2360bdb9230aSGarrett D'Amore dnetp->dma_handle_tx = NULL; 2361bdb9230aSGarrett D'Amore } 2362bdb9230aSGarrett D'Amore 2363bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc != NULL) { 2364bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc); 2365bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_txdesc); 2366bdb9230aSGarrett D'Amore dnetp->dma_handle_txdesc = NULL; 2367bdb9230aSGarrett D'Amore } 2368bdb9230aSGarrett D'Amore 2369bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf != NULL) { 2370bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf); 2371bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_setbuf); 2372bdb9230aSGarrett D'Amore dnetp->dma_handle_setbuf = NULL; 2373bdb9230aSGarrett D'Amore } 2374bdb9230aSGarrett D'Amore 2375bdb9230aSGarrett D'Amore } 2376bdb9230aSGarrett D'Amore 2377bdb9230aSGarrett D'Amore /* 2378bdb9230aSGarrett D'Amore * Initialize transmit and receive descriptors. 2379bdb9230aSGarrett D'Amore */ 2380bdb9230aSGarrett D'Amore static void 238198e8d175SSteven Stallion dnet_init_txrx_bufs(struct dnetinstance *dnetp) 2382bdb9230aSGarrett D'Amore { 2383bdb9230aSGarrett D'Amore int i; 2384bdb9230aSGarrett D'Amore 2385bdb9230aSGarrett D'Amore /* 2386bdb9230aSGarrett D'Amore * Initilize all the Tx descriptors 2387bdb9230aSGarrett D'Amore */ 2388bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) { 2389bdb9230aSGarrett D'Amore /* 2390bdb9230aSGarrett D'Amore * We may be resetting the device due to errors, 2391bdb9230aSGarrett D'Amore * so free up any streams message buffer unclaimed. 2392bdb9230aSGarrett D'Amore */ 2393bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) { 2394bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]); 2395bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[i] = NULL; 2396bdb9230aSGarrett D'Amore } 2397bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc0 = 0; 2398bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc1 = 0; 2399bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer1 = 0; 2400bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer2 = 0; 2401bdb9230aSGarrett D'Amore } 2402bdb9230aSGarrett D'Amore dnetp->tx_desc[i - 1].desc1.end_of_ring = 1; 2403bdb9230aSGarrett D'Amore 2404bdb9230aSGarrett D'Amore /* 2405bdb9230aSGarrett D'Amore * Initialize the Rx descriptors 2406bdb9230aSGarrett D'Amore */ 2407bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) { 2408bdb9230aSGarrett D'Amore uint32_t end_paddr; 2409bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc0 = 0; 2410bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc1 = 0; 2411bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc0.own = 1; 2412bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size; 2413bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i]; 2414bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = 0; 2415bdb9230aSGarrett D'Amore end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1; 2416bdb9230aSGarrett D'Amore 2417bdb9230aSGarrett D'Amore if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) != 2418bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) { 2419bdb9230aSGarrett D'Amore /* discontiguous */ 2420bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask; 2421bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size2 = 2422bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1; 2423bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 = 2424bdb9230aSGarrett D'Amore rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2; 2425bdb9230aSGarrett D'Amore } 2426bdb9230aSGarrett D'Amore } 2427bdb9230aSGarrett D'Amore dnetp->rx_desc[i - 1].desc1.end_of_ring = 1; 2428bdb9230aSGarrett D'Amore } 2429bdb9230aSGarrett D'Amore 2430bdb9230aSGarrett D'Amore static int 243198e8d175SSteven Stallion alloc_descriptor(struct dnetinstance *dnetp) 2432bdb9230aSGarrett D'Amore { 2433bdb9230aSGarrett D'Amore int index; 2434bdb9230aSGarrett D'Amore struct tx_desc_type *ring = dnetp->tx_desc; 2435bdb9230aSGarrett D'Amore 2436bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 2437bdb9230aSGarrett D'Amore alloctop: 2438bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock); 2439bdb9230aSGarrett D'Amore index = dnetp->tx_current_desc; 2440bdb9230aSGarrett D'Amore 244198e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp); 2442bdb9230aSGarrett D'Amore 2443bdb9230aSGarrett D'Amore /* we do have free descriptors, right? */ 2444bdb9230aSGarrett D'Amore if (dnetp->free_desc <= 0) { 2445bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 2446bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV) 2447bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Ring buffer is full"); 2448bdb9230aSGarrett D'Amore #endif 2449bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 2450bdb9230aSGarrett D'Amore return (FAILURE); 2451bdb9230aSGarrett D'Amore } 2452bdb9230aSGarrett D'Amore 2453bdb9230aSGarrett D'Amore /* sanity, make sure the next descriptor is free for use (should be) */ 2454bdb9230aSGarrett D'Amore if (ring[index].desc0.own) { 2455bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 2456bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV) 2457bdb9230aSGarrett D'Amore cmn_err(CE_WARN, 2458bdb9230aSGarrett D'Amore "dnet: next descriptor is not free for use"); 2459bdb9230aSGarrett D'Amore #endif 2460bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 2461bdb9230aSGarrett D'Amore return (FAILURE); 2462bdb9230aSGarrett D'Amore } 2463bdb9230aSGarrett D'Amore if (dnetp->need_saddr) { 2464bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 2465bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 2466bdb9230aSGarrett D'Amore if (!dnetp->suspended) 246798e8d175SSteven Stallion (void) dnet_set_addr(dnetp); 2468bdb9230aSGarrett D'Amore goto alloctop; 2469bdb9230aSGarrett D'Amore } 2470bdb9230aSGarrett D'Amore 2471bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0; /* init descs */ 2472bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING; 2473bdb9230aSGarrett D'Amore 2474bdb9230aSGarrett D'Amore /* hardware will own this descriptor when poll activated */ 2475bdb9230aSGarrett D'Amore dnetp->free_desc--; 2476bdb9230aSGarrett D'Amore 2477bdb9230aSGarrett D'Amore /* point to next free descriptor to be used */ 2478bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(index); 2479bdb9230aSGarrett D'Amore 2480bdb9230aSGarrett D'Amore #ifdef DNET_NOISY 2481bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x", 2482bdb9230aSGarrett D'Amore dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc); 2483bdb9230aSGarrett D'Amore #endif 2484bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock); 2485bdb9230aSGarrett D'Amore return (SUCCESS); 2486bdb9230aSGarrett D'Amore } 2487bdb9230aSGarrett D'Amore 2488bdb9230aSGarrett D'Amore /* 2489bdb9230aSGarrett D'Amore * dnet_reclaim_Tx_desc() - called with txlock held. 2490bdb9230aSGarrett D'Amore */ 2491bdb9230aSGarrett D'Amore static void 249298e8d175SSteven Stallion dnet_reclaim_Tx_desc(struct dnetinstance *dnetp) 2493bdb9230aSGarrett D'Amore { 2494bdb9230aSGarrett D'Amore struct tx_desc_type *desc = dnetp->tx_desc; 2495bdb9230aSGarrett D'Amore int index; 2496bdb9230aSGarrett D'Amore 2497bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->txlock)); 2498bdb9230aSGarrett D'Amore 2499bdb9230aSGarrett D'Amore index = dnetp->transmitted_desc; 2500bdb9230aSGarrett D'Amore while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) && 2501bdb9230aSGarrett D'Amore !(desc[index].desc0.own)) { 2502bdb9230aSGarrett D'Amore /* 2503bdb9230aSGarrett D'Amore * Check for Tx Error that gets set 2504bdb9230aSGarrett D'Amore * in the last desc. 2505bdb9230aSGarrett D'Amore */ 2506bdb9230aSGarrett D'Amore if (desc[index].desc1.setup_packet == 0 && 2507bdb9230aSGarrett D'Amore desc[index].desc1.last_desc && 2508bdb9230aSGarrett D'Amore desc[index].desc0.err_summary) 250998e8d175SSteven Stallion update_tx_stats(dnetp, index); 2510bdb9230aSGarrett D'Amore 2511bdb9230aSGarrett D'Amore /* 2512bdb9230aSGarrett D'Amore * If we have used the streams message buffer for this 2513bdb9230aSGarrett D'Amore * descriptor then free up the message now. 2514bdb9230aSGarrett D'Amore */ 2515bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[index] != NULL) { 2516bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[index]); 2517bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[index] = NULL; 2518bdb9230aSGarrett D'Amore } 2519bdb9230aSGarrett D'Amore dnetp->free_desc++; 2520bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_tx_desc; 2521bdb9230aSGarrett D'Amore } 2522bdb9230aSGarrett D'Amore 2523bdb9230aSGarrett D'Amore dnetp->transmitted_desc = index; 2524bdb9230aSGarrett D'Amore } 2525bdb9230aSGarrett D'Amore 2526bdb9230aSGarrett D'Amore /* 2527bdb9230aSGarrett D'Amore * Receive buffer allocation/freeing routines. 2528bdb9230aSGarrett D'Amore * 2529bdb9230aSGarrett D'Amore * There is a common pool of receive buffers shared by all dnet instances. 2530bdb9230aSGarrett D'Amore * 2531bdb9230aSGarrett D'Amore * XXX NEEDSWORK 2532bdb9230aSGarrett D'Amore * 2533bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as 2534bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams 2535bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should 2536bdb9230aSGarrett D'Amore * instead have initialized constants reflecting 2537bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also 2538bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we 2539bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board. 2540bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number 2541bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the 2542bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be 2543bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers: 2544bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free 2545bdb9230aSGarrett D'Amore * pool. 2546bdb9230aSGarrett D'Amore */ 2547bdb9230aSGarrett D'Amore 2548bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_head; 2549bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_freelist_head; 2550bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_end; /* last buffer allocated */ 2551bdb9230aSGarrett D'Amore 2552bdb9230aSGarrett D'Amore static int rbuf_freebufs; /* no. of free buffers in the pool */ 2553bdb9230aSGarrett D'Amore static int rbuf_pool_size; /* total no. of buffers in the pool */ 2554bdb9230aSGarrett D'Amore 2555bdb9230aSGarrett D'Amore /* initialize/add 'nbufs' buffers to the rbuf pool */ 2556bdb9230aSGarrett D'Amore /* ARGSUSED */ 2557bdb9230aSGarrett D'Amore static int 2558bdb9230aSGarrett D'Amore dnet_rbuf_init(dev_info_t *dip, int nbufs) 2559bdb9230aSGarrett D'Amore { 2560bdb9230aSGarrett D'Amore int i; 2561bdb9230aSGarrett D'Amore struct rbuf_list *rp; 2562bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie; 2563bdb9230aSGarrett D'Amore uint_t ncookies; 2564bdb9230aSGarrett D'Amore size_t len; 2565bdb9230aSGarrett D'Amore 2566bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock); 2567bdb9230aSGarrett D'Amore 2568bdb9230aSGarrett D'Amore /* allocate buffers and add them to the pool */ 2569bdb9230aSGarrett D'Amore for (i = 0; i < nbufs; i++) { 2570bdb9230aSGarrett D'Amore /* allocate rbuf_list element */ 2571bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP); 2572bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP, 2573bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS) 2574bdb9230aSGarrett D'Amore goto fail_kfree; 2575bdb9230aSGarrett D'Amore 2576bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */ 2577bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr, 2578bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 2579bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len, 2580bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS) 2581bdb9230aSGarrett D'Amore goto fail_freehdl; 2582bdb9230aSGarrett D'Amore 2583bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL, 2584bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING, 2585bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, 2586bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED) 2587bdb9230aSGarrett D'Amore goto fail_free; 2588bdb9230aSGarrett D'Amore 2589bdb9230aSGarrett D'Amore if (ncookies > 2) 2590bdb9230aSGarrett D'Amore goto fail_unbind; 2591bdb9230aSGarrett D'Amore if (ncookies == 1) { 2592bdb9230aSGarrett D'Amore rp->rbuf_endpaddr = 2593bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1; 2594bdb9230aSGarrett D'Amore } else { 2595bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie); 2596bdb9230aSGarrett D'Amore rp->rbuf_endpaddr = 2597bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1; 2598bdb9230aSGarrett D'Amore } 2599bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address; 2600bdb9230aSGarrett D'Amore 2601bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head; 2602bdb9230aSGarrett D'Amore rbuf_freelist_head = rp; 2603bdb9230aSGarrett D'Amore rbuf_pool_size++; 2604bdb9230aSGarrett D'Amore rbuf_freebufs++; 2605bdb9230aSGarrett D'Amore } 2606bdb9230aSGarrett D'Amore 2607bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2608bdb9230aSGarrett D'Amore return (0); 2609bdb9230aSGarrett D'Amore fail_unbind: 2610bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 2611bdb9230aSGarrett D'Amore fail_free: 2612bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl); 2613bdb9230aSGarrett D'Amore fail_freehdl: 2614bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl); 2615bdb9230aSGarrett D'Amore fail_kfree: 2616bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list)); 2617bdb9230aSGarrett D'Amore 2618bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2619bdb9230aSGarrett D'Amore return (-1); 2620bdb9230aSGarrett D'Amore } 2621bdb9230aSGarrett D'Amore 2622bdb9230aSGarrett D'Amore /* 2623bdb9230aSGarrett D'Amore * Try to free up all the rbufs in the pool. Returns 0 if it frees up all 2624bdb9230aSGarrett D'Amore * buffers. The buffers in the used list are considered busy so these 2625bdb9230aSGarrett D'Amore * buffers are not freed. 2626bdb9230aSGarrett D'Amore */ 2627bdb9230aSGarrett D'Amore static int 2628bdb9230aSGarrett D'Amore dnet_rbuf_destroy() 2629bdb9230aSGarrett D'Amore { 2630bdb9230aSGarrett D'Amore struct rbuf_list *rp, *next; 2631bdb9230aSGarrett D'Amore 2632bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock); 2633bdb9230aSGarrett D'Amore 2634bdb9230aSGarrett D'Amore for (rp = rbuf_freelist_head; rp; rp = next) { 2635bdb9230aSGarrett D'Amore next = rp->rbuf_next; 2636bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl); 2637bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 2638bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list)); 2639bdb9230aSGarrett D'Amore rbuf_pool_size--; 2640bdb9230aSGarrett D'Amore rbuf_freebufs--; 2641bdb9230aSGarrett D'Amore } 2642bdb9230aSGarrett D'Amore rbuf_freelist_head = NULL; 2643bdb9230aSGarrett D'Amore 2644bdb9230aSGarrett D'Amore if (rbuf_pool_size) { /* pool is still not empty */ 2645bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2646bdb9230aSGarrett D'Amore return (-1); 2647bdb9230aSGarrett D'Amore } 2648bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2649bdb9230aSGarrett D'Amore return (0); 2650bdb9230aSGarrett D'Amore } 2651bdb9230aSGarrett D'Amore static struct rbuf_list * 2652bdb9230aSGarrett D'Amore dnet_rbuf_alloc(dev_info_t *dip, int cansleep) 2653bdb9230aSGarrett D'Amore { 2654bdb9230aSGarrett D'Amore struct rbuf_list *rp; 2655bdb9230aSGarrett D'Amore size_t len; 2656bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie; 2657bdb9230aSGarrett D'Amore uint_t ncookies; 2658bdb9230aSGarrett D'Amore 2659bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock); 2660bdb9230aSGarrett D'Amore 2661bdb9230aSGarrett D'Amore if (rbuf_freelist_head == NULL) { 2662bdb9230aSGarrett D'Amore 2663bdb9230aSGarrett D'Amore if (!cansleep) { 2664bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2665bdb9230aSGarrett D'Amore return (NULL); 2666bdb9230aSGarrett D'Amore } 2667bdb9230aSGarrett D'Amore 2668bdb9230aSGarrett D'Amore /* allocate rbuf_list element */ 2669bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP); 2670bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP, 2671bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS) 2672bdb9230aSGarrett D'Amore goto fail_kfree; 2673bdb9230aSGarrett D'Amore 2674bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */ 2675bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr, 2676bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 2677bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len, 2678bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS) 2679bdb9230aSGarrett D'Amore goto fail_freehdl; 2680bdb9230aSGarrett D'Amore 2681bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL, 2682bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING, 2683bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, 2684bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED) 2685bdb9230aSGarrett D'Amore goto fail_free; 2686bdb9230aSGarrett D'Amore 2687bdb9230aSGarrett D'Amore if (ncookies > 2) 2688bdb9230aSGarrett D'Amore goto fail_unbind; 2689bdb9230aSGarrett D'Amore if (ncookies == 1) { 2690bdb9230aSGarrett D'Amore rp->rbuf_endpaddr = 2691bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1; 2692bdb9230aSGarrett D'Amore } else { 2693bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie); 2694bdb9230aSGarrett D'Amore rp->rbuf_endpaddr = 2695bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1; 2696bdb9230aSGarrett D'Amore } 2697bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address; 2698bdb9230aSGarrett D'Amore 2699bdb9230aSGarrett D'Amore rbuf_freelist_head = rp; 2700bdb9230aSGarrett D'Amore rbuf_pool_size++; 2701bdb9230aSGarrett D'Amore rbuf_freebufs++; 2702bdb9230aSGarrett D'Amore } 2703bdb9230aSGarrett D'Amore 2704bdb9230aSGarrett D'Amore /* take the buffer from the head of the free list */ 2705bdb9230aSGarrett D'Amore rp = rbuf_freelist_head; 2706bdb9230aSGarrett D'Amore rbuf_freelist_head = rbuf_freelist_head->rbuf_next; 2707bdb9230aSGarrett D'Amore 2708bdb9230aSGarrett D'Amore /* update the used list; put the entry at the end */ 2709bdb9230aSGarrett D'Amore if (rbuf_usedlist_head == NULL) 2710bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp; 2711bdb9230aSGarrett D'Amore else 2712bdb9230aSGarrett D'Amore rbuf_usedlist_end->rbuf_next = rp; 2713bdb9230aSGarrett D'Amore rp->rbuf_next = NULL; 2714bdb9230aSGarrett D'Amore rbuf_usedlist_end = rp; 2715bdb9230aSGarrett D'Amore rbuf_freebufs--; 2716bdb9230aSGarrett D'Amore 2717bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2718bdb9230aSGarrett D'Amore 2719bdb9230aSGarrett D'Amore return (rp); 2720bdb9230aSGarrett D'Amore fail_unbind: 2721bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl); 2722bdb9230aSGarrett D'Amore fail_free: 2723bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl); 2724bdb9230aSGarrett D'Amore fail_freehdl: 2725bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl); 2726bdb9230aSGarrett D'Amore fail_kfree: 2727bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list)); 2728bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2729bdb9230aSGarrett D'Amore return (NULL); 2730bdb9230aSGarrett D'Amore } 2731bdb9230aSGarrett D'Amore 2732bdb9230aSGarrett D'Amore static void 2733bdb9230aSGarrett D'Amore dnet_rbuf_free(caddr_t vaddr) 2734bdb9230aSGarrett D'Amore { 2735bdb9230aSGarrett D'Amore struct rbuf_list *rp, *prev; 2736bdb9230aSGarrett D'Amore 2737bdb9230aSGarrett D'Amore ASSERT(vaddr != NULL); 2738bdb9230aSGarrett D'Amore ASSERT(rbuf_usedlist_head != NULL); 2739bdb9230aSGarrett D'Amore 2740bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock); 2741bdb9230aSGarrett D'Amore 2742bdb9230aSGarrett D'Amore /* find the entry in the used list */ 2743bdb9230aSGarrett D'Amore for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) { 2744bdb9230aSGarrett D'Amore if (rp->rbuf_vaddr == vaddr) 2745bdb9230aSGarrett D'Amore break; 2746bdb9230aSGarrett D'Amore prev = rp; 2747bdb9230aSGarrett D'Amore } 2748bdb9230aSGarrett D'Amore 2749bdb9230aSGarrett D'Amore if (rp == NULL) { 2750bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p", 2751bdb9230aSGarrett D'Amore (void *)vaddr); 2752bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2753bdb9230aSGarrett D'Amore return; 2754bdb9230aSGarrett D'Amore } 2755bdb9230aSGarrett D'Amore 2756bdb9230aSGarrett D'Amore /* update the used list and put the buffer back in the free list */ 2757bdb9230aSGarrett D'Amore if (rbuf_usedlist_head != rp) { 2758bdb9230aSGarrett D'Amore prev->rbuf_next = rp->rbuf_next; 2759bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp) 2760bdb9230aSGarrett D'Amore rbuf_usedlist_end = prev; 2761bdb9230aSGarrett D'Amore } else { 2762bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp->rbuf_next; 2763bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp) 2764bdb9230aSGarrett D'Amore rbuf_usedlist_end = NULL; 2765bdb9230aSGarrett D'Amore } 2766bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head; 2767bdb9230aSGarrett D'Amore rbuf_freelist_head = rp; 2768bdb9230aSGarrett D'Amore rbuf_freebufs++; 2769bdb9230aSGarrett D'Amore 2770bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock); 2771bdb9230aSGarrett D'Amore } 2772bdb9230aSGarrett D'Amore 2773bdb9230aSGarrett D'Amore /* 2774bdb9230aSGarrett D'Amore * Free the receive buffer used in a stream's message block allocated 2775bdb9230aSGarrett D'Amore * thru desballoc(). 2776bdb9230aSGarrett D'Amore */ 2777bdb9230aSGarrett D'Amore static void 2778bdb9230aSGarrett D'Amore dnet_freemsg_buf(struct free_ptr *frp) 2779bdb9230aSGarrett D'Amore { 2780bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */ 2781bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */ 2782bdb9230aSGarrett D'Amore } 2783bdb9230aSGarrett D'Amore 2784bdb9230aSGarrett D'Amore /* 2785bdb9230aSGarrett D'Amore * ========== SROM Read Routines ========== 2786bdb9230aSGarrett D'Amore */ 2787bdb9230aSGarrett D'Amore 2788bdb9230aSGarrett D'Amore /* 2789bdb9230aSGarrett D'Amore * The following code gets the SROM information, either by reading it 2790bdb9230aSGarrett D'Amore * from the device or, failing that, by reading a property. 2791bdb9230aSGarrett D'Amore */ 2792bdb9230aSGarrett D'Amore static int 2793bdb9230aSGarrett D'Amore dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle, 2794bdb9230aSGarrett D'Amore caddr_t io_reg, uchar_t *vi, int maxlen) 2795bdb9230aSGarrett D'Amore { 2796bdb9230aSGarrett D'Amore int all_ones, zerocheck, i; 2797bdb9230aSGarrett D'Amore 2798bdb9230aSGarrett D'Amore /* 2799bdb9230aSGarrett D'Amore * Load SROM into vendor_info 2800bdb9230aSGarrett D'Amore */ 2801bdb9230aSGarrett D'Amore if (board_type == DEVICE_ID_21040) 2802bdb9230aSGarrett D'Amore dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen); 2803bdb9230aSGarrett D'Amore else 2804bdb9230aSGarrett D'Amore /* 21041/21140 serial rom */ 2805bdb9230aSGarrett D'Amore dnet_read21140srom(io_handle, io_reg, vi, maxlen); 2806bdb9230aSGarrett D'Amore /* 2807bdb9230aSGarrett D'Amore * If the dumpsrom property is present in the conf file, print 2808bdb9230aSGarrett D'Amore * the contents of the SROM to the console 2809bdb9230aSGarrett D'Amore */ 2810bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 2811bdb9230aSGarrett D'Amore "dumpsrom", 0)) 2812bdb9230aSGarrett D'Amore dnet_dumpbin("SROM", vi, 1, maxlen); 2813bdb9230aSGarrett D'Amore 2814bdb9230aSGarrett D'Amore for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) { 2815bdb9230aSGarrett D'Amore zerocheck |= vi[i]; 2816bdb9230aSGarrett D'Amore all_ones &= vi[i]; 2817bdb9230aSGarrett D'Amore } 2818bdb9230aSGarrett D'Amore if (zerocheck == 0 || all_ones == 0xff) { 2819bdb9230aSGarrett D'Amore return (get_alternative_srom_image(devinfo, vi, maxlen)); 2820bdb9230aSGarrett D'Amore } else { 2821bdb9230aSGarrett D'Amore #ifdef BUG_4010796 2822bdb9230aSGarrett D'Amore set_alternative_srom_image(devinfo, vi, maxlen); 2823bdb9230aSGarrett D'Amore #endif 2824bdb9230aSGarrett D'Amore return (0); /* Primary */ 2825bdb9230aSGarrett D'Amore } 2826bdb9230aSGarrett D'Amore } 2827bdb9230aSGarrett D'Amore 2828bdb9230aSGarrett D'Amore /* 2829bdb9230aSGarrett D'Amore * The function reads the ethernet address of the 21040 adapter 2830bdb9230aSGarrett D'Amore */ 2831bdb9230aSGarrett D'Amore static void 2832bdb9230aSGarrett D'Amore dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg, 2833bdb9230aSGarrett D'Amore uchar_t *addr, int *len) 2834bdb9230aSGarrett D'Amore { 2835bdb9230aSGarrett D'Amore uint32_t val; 2836bdb9230aSGarrett D'Amore int i; 2837bdb9230aSGarrett D'Amore 2838bdb9230aSGarrett D'Amore /* No point reading more than the ethernet address */ 2839bdb9230aSGarrett D'Amore *len = ddi_getprop(DDI_DEV_T_ANY, dip, 2840bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL; 2841bdb9230aSGarrett D'Amore 2842bdb9230aSGarrett D'Amore /* Reset ROM pointer */ 2843bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0); 2844bdb9230aSGarrett D'Amore for (i = 0; i < *len; i++) { 2845bdb9230aSGarrett D'Amore do { 2846bdb9230aSGarrett D'Amore val = ddi_get32(io_handle, 2847bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG)); 2848bdb9230aSGarrett D'Amore } while (val & 0x80000000); 2849bdb9230aSGarrett D'Amore addr[i] = val & 0xFF; 2850bdb9230aSGarrett D'Amore } 2851bdb9230aSGarrett D'Amore } 2852bdb9230aSGarrett D'Amore 2853bdb9230aSGarrett D'Amore #define drv_nsecwait(x) drv_usecwait(((x)+999)/1000) /* XXX */ 2854bdb9230aSGarrett D'Amore 2855bdb9230aSGarrett D'Amore /* 2856bdb9230aSGarrett D'Amore * The function reads the SROM of the 21140 adapter 2857bdb9230aSGarrett D'Amore */ 2858bdb9230aSGarrett D'Amore static void 2859bdb9230aSGarrett D'Amore dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr, 2860bdb9230aSGarrett D'Amore int maxlen) 2861bdb9230aSGarrett D'Amore { 2862bdb9230aSGarrett D'Amore uint32_t i, j; 2863bdb9230aSGarrett D'Amore uint32_t dout; 2864bdb9230aSGarrett D'Amore uint16_t word; 2865bdb9230aSGarrett D'Amore uint8_t rom_addr; 2866bdb9230aSGarrett D'Amore uint8_t bit; 2867bdb9230aSGarrett D'Amore 2868bdb9230aSGarrett D'Amore 2869bdb9230aSGarrett D'Amore rom_addr = 0; 2870bdb9230aSGarrett D'Amore for (i = 0; i < maxlen; i += 2) { 2871bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2872bdb9230aSGarrett D'Amore READ_OP | SEL_ROM); 2873bdb9230aSGarrett D'Amore drv_nsecwait(30); 2874bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2875bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP); 2876bdb9230aSGarrett D'Amore drv_nsecwait(50); 2877bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2878bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 2879bdb9230aSGarrett D'Amore drv_nsecwait(250); 2880bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2881bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP); 2882bdb9230aSGarrett D'Amore drv_nsecwait(100); 2883bdb9230aSGarrett D'Amore 2884bdb9230aSGarrett D'Amore /* command */ 2885bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2886bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 2887bdb9230aSGarrett D'Amore drv_nsecwait(150); 2888bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2889bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK); 2890bdb9230aSGarrett D'Amore drv_nsecwait(250); 2891bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2892bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 2893bdb9230aSGarrett D'Amore drv_nsecwait(250); 2894bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2895bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK); 2896bdb9230aSGarrett D'Amore drv_nsecwait(250); 2897bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2898bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN); 2899bdb9230aSGarrett D'Amore drv_nsecwait(100); 2900bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2901bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP); 2902bdb9230aSGarrett D'Amore drv_nsecwait(150); 2903bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2904bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 2905bdb9230aSGarrett D'Amore drv_nsecwait(250); 2906bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2907bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP); 2908bdb9230aSGarrett D'Amore drv_nsecwait(100); 2909bdb9230aSGarrett D'Amore 2910bdb9230aSGarrett D'Amore /* Address */ 2911bdb9230aSGarrett D'Amore for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) { 2912bdb9230aSGarrett D'Amore bit = (rom_addr & j) ? DATA_IN : 0; 2913bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2914bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit); 2915bdb9230aSGarrett D'Amore drv_nsecwait(150); 2916bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2917bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK); 2918bdb9230aSGarrett D'Amore drv_nsecwait(250); 2919bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2920bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit); 2921bdb9230aSGarrett D'Amore drv_nsecwait(100); 2922bdb9230aSGarrett D'Amore } 2923bdb9230aSGarrett D'Amore drv_nsecwait(150); 2924bdb9230aSGarrett D'Amore 2925bdb9230aSGarrett D'Amore /* Data */ 2926bdb9230aSGarrett D'Amore word = 0; 2927bdb9230aSGarrett D'Amore for (j = 0x8000; j >= 1; j >>= 1) { 2928bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2929bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK); 2930bdb9230aSGarrett D'Amore drv_nsecwait(100); 2931bdb9230aSGarrett D'Amore dout = ddi_get32(io_handle, 2932bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG)); 2933bdb9230aSGarrett D'Amore drv_nsecwait(150); 2934bdb9230aSGarrett D'Amore if (dout & DATA_OUT) 2935bdb9230aSGarrett D'Amore word |= j; 2936bdb9230aSGarrett D'Amore ddi_put32(io_handle, 2937bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG), 2938bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP); 2939bdb9230aSGarrett D'Amore drv_nsecwait(250); 2940bdb9230aSGarrett D'Amore } 2941bdb9230aSGarrett D'Amore addr[i] = (word & 0x0000FF); 2942bdb9230aSGarrett D'Amore addr[i + 1] = (word >> 8); 2943bdb9230aSGarrett D'Amore rom_addr++; 2944bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 2945bdb9230aSGarrett D'Amore READ_OP | SEL_ROM); 2946bdb9230aSGarrett D'Amore drv_nsecwait(100); 2947bdb9230aSGarrett D'Amore } 2948bdb9230aSGarrett D'Amore } 2949bdb9230aSGarrett D'Amore 2950bdb9230aSGarrett D'Amore 2951bdb9230aSGarrett D'Amore /* 2952bdb9230aSGarrett D'Amore * XXX NEEDSWORK 2953bdb9230aSGarrett D'Amore * 2954bdb9230aSGarrett D'Amore * Some lame multiport cards have only one SROM, which can be accessed 2955bdb9230aSGarrett D'Amore * only from the "first" 21x4x chip, whichever that one is. If we can't 2956bdb9230aSGarrett D'Amore * get at our SROM, we look for its contents in a property instead, which 2957bdb9230aSGarrett D'Amore * we rely on the bootstrap to have properly set. 2958bdb9230aSGarrett D'Amore * #ifdef BUG_4010796 2959bdb9230aSGarrett D'Amore * We also have a hack to try to set it ourselves, when the "first" port 2960bdb9230aSGarrett D'Amore * attaches, if it has not already been properly set. However, this method 2961bdb9230aSGarrett D'Amore * is not reliable, since it makes the unwarrented assumption that the 2962bdb9230aSGarrett D'Amore * "first" port will attach first. 2963bdb9230aSGarrett D'Amore * #endif 2964bdb9230aSGarrett D'Amore */ 2965bdb9230aSGarrett D'Amore 2966bdb9230aSGarrett D'Amore static int 2967bdb9230aSGarrett D'Amore get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len) 2968bdb9230aSGarrett D'Amore { 2969bdb9230aSGarrett D'Amore int l = len; 2970bdb9230aSGarrett D'Amore 2971bdb9230aSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 2972bdb9230aSGarrett D'Amore "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS && 2973bdb9230aSGarrett D'Amore (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY, 2974bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM", 2975bdb9230aSGarrett D'Amore (caddr_t)vi, &len) != DDI_PROP_SUCCESS) 2976bdb9230aSGarrett D'Amore return (-1); /* Can't find it! */ 2977bdb9230aSGarrett D'Amore 2978bdb9230aSGarrett D'Amore /* 2979bdb9230aSGarrett D'Amore * The return value from this routine specifies which port number 2980bdb9230aSGarrett D'Amore * we are. The primary port is denoted port 0. On a QUAD card we 2981bdb9230aSGarrett D'Amore * should return 1, 2, and 3 from this routine. The return value 2982bdb9230aSGarrett D'Amore * is used to modify the ethernet address from the SROM data. 2983bdb9230aSGarrett D'Amore */ 2984bdb9230aSGarrett D'Amore 2985bdb9230aSGarrett D'Amore #ifdef BUG_4010796 2986bdb9230aSGarrett D'Amore { 2987bdb9230aSGarrett D'Amore /* 2988bdb9230aSGarrett D'Amore * For the present, we remember the device number of our primary 2989bdb9230aSGarrett D'Amore * sibling and hope we and our other siblings are consecutively 2990bdb9230aSGarrett D'Amore * numbered up from there. In the future perhaps the bootstrap 2991bdb9230aSGarrett D'Amore * will pass us the necessary information telling us which physical 2992bdb9230aSGarrett D'Amore * port we really are. 2993bdb9230aSGarrett D'Amore */ 2994bdb9230aSGarrett D'Amore pci_regspec_t *assignp; 2995bdb9230aSGarrett D'Amore int assign_len; 2996bdb9230aSGarrett D'Amore int devnum; 2997bdb9230aSGarrett D'Amore int primary_devnum; 2998bdb9230aSGarrett D'Amore 2999bdb9230aSGarrett D'Amore primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0, 3000bdb9230aSGarrett D'Amore "DNET_DEVNUM", -1); 3001bdb9230aSGarrett D'Amore if (primary_devnum == -1) 3002bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */ 3003bdb9230aSGarrett D'Amore 3004bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 3005bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp, 3006bdb9230aSGarrett D'Amore &assign_len)) != DDI_PROP_SUCCESS) 3007bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */ 3008bdb9230aSGarrett D'Amore 3009bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi); 3010bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len); 3011bdb9230aSGarrett D'Amore return (devnum - primary_devnum); 3012bdb9230aSGarrett D'Amore } 3013bdb9230aSGarrett D'Amore #else 3014bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */ 3015bdb9230aSGarrett D'Amore #endif 3016bdb9230aSGarrett D'Amore } 3017bdb9230aSGarrett D'Amore 3018bdb9230aSGarrett D'Amore 3019bdb9230aSGarrett D'Amore #ifdef BUG_4010796 3020bdb9230aSGarrett D'Amore static void 3021bdb9230aSGarrett D'Amore set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len) 3022bdb9230aSGarrett D'Amore { 3023bdb9230aSGarrett D'Amore int proplen; 3024bdb9230aSGarrett D'Amore pci_regspec_t *assignp; 3025bdb9230aSGarrett D'Amore int assign_len; 3026bdb9230aSGarrett D'Amore int devnum; 3027bdb9230aSGarrett D'Amore 3028bdb9230aSGarrett D'Amore if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 3029bdb9230aSGarrett D'Amore "DNET_SROM", &proplen) == DDI_PROP_SUCCESS || 3030bdb9230aSGarrett D'Amore ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 3031bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS) 3032bdb9230aSGarrett D'Amore return; /* Already done! */ 3033bdb9230aSGarrett D'Amore 3034bdb9230aSGarrett D'Amore /* function return value ignored */ 3035bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, 3036bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len); 3037bdb9230aSGarrett D'Amore (void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo, 3038bdb9230aSGarrett D'Amore "DNET_HACK", "hack"); 3039bdb9230aSGarrett D'Amore 3040bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 3041bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp, 3042bdb9230aSGarrett D'Amore &assign_len)) == DDI_PROP_SUCCESS) { 3043bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi); 3044bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len); 3045bdb9230aSGarrett D'Amore /* function return value ignored */ 3046bdb9230aSGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, 3047bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_DEVNUM", devnum); 3048bdb9230aSGarrett D'Amore } 3049bdb9230aSGarrett D'Amore } 3050bdb9230aSGarrett D'Amore #endif 3051bdb9230aSGarrett D'Amore 3052bdb9230aSGarrett D'Amore /* 3053bdb9230aSGarrett D'Amore * ========== SROM Parsing Routines ========== 3054bdb9230aSGarrett D'Amore */ 3055bdb9230aSGarrett D'Amore 3056bdb9230aSGarrett D'Amore static int 3057bdb9230aSGarrett D'Amore check_srom_valid(uchar_t *vi) 3058bdb9230aSGarrett D'Amore { 3059bdb9230aSGarrett D'Amore int word, bit; 3060bdb9230aSGarrett D'Amore uint8_t crc; 3061bdb9230aSGarrett D'Amore uint16_t *wvi; /* word16 pointer to vendor info */ 3062bdb9230aSGarrett D'Amore uint16_t bitval; 3063bdb9230aSGarrett D'Amore 3064bdb9230aSGarrett D'Amore /* verify that the number of controllers on the card is within range */ 3065bdb9230aSGarrett D'Amore if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS) 3066bdb9230aSGarrett D'Amore return (0); 3067bdb9230aSGarrett D'Amore 3068bdb9230aSGarrett D'Amore /* 3069bdb9230aSGarrett D'Amore * version 1 and 3 of this card did not check the id block CRC value 3070bdb9230aSGarrett D'Amore * and this can't be changed without retesting every supported card 3071bdb9230aSGarrett D'Amore * 3072bdb9230aSGarrett D'Amore * however version 4 of the SROM can have this test applied 3073bdb9230aSGarrett D'Amore * without fear of breaking something that used to work. 3074bdb9230aSGarrett D'Amore * the CRC algorithm is taken from the Intel document 3075bdb9230aSGarrett D'Amore * "21x4 Serial ROM Format" 3076bdb9230aSGarrett D'Amore * version 4.09 3077bdb9230aSGarrett D'Amore * 3-Mar-1999 3078bdb9230aSGarrett D'Amore */ 3079bdb9230aSGarrett D'Amore 3080bdb9230aSGarrett D'Amore switch (vi[SROM_VERSION]) { 3081bdb9230aSGarrett D'Amore case 1: 3082bdb9230aSGarrett D'Amore /* fallthru */ 3083bdb9230aSGarrett D'Amore case 3: 3084bdb9230aSGarrett D'Amore return (vi[SROM_MBZ] == 0 && /* must be zero */ 3085bdb9230aSGarrett D'Amore vi[SROM_MBZ2] == 0 && /* must be zero */ 3086bdb9230aSGarrett D'Amore vi[SROM_MBZ3] == 0); /* must be zero */ 3087bdb9230aSGarrett D'Amore 3088bdb9230aSGarrett D'Amore case 4: 3089bdb9230aSGarrett D'Amore wvi = (uint16_t *)vi; 3090bdb9230aSGarrett D'Amore crc = 0xff; 3091bdb9230aSGarrett D'Amore for (word = 0; word < 9; word++) 3092bdb9230aSGarrett D'Amore for (bit = 15; bit >= 0; bit--) { 3093bdb9230aSGarrett D'Amore if (word == 8 && bit == 7) 3094bdb9230aSGarrett D'Amore return (crc == vi[16]); 3095bdb9230aSGarrett D'Amore bitval = 3096bdb9230aSGarrett D'Amore ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1); 3097bdb9230aSGarrett D'Amore crc <<= 1; 3098bdb9230aSGarrett D'Amore if (bitval == 1) { 3099bdb9230aSGarrett D'Amore crc ^= 7; 3100bdb9230aSGarrett D'Amore } 3101bdb9230aSGarrett D'Amore } 3102bdb9230aSGarrett D'Amore 3103bdb9230aSGarrett D'Amore default: 3104bdb9230aSGarrett D'Amore return (0); 3105bdb9230aSGarrett D'Amore } 3106bdb9230aSGarrett D'Amore } 3107bdb9230aSGarrett D'Amore 3108bdb9230aSGarrett D'Amore /* 3109bdb9230aSGarrett D'Amore * ========== Active Media Determination Routines ========== 3110bdb9230aSGarrett D'Amore */ 3111bdb9230aSGarrett D'Amore 3112bdb9230aSGarrett D'Amore /* This routine is also called for V3 Compact and extended type 0 SROMs */ 3113bdb9230aSGarrett D'Amore static int 3114bdb9230aSGarrett D'Amore is_fdmedia(int media) 3115bdb9230aSGarrett D'Amore { 3116bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD) 3117bdb9230aSGarrett D'Amore return (1); 3118bdb9230aSGarrett D'Amore else 3119bdb9230aSGarrett D'Amore return (0); 3120bdb9230aSGarrett D'Amore } 3121bdb9230aSGarrett D'Amore 3122bdb9230aSGarrett D'Amore /* 3123bdb9230aSGarrett D'Amore * "Linkset" is used to merge media that use the same link test check. So, 3124bdb9230aSGarrett D'Amore * if the TP link is added to the linkset, so is the TP Full duplex link. 3125bdb9230aSGarrett D'Amore * Used to avoid checking the same link status twice. 3126bdb9230aSGarrett D'Amore */ 3127bdb9230aSGarrett D'Amore static void 3128bdb9230aSGarrett D'Amore linkset_add(uint32_t *set, int media) 3129bdb9230aSGarrett D'Amore { 3130bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_TP) 3131bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP); 3132bdb9230aSGarrett D'Amore else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR) 3133bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR); 3134bdb9230aSGarrett D'Amore else *set |= 1UL<<media; 3135bdb9230aSGarrett D'Amore } 3136bdb9230aSGarrett D'Amore static int 3137bdb9230aSGarrett D'Amore linkset_isset(uint32_t linkset, int media) 3138bdb9230aSGarrett D'Amore { 3139bdb9230aSGarrett D'Amore return (((1UL<<media) & linkset) ? 1:0); 3140bdb9230aSGarrett D'Amore } 3141bdb9230aSGarrett D'Amore 3142bdb9230aSGarrett D'Amore /* 3143bdb9230aSGarrett D'Amore * The following code detects which Media is connected for 21041/21140 3144bdb9230aSGarrett D'Amore * Expect to change this code to support new 21140 variants. 3145bdb9230aSGarrett D'Amore * find_active_media() - called with intrlock held. 3146bdb9230aSGarrett D'Amore */ 3147bdb9230aSGarrett D'Amore static void 314898e8d175SSteven Stallion find_active_media(struct dnetinstance *dnetp) 3149bdb9230aSGarrett D'Amore { 3150bdb9230aSGarrett D'Amore int i; 3151bdb9230aSGarrett D'Amore media_block_t *block; 3152bdb9230aSGarrett D'Amore media_block_t *best_allowed = NULL; 3153bdb9230aSGarrett D'Amore media_block_t *hd_found = NULL; 3154bdb9230aSGarrett D'Amore media_block_t *fd_found = NULL; 3155bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf]; 3156bdb9230aSGarrett D'Amore uint32_t checked = 0, links_up = 0; 3157bdb9230aSGarrett D'Amore 3158bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 315998e8d175SSteven Stallion 3160bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block; 3161bdb9230aSGarrett D'Amore 3162bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1) { 3163bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block; 316498e8d175SSteven Stallion setup_block(dnetp); 3165bdb9230aSGarrett D'Amore 3166bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3167bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "portmon", 1)) { 3168bdb9230aSGarrett D'Amore /* XXX return value ignored */ 3169bdb9230aSGarrett D'Amore (void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb, 3170bdb9230aSGarrett D'Amore &dnetp->intrlock); 3171bdb9230aSGarrett D'Amore /* 3172bdb9230aSGarrett D'Amore * If the port monitor detects the link is already 3173bdb9230aSGarrett D'Amore * up, there is no point going through the rest of the 3174bdb9230aSGarrett D'Amore * link sense 3175bdb9230aSGarrett D'Amore */ 3176bdb9230aSGarrett D'Amore if (dnetp->mii_up) { 3177bdb9230aSGarrett D'Amore return; 3178bdb9230aSGarrett D'Amore } 3179bdb9230aSGarrett D'Amore } 3180bdb9230aSGarrett D'Amore } 3181bdb9230aSGarrett D'Amore 3182bdb9230aSGarrett D'Amore /* 3183bdb9230aSGarrett D'Amore * Media is searched for in order of Precedence. This DEC SROM spec 3184bdb9230aSGarrett D'Amore * tells us that the first media entry in the SROM is the lowest 3185bdb9230aSGarrett D'Amore * precedence and should be checked last. This is why we go to the last 3186bdb9230aSGarrett D'Amore * Media block and work back to the beginning. 3187bdb9230aSGarrett D'Amore * 3188bdb9230aSGarrett D'Amore * However, some older SROMs (Cogent EM110's etc.) have this the wrong 3189bdb9230aSGarrett D'Amore * way around. As a result, following the SROM spec would result in a 3190bdb9230aSGarrett D'Amore * 10 link being chosen over a 100 link if both media are available. 3191bdb9230aSGarrett D'Amore * So we continue trying the media until we have at least tried the 3192bdb9230aSGarrett D'Amore * DEFAULT media. 3193bdb9230aSGarrett D'Amore */ 3194bdb9230aSGarrett D'Amore 3195bdb9230aSGarrett D'Amore /* Search for an active medium, and select it */ 3196bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count - 1; 3197bdb9230aSGarrett D'Amore block >= leaf->block; block--) { 3198bdb9230aSGarrett D'Amore int media = block->media_code; 3199bdb9230aSGarrett D'Amore 3200bdb9230aSGarrett D'Amore /* User settings disallow selection of this block */ 3201bdb9230aSGarrett D'Amore if (dnetp->disallowed_media & (1UL<<media)) 3202bdb9230aSGarrett D'Amore continue; 3203bdb9230aSGarrett D'Amore 3204bdb9230aSGarrett D'Amore /* We may not be able to pick the default */ 3205bdb9230aSGarrett D'Amore if (best_allowed == NULL || block == leaf->default_block) 3206bdb9230aSGarrett D'Amore best_allowed = block; 3207bdb9230aSGarrett D'Amore #ifdef DEBUG 3208bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 3209bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Testing %s medium (block type %d)", 3210bdb9230aSGarrett D'Amore media_str[media], block->type); 3211bdb9230aSGarrett D'Amore #endif 3212bdb9230aSGarrett D'Amore 3213bdb9230aSGarrett D'Amore dnetp->selected_media_block = block; 3214bdb9230aSGarrett D'Amore switch (block->type) { 3215bdb9230aSGarrett D'Amore 3216bdb9230aSGarrett D'Amore case 2: /* SIA Media block: Best we can do is send a packet */ 321798e8d175SSteven Stallion setup_block(dnetp); 321898e8d175SSteven Stallion if (send_test_packet(dnetp)) { 3219bdb9230aSGarrett D'Amore if (!is_fdmedia(media)) 3220bdb9230aSGarrett D'Amore return; 3221bdb9230aSGarrett D'Amore if (!fd_found) 3222bdb9230aSGarrett D'Amore fd_found = block; 3223bdb9230aSGarrett D'Amore } 3224bdb9230aSGarrett D'Amore break; 3225bdb9230aSGarrett D'Amore 3226bdb9230aSGarrett D'Amore /* SYM/SCR or TP block: Use the link-sense bits */ 3227bdb9230aSGarrett D'Amore case 0: 3228bdb9230aSGarrett D'Amore if (!linkset_isset(checked, media)) { 3229bdb9230aSGarrett D'Amore linkset_add(&checked, media); 3230bdb9230aSGarrett D'Amore if (((media == MEDIA_BNC || 3231bdb9230aSGarrett D'Amore media == MEDIA_AUI) && 323298e8d175SSteven Stallion send_test_packet(dnetp)) || 323398e8d175SSteven Stallion dnet_link_sense(dnetp)) 3234bdb9230aSGarrett D'Amore linkset_add(&links_up, media); 3235bdb9230aSGarrett D'Amore } 3236bdb9230aSGarrett D'Amore 3237bdb9230aSGarrett D'Amore if (linkset_isset(links_up, media)) { 3238bdb9230aSGarrett D'Amore /* 3239bdb9230aSGarrett D'Amore * Half Duplex is *always* the favoured media. 3240bdb9230aSGarrett D'Amore * Full Duplex can be set and forced via the 3241bdb9230aSGarrett D'Amore * conf file. 3242bdb9230aSGarrett D'Amore */ 3243bdb9230aSGarrett D'Amore if (!is_fdmedia(media) && 3244bdb9230aSGarrett D'Amore dnetp->selected_media_block == 3245bdb9230aSGarrett D'Amore leaf->default_block) { 3246bdb9230aSGarrett D'Amore /* 3247bdb9230aSGarrett D'Amore * Cogent cards have the media in 3248bdb9230aSGarrett D'Amore * opposite order to the spec., 3249bdb9230aSGarrett D'Amore * this code forces the media test to 3250bdb9230aSGarrett D'Amore * keep going until the default media 3251bdb9230aSGarrett D'Amore * is tested. 3252bdb9230aSGarrett D'Amore * 3253bdb9230aSGarrett D'Amore * In Cogent case, 10, 10FD, 100FD, 100 3254bdb9230aSGarrett D'Amore * 100 is the default but 10 could have 3255bdb9230aSGarrett D'Amore * been detected and would have been 3256bdb9230aSGarrett D'Amore * chosen but now we force it through to 3257bdb9230aSGarrett D'Amore * 100. 3258bdb9230aSGarrett D'Amore */ 325998e8d175SSteven Stallion setup_block(dnetp); 3260bdb9230aSGarrett D'Amore return; 3261bdb9230aSGarrett D'Amore } else if (!is_fdmedia(media)) { 3262bdb9230aSGarrett D'Amore /* 3263bdb9230aSGarrett D'Amore * This allows all the others to work 3264bdb9230aSGarrett D'Amore * properly by remembering the media 3265bdb9230aSGarrett D'Amore * that works and not defaulting to 3266bdb9230aSGarrett D'Amore * a FD link. 3267bdb9230aSGarrett D'Amore */ 3268bdb9230aSGarrett D'Amore if (hd_found == NULL) 3269bdb9230aSGarrett D'Amore hd_found = block; 3270bdb9230aSGarrett D'Amore } else if (fd_found == NULL) { 3271bdb9230aSGarrett D'Amore /* 3272bdb9230aSGarrett D'Amore * No media have already been found 3273bdb9230aSGarrett D'Amore * so far, this is FD, it works so 3274bdb9230aSGarrett D'Amore * remember it and if no others are 3275bdb9230aSGarrett D'Amore * detected, use it. 3276bdb9230aSGarrett D'Amore */ 3277bdb9230aSGarrett D'Amore fd_found = block; 3278bdb9230aSGarrett D'Amore } 3279bdb9230aSGarrett D'Amore } 3280bdb9230aSGarrett D'Amore break; 3281bdb9230aSGarrett D'Amore 3282bdb9230aSGarrett D'Amore /* 3283bdb9230aSGarrett D'Amore * MII block: May take up to a second or so to settle if 3284bdb9230aSGarrett D'Amore * setup causes a PHY reset 3285bdb9230aSGarrett D'Amore */ 3286bdb9230aSGarrett D'Amore case 1: case 3: 328798e8d175SSteven Stallion setup_block(dnetp); 3288bdb9230aSGarrett D'Amore for (i = 0; ; i++) { 3289bdb9230aSGarrett D'Amore if (mii_linkup(dnetp->mii, dnetp->phyaddr)) { 3290bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 3291bdb9230aSGarrett D'Amore (void) mii_getspeed(dnetp->mii, 3292bdb9230aSGarrett D'Amore dnetp->phyaddr, 3293bdb9230aSGarrett D'Amore &dnetp->mii_speed, 3294bdb9230aSGarrett D'Amore &dnetp->mii_duplex); 3295bdb9230aSGarrett D'Amore dnetp->mii_up = 1; 3296bdb9230aSGarrett D'Amore leaf->mii_block = block; 3297bdb9230aSGarrett D'Amore return; 3298bdb9230aSGarrett D'Amore } 3299bdb9230aSGarrett D'Amore if (i == 10) 3300bdb9230aSGarrett D'Amore break; 3301bdb9230aSGarrett D'Amore delay(drv_usectohz(150000)); 3302bdb9230aSGarrett D'Amore } 3303bdb9230aSGarrett D'Amore dnetp->mii_up = 0; 3304bdb9230aSGarrett D'Amore break; 3305bdb9230aSGarrett D'Amore } 3306bdb9230aSGarrett D'Amore } /* for loop */ 3307bdb9230aSGarrett D'Amore if (hd_found) { 3308bdb9230aSGarrett D'Amore dnetp->selected_media_block = hd_found; 3309bdb9230aSGarrett D'Amore } else if (fd_found) { 3310bdb9230aSGarrett D'Amore dnetp->selected_media_block = fd_found; 3311bdb9230aSGarrett D'Amore } else { 3312bdb9230aSGarrett D'Amore if (best_allowed == NULL) 3313bdb9230aSGarrett D'Amore best_allowed = leaf->default_block; 3314bdb9230aSGarrett D'Amore dnetp->selected_media_block = best_allowed; 3315bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "!dnet: Default media selected\n"); 3316bdb9230aSGarrett D'Amore } 331798e8d175SSteven Stallion setup_block(dnetp); 3318bdb9230aSGarrett D'Amore } 3319bdb9230aSGarrett D'Amore 3320bdb9230aSGarrett D'Amore /* 3321bdb9230aSGarrett D'Amore * Do anything neccessary to select the selected_media_block. 3322bdb9230aSGarrett D'Amore * setup_block() - called with intrlock held. 3323bdb9230aSGarrett D'Amore */ 3324bdb9230aSGarrett D'Amore static void 332598e8d175SSteven Stallion setup_block(struct dnetinstance *dnetp) 3326bdb9230aSGarrett D'Amore { 332798e8d175SSteven Stallion dnet_reset_board(dnetp); 332898e8d175SSteven Stallion dnet_init_board(dnetp); 3329bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 333098e8d175SSteven Stallion (void) dnet_start(dnetp); 3331bdb9230aSGarrett D'Amore } 3332bdb9230aSGarrett D'Amore 3333bdb9230aSGarrett D'Amore /* dnet_link_sense() - called with intrlock held */ 3334bdb9230aSGarrett D'Amore static int 333598e8d175SSteven Stallion dnet_link_sense(struct dnetinstance *dnetp) 3336bdb9230aSGarrett D'Amore { 3337bdb9230aSGarrett D'Amore /* 3338bdb9230aSGarrett D'Amore * This routine makes use of the command word from the srom config. 3339bdb9230aSGarrett D'Amore * Details of the auto-sensing information contained in this can 3340bdb9230aSGarrett D'Amore * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03" 3341bdb9230aSGarrett D'Amore * spec. Section 4.3.2.1, and 4.5.2.1.3 3342bdb9230aSGarrett D'Amore */ 3343bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block; 3344bdb9230aSGarrett D'Amore uint32_t link, status, mask, polarity; 3345bdb9230aSGarrett D'Amore int settletime, stabletime, waittime, upsamples; 3346bdb9230aSGarrett D'Amore int delay_100, delay_10; 3347bdb9230aSGarrett D'Amore 3348bdb9230aSGarrett D'Amore 3349bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3350bdb9230aSGarrett D'Amore /* Don't autosense if the medium does not support it */ 3351bdb9230aSGarrett D'Amore if (block->command & (1 << 15)) { 3352bdb9230aSGarrett D'Amore /* This should be the default block */ 3353bdb9230aSGarrett D'Amore if (block->command & (1UL<<14)) 3354bdb9230aSGarrett D'Amore dnetp->sr.leaf[dnetp->leaf].default_block = block; 3355bdb9230aSGarrett D'Amore return (0); 3356bdb9230aSGarrett D'Amore } 3357bdb9230aSGarrett D'Amore 3358bdb9230aSGarrett D'Amore delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3359bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-100", 2000); 3360bdb9230aSGarrett D'Amore 3361bdb9230aSGarrett D'Amore delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3362bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-10", 400); 3363bdb9230aSGarrett D'Amore 3364bdb9230aSGarrett D'Amore /* 3365bdb9230aSGarrett D'Amore * Scrambler may need to be disabled for link sensing 3366bdb9230aSGarrett D'Amore * to work 3367bdb9230aSGarrett D'Amore */ 3368bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 1; 336998e8d175SSteven Stallion setup_block(dnetp); 3370bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 0; 3371bdb9230aSGarrett D'Amore 3372bdb9230aSGarrett D'Amore if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD) 3373bdb9230aSGarrett D'Amore settletime = delay_10; 3374bdb9230aSGarrett D'Amore else 3375bdb9230aSGarrett D'Amore settletime = delay_100; 3376bdb9230aSGarrett D'Amore stabletime = settletime / 4; 3377bdb9230aSGarrett D'Amore 3378bdb9230aSGarrett D'Amore mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1); 3379bdb9230aSGarrett D'Amore polarity = block->command & CMD_POL ? 0xffffffff : 0; 3380bdb9230aSGarrett D'Amore 3381bdb9230aSGarrett D'Amore for (waittime = 0, upsamples = 0; 3382bdb9230aSGarrett D'Amore waittime <= settletime + stabletime && upsamples < 8; 3383bdb9230aSGarrett D'Amore waittime += stabletime/8) { 3384bdb9230aSGarrett D'Amore delay(drv_usectohz(stabletime*1000 / 8)); 3385bdb9230aSGarrett D'Amore status = read_gpr(dnetp); 3386bdb9230aSGarrett D'Amore link = (status^polarity) & mask; 3387bdb9230aSGarrett D'Amore if (link) 3388bdb9230aSGarrett D'Amore upsamples++; 3389bdb9230aSGarrett D'Amore else 3390bdb9230aSGarrett D'Amore upsamples = 0; 3391bdb9230aSGarrett D'Amore } 3392bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 3393bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 3394bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x " 3395bdb9230aSGarrett D'Amore "mask:%x link:%x", 3396bdb9230aSGarrett D'Amore upsamples == 8 ? "UP":"DOWN", 3397bdb9230aSGarrett D'Amore upsamples, status, polarity, mask, link); 3398bdb9230aSGarrett D'Amore #endif 3399bdb9230aSGarrett D'Amore if (upsamples == 8) 3400bdb9230aSGarrett D'Amore return (1); 3401bdb9230aSGarrett D'Amore return (0); 3402bdb9230aSGarrett D'Amore } 3403bdb9230aSGarrett D'Amore 3404bdb9230aSGarrett D'Amore static int 340598e8d175SSteven Stallion send_test_packet(struct dnetinstance *dnetp) 3406bdb9230aSGarrett D'Amore { 3407bdb9230aSGarrett D'Amore int packet_delay; 3408bdb9230aSGarrett D'Amore struct tx_desc_type *desc; 3409bdb9230aSGarrett D'Amore int bufindex; 3410bdb9230aSGarrett D'Amore int media_code = dnetp->selected_media_block->media_code; 3411bdb9230aSGarrett D'Amore uint32_t del; 3412bdb9230aSGarrett D'Amore 3413bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3414bdb9230aSGarrett D'Amore /* 3415bdb9230aSGarrett D'Amore * For a successful test packet, the card must have settled into 3416bdb9230aSGarrett D'Amore * its current setting. Almost all cards we've tested manage to 3417bdb9230aSGarrett D'Amore * do this with all media within 50ms. However, the SMC 8432 3418bdb9230aSGarrett D'Amore * requires 300ms to settle into BNC mode. We now only do this 3419bdb9230aSGarrett D'Amore * from attach, and we do sleeping delay() instead of drv_usecwait() 3420bdb9230aSGarrett D'Amore * so we hope this .2 second delay won't cause too much suffering. 3421bdb9230aSGarrett D'Amore * ALSO: with an autonegotiating hub, an aditional 1 second delay is 3422bdb9230aSGarrett D'Amore * required. This is done if the media type is TP 3423bdb9230aSGarrett D'Amore */ 3424bdb9230aSGarrett D'Amore if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) { 3425bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3426bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000); 3427bdb9230aSGarrett D'Amore } else { 3428bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3429bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay", 300000); 3430bdb9230aSGarrett D'Amore } 3431bdb9230aSGarrett D'Amore delay(drv_usectohz(packet_delay)); 3432bdb9230aSGarrett D'Amore 3433bdb9230aSGarrett D'Amore desc = dnetp->tx_desc; 3434bdb9230aSGarrett D'Amore 3435bdb9230aSGarrett D'Amore bufindex = dnetp->tx_current_desc; 343698e8d175SSteven Stallion if (alloc_descriptor(dnetp) == FAILURE) { 3437bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor" 3438bdb9230aSGarrett D'Amore "failed"); 3439bdb9230aSGarrett D'Amore return (0); 3440bdb9230aSGarrett D'Amore } 3441bdb9230aSGarrett D'Amore 3442bdb9230aSGarrett D'Amore /* 3443bdb9230aSGarrett D'Amore * use setup buffer as the buffer for the test packet 3444bdb9230aSGarrett D'Amore * instead of allocating one. 3445bdb9230aSGarrett D'Amore */ 3446bdb9230aSGarrett D'Amore 3447bdb9230aSGarrett D'Amore ASSERT(dnetp->setup_buf_vaddr != NULL); 3448bdb9230aSGarrett D'Amore /* Put something decent in dest address so we don't annoy other cards */ 3449bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr, 3450bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL); 3451bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr, 3452bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL); 3453bdb9230aSGarrett D'Amore 3454bdb9230aSGarrett D'Amore desc[bufindex].buffer1 = dnetp->setup_buf_paddr; 3455bdb9230aSGarrett D'Amore desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE; 3456bdb9230aSGarrett D'Amore desc[bufindex].buffer2 = (uint32_t)(0); 3457bdb9230aSGarrett D'Amore desc[bufindex].desc1.first_desc = 1; 3458bdb9230aSGarrett D'Amore desc[bufindex].desc1.last_desc = 1; 3459bdb9230aSGarrett D'Amore desc[bufindex].desc1.int_on_comp = 1; 3460bdb9230aSGarrett D'Amore desc[bufindex].desc0.own = 1; 3461bdb9230aSGarrett D'Amore 3462bdb9230aSGarrett D'Amore ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG), 3463bdb9230aSGarrett D'Amore TX_POLL_DEMAND); 3464bdb9230aSGarrett D'Amore 3465bdb9230aSGarrett D'Amore /* 3466bdb9230aSGarrett D'Amore * Give enough time for the chip to transmit the packet 3467bdb9230aSGarrett D'Amore */ 3468bdb9230aSGarrett D'Amore #if 1 3469bdb9230aSGarrett D'Amore del = 1000; 3470bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del) 3471bdb9230aSGarrett D'Amore drv_usecwait(10); /* quickly wait up to 10ms */ 3472bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own) 3473bdb9230aSGarrett D'Amore delay(drv_usectohz(200000)); /* nicely wait a longer time */ 3474bdb9230aSGarrett D'Amore #else 3475bdb9230aSGarrett D'Amore del = 0x10000; 3476bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del) 3477bdb9230aSGarrett D'Amore drv_usecwait(10); 3478bdb9230aSGarrett D'Amore #endif 3479bdb9230aSGarrett D'Amore 3480bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 3481bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 3482bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u", 3483bdb9230aSGarrett D'Amore desc[bufindex].desc0.own, 3484bdb9230aSGarrett D'Amore desc[bufindex].desc0.err_summary, 3485bdb9230aSGarrett D'Amore desc[bufindex].desc0.carrier_loss, 3486bdb9230aSGarrett D'Amore desc[bufindex].desc0.no_carrier, 3487bdb9230aSGarrett D'Amore desc[bufindex].desc0.late_collision, 3488bdb9230aSGarrett D'Amore desc[bufindex].desc0.link_fail); 3489bdb9230aSGarrett D'Amore #endif 3490bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */ 3491bdb9230aSGarrett D'Amore return (0); 3492bdb9230aSGarrett D'Amore 3493bdb9230aSGarrett D'Amore return (!desc[bufindex].desc0.err_summary); 3494bdb9230aSGarrett D'Amore } 3495bdb9230aSGarrett D'Amore 3496bdb9230aSGarrett D'Amore /* enable_interrupts - called with intrlock held */ 3497bdb9230aSGarrett D'Amore static void 349898e8d175SSteven Stallion enable_interrupts(struct dnetinstance *dnetp) 3499bdb9230aSGarrett D'Amore { 3500bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3501bdb9230aSGarrett D'Amore /* Don't enable interrupts if they have been forced off */ 3502bdb9230aSGarrett D'Amore if (dnetp->interrupts_disabled) 3503bdb9230aSGarrett D'Amore return; 3504bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 350598e8d175SSteven Stallion ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK | 3506bdb9230aSGarrett D'Amore (dnetp->timer.cb ? GPTIMER_INTR : 0) | 350798e8d175SSteven Stallion RX_INTERRUPT_MASK | 350898e8d175SSteven Stallion TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK); 3509bdb9230aSGarrett D'Amore } 3510bdb9230aSGarrett D'Amore 3511bdb9230aSGarrett D'Amore /* 3512bdb9230aSGarrett D'Amore * Some older multiport cards are non-PCI compliant in their interrupt routing. 3513bdb9230aSGarrett D'Amore * Second and subsequent devices are incorrectly configured by the BIOS 3514bdb9230aSGarrett D'Amore * (either in their ILINE configuration or the MP Configuration Table for PC+MP 3515bdb9230aSGarrett D'Amore * systems). 351698e8d175SSteven Stallion * The hack stops registering the interrupt routine for the FIRST 351798e8d175SSteven Stallion * device on the adapter, and registers its own. It builds up a table 351898e8d175SSteven Stallion * of dnetp structures for each device, and the new interrupt routine 351998e8d175SSteven Stallion * calls dnet_intr for each of them. 3520bdb9230aSGarrett D'Amore * Known cards that suffer from this problem are: 3521bdb9230aSGarrett D'Amore * All Cogent multiport cards; 3522bdb9230aSGarrett D'Amore * Znyx 314; 3523bdb9230aSGarrett D'Amore * Znyx 315. 3524bdb9230aSGarrett D'Amore * 3525bdb9230aSGarrett D'Amore * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This 3526bdb9230aSGarrett D'Amore * hack relies on the fact that the offending cards will have only one SROM. 3527bdb9230aSGarrett D'Amore * It uses this fact to identify devices that are on the same multiport 3528bdb9230aSGarrett D'Amore * adapter, as opposed to multiple devices from the same vendor (as 3529bdb9230aSGarrett D'Amore * indicated by "secondary") 3530bdb9230aSGarrett D'Amore */ 3531bdb9230aSGarrett D'Amore static int 353298e8d175SSteven Stallion dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary) 3533bdb9230aSGarrett D'Amore { 3534bdb9230aSGarrett D'Amore int i; 3535bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf; 3536bdb9230aSGarrett D'Amore dev_info_t *devinfo = dnetp->devinfo; 3537bdb9230aSGarrett D'Amore uint32_t oui = 0; /* Organizationally Unique ID */ 3538bdb9230aSGarrett D'Amore 3539bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, 3540bdb9230aSGarrett D'Amore "no_INTA_workaround", 0) != 0) 3541bdb9230aSGarrett D'Amore return (0); 3542bdb9230aSGarrett D'Amore 3543bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++) 3544bdb9230aSGarrett D'Amore oui = (oui << 8) | dnetp->vendor_addr[i]; 3545bdb9230aSGarrett D'Amore 3546bdb9230aSGarrett D'Amore /* Check wheather or not we need to implement the hack */ 3547bdb9230aSGarrett D'Amore 3548bdb9230aSGarrett D'Amore switch (oui) { 3549bdb9230aSGarrett D'Amore case ZNYX_ETHER: 3550bdb9230aSGarrett D'Amore /* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */ 3551bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040) 3552bdb9230aSGarrett D'Amore return (0); 3553bdb9230aSGarrett D'Amore break; 3554bdb9230aSGarrett D'Amore 3555bdb9230aSGarrett D'Amore case COGENT_ETHER: 3556bdb9230aSGarrett D'Amore /* All known Cogent multiport cards */ 3557bdb9230aSGarrett D'Amore break; 3558bdb9230aSGarrett D'Amore 3559bdb9230aSGarrett D'Amore case ADAPTEC_ETHER: 3560bdb9230aSGarrett D'Amore /* Adaptec multiport cards */ 3561bdb9230aSGarrett D'Amore break; 3562bdb9230aSGarrett D'Amore 3563bdb9230aSGarrett D'Amore default: 3564bdb9230aSGarrett D'Amore /* Other cards work correctly */ 3565bdb9230aSGarrett D'Amore return (0); 3566bdb9230aSGarrett D'Amore } 3567bdb9230aSGarrett D'Amore 3568bdb9230aSGarrett D'Amore /* card is (probably) non-PCI compliant in its interrupt routing */ 3569bdb9230aSGarrett D'Amore 3570bdb9230aSGarrett D'Amore 3571bdb9230aSGarrett D'Amore if (!secondary) { 3572bdb9230aSGarrett D'Amore 3573bdb9230aSGarrett D'Amore /* 3574bdb9230aSGarrett D'Amore * If we have already registered a hacked interrupt, and 3575bdb9230aSGarrett D'Amore * this is also a 'primary' adapter, then this is NOT part of 3576bdb9230aSGarrett D'Amore * a multiport card, but a second card on the same PCI bus. 3577bdb9230aSGarrett D'Amore * BUGID: 4057747 3578bdb9230aSGarrett D'Amore */ 3579bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 3580bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0) != 0) 3581bdb9230aSGarrett D'Amore return (0); 3582bdb9230aSGarrett D'Amore /* ... Primary not part of a multiport device */ 3583bdb9230aSGarrett D'Amore 3584bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 3585bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE) 3586bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Implementing hardware " 3587bdb9230aSGarrett D'Amore "interrupt flaw workaround"); 3588bdb9230aSGarrett D'Amore #endif 3589bdb9230aSGarrett D'Amore dnetp->hackintr_inf = hackintr_inf = 3590bdb9230aSGarrett D'Amore kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP); 3591bdb9230aSGarrett D'Amore if (hackintr_inf == NULL) 3592bdb9230aSGarrett D'Amore goto fail; 3593bdb9230aSGarrett D'Amore 359498e8d175SSteven Stallion hackintr_inf->dnetps[0] = dnetp; 3595bdb9230aSGarrett D'Amore hackintr_inf->devinfo = devinfo; 3596bdb9230aSGarrett D'Amore 3597bdb9230aSGarrett D'Amore /* 3598bdb9230aSGarrett D'Amore * Add a property to allow successive attaches to find the 3599bdb9230aSGarrett D'Amore * table 3600bdb9230aSGarrett D'Amore */ 3601bdb9230aSGarrett D'Amore 3602bdb9230aSGarrett D'Amore if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, 3603bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), hackintr_propname, 3604bdb9230aSGarrett D'Amore (uchar_t *)&dnetp->hackintr_inf, 3605bdb9230aSGarrett D'Amore sizeof (void *)) != DDI_PROP_SUCCESS) 3606bdb9230aSGarrett D'Amore goto fail; 3607bdb9230aSGarrett D'Amore 3608bdb9230aSGarrett D'Amore 3609bdb9230aSGarrett D'Amore /* Register our hacked interrupt routine */ 361098e8d175SSteven Stallion if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL, 3611bdb9230aSGarrett D'Amore (uint_t (*)(char *))dnet_hack_intr, 3612bdb9230aSGarrett D'Amore (caddr_t)hackintr_inf) != DDI_SUCCESS) { 3613bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 3614bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, 3615bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), 3616bdb9230aSGarrett D'Amore hackintr_propname); 3617bdb9230aSGarrett D'Amore goto fail; 3618bdb9230aSGarrett D'Amore } 3619bdb9230aSGarrett D'Amore 3620bdb9230aSGarrett D'Amore /* 3621bdb9230aSGarrett D'Amore * Mutex required to ensure interrupt routine has completed 3622bdb9230aSGarrett D'Amore * when detaching devices 3623bdb9230aSGarrett D'Amore */ 3624bdb9230aSGarrett D'Amore mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER, 362598e8d175SSteven Stallion dnetp->icookie); 3626bdb9230aSGarrett D'Amore 3627bdb9230aSGarrett D'Amore /* Stop GLD registering an interrupt */ 3628bdb9230aSGarrett D'Amore return (-1); 3629bdb9230aSGarrett D'Amore } else { 3630bdb9230aSGarrett D'Amore 363198e8d175SSteven Stallion /* Add the dnetp for this secondary device to the table */ 3632bdb9230aSGarrett D'Amore 3633bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t) 3634bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 3635bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0); 3636bdb9230aSGarrett D'Amore 3637bdb9230aSGarrett D'Amore if (hackintr_inf == NULL) 3638bdb9230aSGarrett D'Amore goto fail; 3639bdb9230aSGarrett D'Amore 3640bdb9230aSGarrett D'Amore /* Find an empty slot */ 3641bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) 364298e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == NULL) 3643bdb9230aSGarrett D'Amore break; 3644bdb9230aSGarrett D'Amore 3645bdb9230aSGarrett D'Amore /* More than 8 ports on adapter ?! */ 3646bdb9230aSGarrett D'Amore if (i == MAX_INST) 3647bdb9230aSGarrett D'Amore goto fail; 3648bdb9230aSGarrett D'Amore 364998e8d175SSteven Stallion hackintr_inf->dnetps[i] = dnetp; 3650bdb9230aSGarrett D'Amore 3651bdb9230aSGarrett D'Amore /* 3652bdb9230aSGarrett D'Amore * Allow GLD to register a handler for this 3653bdb9230aSGarrett D'Amore * device. If the card is actually broken, as we suspect, this 3654bdb9230aSGarrett D'Amore * handler will never get called. However, by registering the 3655bdb9230aSGarrett D'Amore * interrupt handler, we can copy gracefully with new multiport 3656bdb9230aSGarrett D'Amore * Cogent cards that decide to fix the hardware problem 3657bdb9230aSGarrett D'Amore */ 3658bdb9230aSGarrett D'Amore return (0); 3659bdb9230aSGarrett D'Amore } 3660bdb9230aSGarrett D'Amore 3661bdb9230aSGarrett D'Amore fail: 3662bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt" 3663bdb9230aSGarrett D'Amore " routing problem"); 3664bdb9230aSGarrett D'Amore return (0); 3665bdb9230aSGarrett D'Amore } 3666bdb9230aSGarrett D'Amore 3667bdb9230aSGarrett D'Amore /* 366898e8d175SSteven Stallion * Call dnet_intr for all adapters on a multiport card 3669bdb9230aSGarrett D'Amore */ 3670bdb9230aSGarrett D'Amore static uint_t 3671bdb9230aSGarrett D'Amore dnet_hack_intr(struct hackintr_inf *hackintr_inf) 3672bdb9230aSGarrett D'Amore { 3673bdb9230aSGarrett D'Amore int i; 3674bdb9230aSGarrett D'Amore int claimed = DDI_INTR_UNCLAIMED; 3675bdb9230aSGarrett D'Amore 3676bdb9230aSGarrett D'Amore /* Stop detaches while processing interrupts */ 3677bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock); 3678bdb9230aSGarrett D'Amore 3679bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) { 368098e8d175SSteven Stallion if (hackintr_inf->dnetps[i] && 368198e8d175SSteven Stallion dnet_intr((caddr_t)hackintr_inf->dnetps[i]) == 368298e8d175SSteven Stallion DDI_INTR_CLAIMED) { 3683bdb9230aSGarrett D'Amore claimed = DDI_INTR_CLAIMED; 3684bdb9230aSGarrett D'Amore } 368598e8d175SSteven Stallion } 3686bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock); 3687bdb9230aSGarrett D'Amore return (claimed); 3688bdb9230aSGarrett D'Amore } 3689bdb9230aSGarrett D'Amore 3690bdb9230aSGarrett D'Amore /* 3691bdb9230aSGarrett D'Amore * This removes the detaching device from the table procesed by the hacked 3692bdb9230aSGarrett D'Amore * interrupt routine. Because the interrupts from all devices come in to the 3693bdb9230aSGarrett D'Amore * same interrupt handler, ALL devices must stop interrupting once the 3694bdb9230aSGarrett D'Amore * primary device detaches. This isn't a problem at present, because all 3695bdb9230aSGarrett D'Amore * instances of a device are detached when the driver is unloaded. 3696bdb9230aSGarrett D'Amore */ 3697bdb9230aSGarrett D'Amore static int 3698bdb9230aSGarrett D'Amore dnet_detach_hacked_interrupt(dev_info_t *devinfo) 3699bdb9230aSGarrett D'Amore { 3700bdb9230aSGarrett D'Amore int i; 3701bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf; 370298e8d175SSteven Stallion struct dnetinstance *altdnetp, *dnetp = 370398e8d175SSteven Stallion ddi_get_driver_private(devinfo); 3704bdb9230aSGarrett D'Amore 3705bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t) 3706bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo), 3707bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0); 3708bdb9230aSGarrett D'Amore 3709bdb9230aSGarrett D'Amore /* 3710bdb9230aSGarrett D'Amore * No hackintr_inf implies hack was not required or the primary has 3711bdb9230aSGarrett D'Amore * detached, and our interrupts are already disabled 3712bdb9230aSGarrett D'Amore */ 3713bdb9230aSGarrett D'Amore if (!hackintr_inf) { 3714bdb9230aSGarrett D'Amore /* remove the interrupt for the non-hacked case */ 371598e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie); 3716bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 3717bdb9230aSGarrett D'Amore } 3718bdb9230aSGarrett D'Amore 3719bdb9230aSGarrett D'Amore /* Remove this device from the handled table */ 3720bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock); 3721bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) { 372298e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == dnetp) { 372398e8d175SSteven Stallion hackintr_inf->dnetps[i] = NULL; 3724bdb9230aSGarrett D'Amore break; 3725bdb9230aSGarrett D'Amore } 3726bdb9230aSGarrett D'Amore } 3727bdb9230aSGarrett D'Amore 3728bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock); 3729bdb9230aSGarrett D'Amore 3730bdb9230aSGarrett D'Amore /* Not the primary card, we are done */ 3731bdb9230aSGarrett D'Amore if (devinfo != hackintr_inf->devinfo) 3732bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 3733bdb9230aSGarrett D'Amore 3734bdb9230aSGarrett D'Amore /* 3735bdb9230aSGarrett D'Amore * This is the primary card. All remaining adapters on this device 3736bdb9230aSGarrett D'Amore * must have their interrupts disabled before we remove the handler 3737bdb9230aSGarrett D'Amore */ 3738bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) { 373998e8d175SSteven Stallion if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) { 3740bdb9230aSGarrett D'Amore altdnetp->interrupts_disabled = 1; 3741bdb9230aSGarrett D'Amore ddi_put32(altdnetp->io_handle, 3742bdb9230aSGarrett D'Amore REG32(altdnetp->io_reg, INT_MASK_REG), 0); 3743bdb9230aSGarrett D'Amore } 3744bdb9230aSGarrett D'Amore } 3745bdb9230aSGarrett D'Amore 3746bdb9230aSGarrett D'Amore /* It should now be safe to remove the interrupt handler */ 3747bdb9230aSGarrett D'Amore 374898e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie); 3749bdb9230aSGarrett D'Amore mutex_destroy(&hackintr_inf->lock); 3750bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 3751bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo), 3752bdb9230aSGarrett D'Amore hackintr_propname); 3753bdb9230aSGarrett D'Amore kmem_free(hackintr_inf, sizeof (struct hackintr_inf)); 3754bdb9230aSGarrett D'Amore return (DDI_SUCCESS); 3755bdb9230aSGarrett D'Amore } 3756bdb9230aSGarrett D'Amore 3757bdb9230aSGarrett D'Amore /* do_phy() - called with intrlock held */ 3758bdb9230aSGarrett D'Amore static void 375998e8d175SSteven Stallion do_phy(struct dnetinstance *dnetp) 3760bdb9230aSGarrett D'Amore { 3761bdb9230aSGarrett D'Amore dev_info_t *dip; 3762bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf; 3763bdb9230aSGarrett D'Amore media_block_t *block; 3764bdb9230aSGarrett D'Amore int phy; 3765bdb9230aSGarrett D'Amore 3766bdb9230aSGarrett D'Amore dip = dnetp->devinfo; 3767bdb9230aSGarrett D'Amore 3768bdb9230aSGarrett D'Amore /* 3769bdb9230aSGarrett D'Amore * Find and configure the PHY media block. If NO PHY blocks are 3770bdb9230aSGarrett D'Amore * found on the SROM, but a PHY device is present, we assume the card 3771bdb9230aSGarrett D'Amore * is a legacy device, and that there is ONLY a PHY interface on the 3772bdb9230aSGarrett D'Amore * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY 3773bdb9230aSGarrett D'Amore */ 3774bdb9230aSGarrett D'Amore 3775bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count -1; 3776bdb9230aSGarrett D'Amore block >= leaf->block; block --) { 3777bdb9230aSGarrett D'Amore if (block->type == 3 || block->type == 1) { 3778bdb9230aSGarrett D'Amore leaf->mii_block = block; 3779bdb9230aSGarrett D'Amore break; 3780bdb9230aSGarrett D'Amore } 3781bdb9230aSGarrett D'Amore } 3782bdb9230aSGarrett D'Amore 3783bdb9230aSGarrett D'Amore /* 3784bdb9230aSGarrett D'Amore * If no MII block, select default, and hope this configuration will 3785bdb9230aSGarrett D'Amore * allow the phy to be read/written if it is present 3786bdb9230aSGarrett D'Amore */ 3787bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block ? 3788bdb9230aSGarrett D'Amore leaf->mii_block : leaf->default_block; 3789bdb9230aSGarrett D'Amore 379098e8d175SSteven Stallion setup_block(dnetp); 3791bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 3792bdb9230aSGarrett D'Amore (void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii); 3793bdb9230aSGarrett D'Amore 3794bdb9230aSGarrett D'Amore /* 3795bdb9230aSGarrett D'Amore * We try PHY 0 LAST because it is less likely to be connected 3796bdb9230aSGarrett D'Amore */ 3797bdb9230aSGarrett D'Amore for (phy = 1; phy < 33; phy++) 3798bdb9230aSGarrett D'Amore if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS && 3799bdb9230aSGarrett D'Amore mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) { 3800bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 3801bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 3802bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: " 3803bdb9230aSGarrett D'Amore "PHY at address %d", phy % 32); 3804bdb9230aSGarrett D'Amore #endif 3805bdb9230aSGarrett D'Amore dnetp->phyaddr = phy % 32; 3806bdb9230aSGarrett D'Amore if (!leaf->mii_block) { 3807bdb9230aSGarrett D'Amore /* Legacy card, change the leaf node */ 3808bdb9230aSGarrett D'Amore set_leaf(&dnetp->sr, &leaf_phylegacy); 3809bdb9230aSGarrett D'Amore } 3810bdb9230aSGarrett D'Amore return; 3811bdb9230aSGarrett D'Amore } 3812bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 3813bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE) 3814bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: No PHY found"); 3815bdb9230aSGarrett D'Amore #endif 3816bdb9230aSGarrett D'Amore } 3817bdb9230aSGarrett D'Amore 3818bdb9230aSGarrett D'Amore static ushort_t 3819bdb9230aSGarrett D'Amore dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num) 3820bdb9230aSGarrett D'Amore { 3821bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; 3822bdb9230aSGarrett D'Amore 3823bdb9230aSGarrett D'Amore uint32_t command_word; 3824bdb9230aSGarrett D'Amore uint32_t tmp; 3825bdb9230aSGarrett D'Amore uint32_t data = 0; 3826bdb9230aSGarrett D'Amore int i; 3827bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8); 3828bdb9230aSGarrett D'Amore int turned_around = 0; 3829bdb9230aSGarrett D'Amore 383098e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip); 3831bdb9230aSGarrett D'Amore 3832bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3833bdb9230aSGarrett D'Amore /* Write Preamble */ 3834bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort); 3835bdb9230aSGarrett D'Amore 3836bdb9230aSGarrett D'Amore /* Prepare command word */ 3837bdb9230aSGarrett D'Amore command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN; 3838bdb9230aSGarrett D'Amore command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN; 3839bdb9230aSGarrett D'Amore command_word |= MII_READ_FRAME; 3840bdb9230aSGarrett D'Amore 3841bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, bits_in_ushort-2); 3842bdb9230aSGarrett D'Amore 3843bdb9230aSGarrett D'Amore mii_tristate(dnetp); 3844bdb9230aSGarrett D'Amore 3845bdb9230aSGarrett D'Amore /* Check that the PHY generated a zero bit the 2nd clock */ 3846bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG)); 3847bdb9230aSGarrett D'Amore 3848bdb9230aSGarrett D'Amore turned_around = (tmp & MII_DATA_IN) ? 0 : 1; 3849bdb9230aSGarrett D'Amore 3850bdb9230aSGarrett D'Amore /* read data WORD */ 3851bdb9230aSGarrett D'Amore for (i = 0; i < bits_in_ushort; i++) { 3852bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 3853bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ); 3854bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3855bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 3856bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK); 3857bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3858bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle, 3859bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG)); 3860bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3861bdb9230aSGarrett D'Amore data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001; 3862bdb9230aSGarrett D'Amore } 3863bdb9230aSGarrett D'Amore 3864bdb9230aSGarrett D'Amore mii_tristate(dnetp); 3865bdb9230aSGarrett D'Amore return (turned_around ? data: -1); 3866bdb9230aSGarrett D'Amore } 3867bdb9230aSGarrett D'Amore 3868bdb9230aSGarrett D'Amore static void 3869bdb9230aSGarrett D'Amore dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat) 3870bdb9230aSGarrett D'Amore { 3871bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; 3872bdb9230aSGarrett D'Amore uint32_t command_word; 3873bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8); 3874bdb9230aSGarrett D'Amore 387598e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip); 3876bdb9230aSGarrett D'Amore 3877bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3878bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort); 3879bdb9230aSGarrett D'Amore 3880bdb9230aSGarrett D'Amore /* Prepare command word */ 3881bdb9230aSGarrett D'Amore command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN); 3882bdb9230aSGarrett D'Amore command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN); 3883bdb9230aSGarrett D'Amore command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat); 3884bdb9230aSGarrett D'Amore 3885bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, 2*bits_in_ushort); 3886bdb9230aSGarrett D'Amore mii_tristate(dnetp); 3887bdb9230aSGarrett D'Amore } 3888bdb9230aSGarrett D'Amore 3889bdb9230aSGarrett D'Amore /* 3890bdb9230aSGarrett D'Amore * Write data size bits from mii_data to the MII control lines. 3891bdb9230aSGarrett D'Amore */ 3892bdb9230aSGarrett D'Amore static void 3893bdb9230aSGarrett D'Amore write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size) 3894bdb9230aSGarrett D'Amore { 3895bdb9230aSGarrett D'Amore int i; 3896bdb9230aSGarrett D'Amore uint32_t dbit; 3897bdb9230aSGarrett D'Amore 3898bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3899bdb9230aSGarrett D'Amore for (i = data_size; i > 0; i--) { 3900bdb9230aSGarrett D'Amore dbit = ((mii_data >> 3901bdb9230aSGarrett D'Amore (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA); 3902bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 3903bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), 3904bdb9230aSGarrett D'Amore MII_WRITE | dbit); 3905bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3906bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, 3907bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), 3908bdb9230aSGarrett D'Amore MII_WRITE | MII_CLOCK | dbit); 3909bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3910bdb9230aSGarrett D'Amore mii_data <<= 1; 3911bdb9230aSGarrett D'Amore } 3912bdb9230aSGarrett D'Amore } 3913bdb9230aSGarrett D'Amore 3914bdb9230aSGarrett D'Amore /* 3915bdb9230aSGarrett D'Amore * Put the MDIO port in tri-state for the turn around bits 3916bdb9230aSGarrett D'Amore * in MII read and at end of MII management sequence. 3917bdb9230aSGarrett D'Amore */ 3918bdb9230aSGarrett D'Amore static void 3919bdb9230aSGarrett D'Amore mii_tristate(struct dnetinstance *dnetp) 3920bdb9230aSGarrett D'Amore { 3921bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 3922bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG), 3923bdb9230aSGarrett D'Amore MII_WRITE_TS); 3924bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3925bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG), 3926bdb9230aSGarrett D'Amore MII_WRITE_TS | MII_CLOCK); 3927bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY); 3928bdb9230aSGarrett D'Amore } 3929bdb9230aSGarrett D'Amore 3930bdb9230aSGarrett D'Amore 3931bdb9230aSGarrett D'Amore static void 3932bdb9230aSGarrett D'Amore set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf) 3933bdb9230aSGarrett D'Amore { 3934bdb9230aSGarrett D'Amore if (sr->leaf && !sr->leaf->is_static) 3935bdb9230aSGarrett D'Amore kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT)); 3936bdb9230aSGarrett D'Amore sr->leaf = leaf; 3937bdb9230aSGarrett D'Amore } 3938bdb9230aSGarrett D'Amore 3939bdb9230aSGarrett D'Amore /* 3940bdb9230aSGarrett D'Amore * Callback from MII module. Makes sure that the CSR registers are 3941bdb9230aSGarrett D'Amore * configured properly if the PHY changes mode. 3942bdb9230aSGarrett D'Amore */ 3943bdb9230aSGarrett D'Amore /* ARGSUSED */ 3944bdb9230aSGarrett D'Amore /* dnet_mii_link_cb - called with intrlock held */ 3945bdb9230aSGarrett D'Amore static void 3946bdb9230aSGarrett D'Amore dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state) 3947bdb9230aSGarrett D'Amore { 394898e8d175SSteven Stallion struct dnetinstance *dnetp = ddi_get_driver_private(dip); 3949bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf; 3950bdb9230aSGarrett D'Amore 3951bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock)); 395298e8d175SSteven Stallion 3953bdb9230aSGarrett D'Amore leaf = dnetp->sr.leaf + dnetp->leaf; 3954bdb9230aSGarrett D'Amore if (state == phy_state_linkup) { 3955bdb9230aSGarrett D'Amore dnetp->mii_up = 1; 395698e8d175SSteven Stallion 395798e8d175SSteven Stallion (void) mii_getspeed(dnetp->mii, dnetp->phyaddr, 395898e8d175SSteven Stallion &dnetp->mii_speed, &dnetp->mii_duplex); 395998e8d175SSteven Stallion 3960bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block; 396198e8d175SSteven Stallion setup_block(dnetp); 3962bdb9230aSGarrett D'Amore } else { 3963bdb9230aSGarrett D'Amore /* NEEDSWORK: Probably can call find_active_media here */ 3964bdb9230aSGarrett D'Amore dnetp->mii_up = 0; 396598e8d175SSteven Stallion 3966bdb9230aSGarrett D'Amore if (leaf->default_block->media_code == MEDIA_MII) 3967bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block; 396898e8d175SSteven Stallion setup_block(dnetp); 396998e8d175SSteven Stallion } 397098e8d175SSteven Stallion 397132607e28SSteven Stallion if (dnetp->running) { 397232607e28SSteven Stallion mac_link_update(dnetp->mac_handle, 397332607e28SSteven Stallion (dnetp->mii_up ? LINK_STATE_UP : LINK_STATE_DOWN)); 3974bdb9230aSGarrett D'Amore } 3975bdb9230aSGarrett D'Amore } 3976bdb9230aSGarrett D'Amore 3977bdb9230aSGarrett D'Amore /* 3978bdb9230aSGarrett D'Amore * SROM parsing routines. 3979bdb9230aSGarrett D'Amore * Refer to the Digital 3.03 SROM spec while reading this! (references refer 3980bdb9230aSGarrett D'Amore * to this document) 3981bdb9230aSGarrett D'Amore * Where possible ALL vendor specific changes should be localised here. The 3982bdb9230aSGarrett D'Amore * SROM data should be capable of describing any programmatic irregularities 3983bdb9230aSGarrett D'Amore * of DNET cards (via SIA or GP registers, in particular), so vendor specific 3984bdb9230aSGarrett D'Amore * code elsewhere should not be required 3985bdb9230aSGarrett D'Amore */ 3986bdb9230aSGarrett D'Amore static void 3987bdb9230aSGarrett D'Amore dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi) 3988bdb9230aSGarrett D'Amore { 3989bdb9230aSGarrett D'Amore uint32_t ether_mfg = 0; 3990bdb9230aSGarrett D'Amore int i; 3991bdb9230aSGarrett D'Amore uchar_t *p; 3992bdb9230aSGarrett D'Amore 3993bdb9230aSGarrett D'Amore if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 3994bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "no_sromconfig", 0)) 3995bdb9230aSGarrett D'Amore dnetp->sr.init_from_srom = check_srom_valid(vi); 3996bdb9230aSGarrett D'Amore 3997bdb9230aSGarrett D'Amore if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) { 3998bdb9230aSGarrett D'Amore /* Section 2/3: General SROM Format/ ID Block */ 3999bdb9230aSGarrett D'Amore p = vi+18; 4000bdb9230aSGarrett D'Amore sr->version = *p++; 4001bdb9230aSGarrett D'Amore sr->adapters = *p++; 4002bdb9230aSGarrett D'Amore 4003bdb9230aSGarrett D'Amore sr->leaf = 4004bdb9230aSGarrett D'Amore kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP); 4005bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++) 4006bdb9230aSGarrett D'Amore sr->netaddr[i] = *p++; 4007bdb9230aSGarrett D'Amore 4008bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++) { 4009bdb9230aSGarrett D'Amore uchar_t devno = *p++; 4010bdb9230aSGarrett D'Amore uint16_t offset = *p++; 4011bdb9230aSGarrett D'Amore offset |= *p++ << 8; 4012bdb9230aSGarrett D'Amore sr->leaf[i].device_number = devno; 4013bdb9230aSGarrett D'Amore parse_controller_leaf(dnetp, sr->leaf+i, vi+offset); 4014bdb9230aSGarrett D'Amore } 4015bdb9230aSGarrett D'Amore /* 4016bdb9230aSGarrett D'Amore * 'Orrible hack for cogent cards. The 6911A board seems to 4017bdb9230aSGarrett D'Amore * have an incorrect SROM. (From the OEMDEMO program 4018bdb9230aSGarrett D'Amore * supplied by cogent, it seems that the ROM matches a setup 4019bdb9230aSGarrett D'Amore * or a board with a QSI or ICS PHY. 4020bdb9230aSGarrett D'Amore */ 4021bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++) 4022bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | sr->netaddr[i]; 4023bdb9230aSGarrett D'Amore 4024bdb9230aSGarrett D'Amore if (ether_mfg == ADAPTEC_ETHER) { 4025bdb9230aSGarrett D'Amore static uint16_t cogent_gprseq[] = {0x821, 0}; 4026bdb9230aSGarrett D'Amore switch (vi[COGENT_SROM_ID]) { 4027bdb9230aSGarrett D'Amore case COGENT_ANA6911A_C: 4028bdb9230aSGarrett D'Amore case COGENT_ANA6911AC_C: 4029bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 4030bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE) 4031bdb9230aSGarrett D'Amore cmn_err(CE_WARN, 4032bdb9230aSGarrett D'Amore "Suspected bad GPR sequence." 4033bdb9230aSGarrett D'Amore " Making a guess (821,0)"); 4034bdb9230aSGarrett D'Amore #endif 4035bdb9230aSGarrett D'Amore 4036bdb9230aSGarrett D'Amore /* XXX function return value ignored */ 4037bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array( 4038bdb9230aSGarrett D'Amore DDI_DEV_T_NONE, dnetp->devinfo, 4039bdb9230aSGarrett D'Amore "gpr-sequence", (uchar_t *)cogent_gprseq, 4040bdb9230aSGarrett D'Amore sizeof (cogent_gprseq)); 4041bdb9230aSGarrett D'Amore break; 4042bdb9230aSGarrett D'Amore } 4043bdb9230aSGarrett D'Amore } 4044bdb9230aSGarrett D'Amore } else { 4045bdb9230aSGarrett D'Amore /* 4046bdb9230aSGarrett D'Amore * Adhoc SROM, check for some cards which need special handling 4047bdb9230aSGarrett D'Amore * Assume vendor info contains ether address in first six bytes 4048bdb9230aSGarrett D'Amore */ 4049bdb9230aSGarrett D'Amore 4050bdb9230aSGarrett D'Amore uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo, 4051bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0); 4052bdb9230aSGarrett D'Amore 4053bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++) 4054bdb9230aSGarrett D'Amore sr->netaddr[i] = mac[i]; 4055bdb9230aSGarrett D'Amore 4056bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) { 4057bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++) 4058bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | mac[i]; 4059bdb9230aSGarrett D'Amore 4060bdb9230aSGarrett D'Amore switch (ether_mfg) { 4061bdb9230aSGarrett D'Amore case ASANTE_ETHER: 4062bdb9230aSGarrett D'Amore dnetp->vendor_21140 = ASANTE_TYPE; 4063bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0; 4064bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_asante); 4065bdb9230aSGarrett D'Amore sr->adapters = 1; 4066bdb9230aSGarrett D'Amore break; 4067bdb9230aSGarrett D'Amore 4068bdb9230aSGarrett D'Amore case COGENT_ETHER: 4069bdb9230aSGarrett D'Amore case ADAPTEC_ETHER: 4070bdb9230aSGarrett D'Amore dnetp->vendor_21140 = COGENT_EM_TYPE; 4071bdb9230aSGarrett D'Amore dnetp->vendor_revision = 4072bdb9230aSGarrett D'Amore vi[VENDOR_REVISION_OFFSET]; 4073bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_cogent_100); 4074bdb9230aSGarrett D'Amore sr->adapters = 1; 4075bdb9230aSGarrett D'Amore break; 4076bdb9230aSGarrett D'Amore 4077bdb9230aSGarrett D'Amore default: 4078bdb9230aSGarrett D'Amore dnetp->vendor_21140 = DEFAULT_TYPE; 4079bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0; 4080bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_default_100); 4081bdb9230aSGarrett D'Amore sr->adapters = 1; 4082bdb9230aSGarrett D'Amore break; 4083bdb9230aSGarrett D'Amore } 4084bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21041) { 4085bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21041); 4086bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21040) { 4087bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21040); 4088bdb9230aSGarrett D'Amore } 4089bdb9230aSGarrett D'Amore } 4090bdb9230aSGarrett D'Amore } 4091bdb9230aSGarrett D'Amore 4092bdb9230aSGarrett D'Amore /* Section 4.2, 4.3, 4.4, 4.5 */ 4093bdb9230aSGarrett D'Amore static void 4094bdb9230aSGarrett D'Amore parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf, 4095bdb9230aSGarrett D'Amore uchar_t *vi) 4096bdb9230aSGarrett D'Amore { 4097bdb9230aSGarrett D'Amore int i; 4098bdb9230aSGarrett D'Amore 4099bdb9230aSGarrett D'Amore leaf->selected_contype = *vi++; 4100bdb9230aSGarrett D'Amore leaf->selected_contype |= *vi++ << 8; 4101bdb9230aSGarrett D'Amore 4102bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */ 4103bdb9230aSGarrett D'Amore leaf->gpr = *vi++; 4104bdb9230aSGarrett D'Amore 4105bdb9230aSGarrett D'Amore leaf->block_count = *vi++; 4106bdb9230aSGarrett D'Amore 4107bdb9230aSGarrett D'Amore if (leaf->block_count > MAX_MEDIA) { 4108bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Too many media in SROM!"); 4109bdb9230aSGarrett D'Amore leaf->block_count = 1; 4110bdb9230aSGarrett D'Amore } 4111bdb9230aSGarrett D'Amore for (i = 0; i <= leaf->block_count; i++) { 4112bdb9230aSGarrett D'Amore vi = parse_media_block(dnetp, leaf->block + i, vi); 4113bdb9230aSGarrett D'Amore if (leaf->block[i].command & CMD_DEFAULT_MEDIUM) 4114bdb9230aSGarrett D'Amore leaf->default_block = leaf->block+i; 4115bdb9230aSGarrett D'Amore } 4116bdb9230aSGarrett D'Amore /* No explicit default block: use last in the ROM */ 4117bdb9230aSGarrett D'Amore if (leaf->default_block == NULL) 4118bdb9230aSGarrett D'Amore leaf->default_block = leaf->block + leaf->block_count -1; 4119bdb9230aSGarrett D'Amore 4120bdb9230aSGarrett D'Amore } 4121bdb9230aSGarrett D'Amore 4122bdb9230aSGarrett D'Amore static uchar_t * 4123bdb9230aSGarrett D'Amore parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi) 4124bdb9230aSGarrett D'Amore { 4125bdb9230aSGarrett D'Amore int i; 4126bdb9230aSGarrett D'Amore 4127bdb9230aSGarrett D'Amore /* 4128bdb9230aSGarrett D'Amore * There are three kinds of media block we need to worry about: 4129bdb9230aSGarrett D'Amore * The 21041 blocks. 4130bdb9230aSGarrett D'Amore * 21140 blocks from a version 1 SROM 4131bdb9230aSGarrett D'Amore * 2114[023] block from a version 3 SROM 4132bdb9230aSGarrett D'Amore */ 4133bdb9230aSGarrett D'Amore 4134bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21041) { 4135bdb9230aSGarrett D'Amore /* Section 4.2 */ 4136bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f; 4137bdb9230aSGarrett D'Amore block->type = 2; 4138bdb9230aSGarrett D'Amore if (*vi++ & 0x40) { 4139bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++; 4140bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8; 4141bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++; 4142bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8; 4143bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++; 4144bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8; 4145bdb9230aSGarrett D'Amore } else { 4146bdb9230aSGarrett D'Amore /* No media data (csrs 13,14,15). Insert defaults */ 4147bdb9230aSGarrett D'Amore switch (block->media_code) { 4148bdb9230aSGarrett D'Amore case MEDIA_TP: 4149bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01; 4150bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f; 4151bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4152bdb9230aSGarrett D'Amore break; 4153bdb9230aSGarrett D'Amore case MEDIA_TP_FD: 4154bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01; 4155bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d; 4156bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4157bdb9230aSGarrett D'Amore break; 4158bdb9230aSGarrett D'Amore case MEDIA_BNC: 4159bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09; 4160bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4161bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006; 4162bdb9230aSGarrett D'Amore break; 4163bdb9230aSGarrett D'Amore case MEDIA_AUI: 4164bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09; 4165bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4166bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e; 4167bdb9230aSGarrett D'Amore break; 4168bdb9230aSGarrett D'Amore } 4169bdb9230aSGarrett D'Amore } 4170bdb9230aSGarrett D'Amore } else if (*vi & 0x80) { /* Extended format: Section 4.3.2.2 */ 4171bdb9230aSGarrett D'Amore int blocklen = *vi++ & 0x7f; 4172bdb9230aSGarrett D'Amore block->type = *vi++; 4173bdb9230aSGarrett D'Amore switch (block->type) { 4174bdb9230aSGarrett D'Amore case 0: /* "non-MII": Section 4.3.2.2.1 */ 4175bdb9230aSGarrett D'Amore block->media_code = (*vi++) & 0x3f; 4176bdb9230aSGarrett D'Amore block->gprseqlen = 1; 4177bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++; 4178bdb9230aSGarrett D'Amore block->command = *vi++; 4179bdb9230aSGarrett D'Amore block->command |= *vi++ << 8; 4180bdb9230aSGarrett D'Amore break; 4181bdb9230aSGarrett D'Amore 4182bdb9230aSGarrett D'Amore case 1: /* MII/PHY: Section 4.3.2.2.2 */ 4183bdb9230aSGarrett D'Amore block->command = CMD_PS; 4184bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII; 4185bdb9230aSGarrett D'Amore /* This is whats needed in CSR6 */ 4186bdb9230aSGarrett D'Amore 4187bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++; 4188bdb9230aSGarrett D'Amore block->gprseqlen = *vi++; 4189bdb9230aSGarrett D'Amore 4190bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++) 4191bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++; 4192bdb9230aSGarrett D'Amore block->rstseqlen = *vi++; 4193bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) 4194bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++; 4195bdb9230aSGarrett D'Amore 4196bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++; 4197bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8; 4198bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++; 4199bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8; 4200bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++; 4201bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8; 4202bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++; 4203bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8; 4204bdb9230aSGarrett D'Amore break; 4205bdb9230aSGarrett D'Amore 4206bdb9230aSGarrett D'Amore case 2: /* SIA Media: Section 4.4.2.1.1 */ 4207bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f; 4208bdb9230aSGarrett D'Amore if (*vi++ & 0x40) { 4209bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++; 4210bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8; 4211bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++; 4212bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8; 4213bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++; 4214bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8; 4215bdb9230aSGarrett D'Amore } else { 4216bdb9230aSGarrett D'Amore /* 4217bdb9230aSGarrett D'Amore * SIA values not provided by SROM; provide 4218bdb9230aSGarrett D'Amore * defaults. See appendix D of 2114[23] manuals. 4219bdb9230aSGarrett D'Amore */ 4220bdb9230aSGarrett D'Amore switch (block->media_code) { 4221bdb9230aSGarrett D'Amore case MEDIA_BNC: 4222bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009; 4223bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4224bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000; 4225bdb9230aSGarrett D'Amore break; 4226bdb9230aSGarrett D'Amore case MEDIA_AUI: 4227bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009; 4228bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4229bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4230bdb9230aSGarrett D'Amore break; 4231bdb9230aSGarrett D'Amore case MEDIA_TP: 4232bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001; 4233bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f; 4234bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000; 4235bdb9230aSGarrett D'Amore break; 4236bdb9230aSGarrett D'Amore case MEDIA_TP_FD: 4237bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001; 4238bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d; 4239bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000; 4240bdb9230aSGarrett D'Amore break; 4241bdb9230aSGarrett D'Amore default: 4242bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0000; 4243bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0000; 4244bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000; 4245bdb9230aSGarrett D'Amore } 4246bdb9230aSGarrett D'Amore } 4247bdb9230aSGarrett D'Amore 4248bdb9230aSGarrett D'Amore /* Treat GP control/data as a GPR sequence */ 4249bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4250bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++; 4251bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8; 4252bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE; 4253bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++; 4254bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8; 4255bdb9230aSGarrett D'Amore break; 4256bdb9230aSGarrett D'Amore 4257bdb9230aSGarrett D'Amore case 3: /* MII/PHY : Section 4.4.2.1.2 */ 4258bdb9230aSGarrett D'Amore block->command = CMD_PS; 4259bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII; 4260bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++; 4261bdb9230aSGarrett D'Amore 4262bdb9230aSGarrett D'Amore block->gprseqlen = *vi++; 4263bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++) { 4264bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++; 4265bdb9230aSGarrett D'Amore block->gprseq[i] |= *vi++ << 8; 4266bdb9230aSGarrett D'Amore } 4267bdb9230aSGarrett D'Amore 4268bdb9230aSGarrett D'Amore block->rstseqlen = *vi++; 4269bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) { 4270bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++; 4271bdb9230aSGarrett D'Amore block->rstseq[i] |= *vi++ << 8; 4272bdb9230aSGarrett D'Amore } 4273bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++; 4274bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8; 4275bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++; 4276bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8; 4277bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++; 4278bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8; 4279bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++; 4280bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8; 4281bdb9230aSGarrett D'Amore block->un.mii.miiintr |= *vi++; 4282bdb9230aSGarrett D'Amore break; 4283bdb9230aSGarrett D'Amore 4284bdb9230aSGarrett D'Amore case 4: /* SYM Media: 4.5.2.1.3 */ 4285bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f; 4286bdb9230aSGarrett D'Amore /* Treat GP control and data as a GPR sequence */ 4287bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4288bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++; 4289bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8; 4290bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE; 4291bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++; 4292bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8; 4293bdb9230aSGarrett D'Amore block->command = *vi++; 4294bdb9230aSGarrett D'Amore block->command |= *vi++ << 8; 4295bdb9230aSGarrett D'Amore break; 4296bdb9230aSGarrett D'Amore 4297bdb9230aSGarrett D'Amore case 5: /* GPR reset sequence: Section 4.5.2.1.4 */ 4298bdb9230aSGarrett D'Amore block->rstseqlen = *vi++; 4299bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) 4300bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++; 4301bdb9230aSGarrett D'Amore break; 4302bdb9230aSGarrett D'Amore 4303bdb9230aSGarrett D'Amore default: /* Unknown media block. Skip it. */ 4304bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Unsupported SROM block."); 4305bdb9230aSGarrett D'Amore vi += blocklen; 4306bdb9230aSGarrett D'Amore break; 4307bdb9230aSGarrett D'Amore } 4308bdb9230aSGarrett D'Amore } else { /* Compact format (or V1 SROM): Section 4.3.2.1 */ 4309bdb9230aSGarrett D'Amore block->type = 0; 4310bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f; 4311bdb9230aSGarrett D'Amore block->gprseqlen = 1; 4312bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++; 4313bdb9230aSGarrett D'Amore block->command = *vi++; 4314bdb9230aSGarrett D'Amore block->command |= (*vi++) << 8; 4315bdb9230aSGarrett D'Amore } 4316bdb9230aSGarrett D'Amore return (vi); 4317bdb9230aSGarrett D'Amore } 4318bdb9230aSGarrett D'Amore 4319bdb9230aSGarrett D'Amore 4320bdb9230aSGarrett D'Amore /* 4321bdb9230aSGarrett D'Amore * An alternative to doing this would be to store the legacy ROMs in binary 4322bdb9230aSGarrett D'Amore * format in the conf file, and in read_srom, pick out the data. This would 4323bdb9230aSGarrett D'Amore * then allow the parser to continue on as normal. This makes it a little 4324bdb9230aSGarrett D'Amore * easier to read. 4325bdb9230aSGarrett D'Amore */ 4326bdb9230aSGarrett D'Amore static void 4327bdb9230aSGarrett D'Amore setup_legacy_blocks() 4328bdb9230aSGarrett D'Amore { 4329bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf; 4330bdb9230aSGarrett D'Amore media_block_t *block; 4331bdb9230aSGarrett D'Amore 4332bdb9230aSGarrett D'Amore /* Default FAKE SROM */ 4333bdb9230aSGarrett D'Amore leaf = &leaf_default_100; 4334bdb9230aSGarrett D'Amore leaf->is_static = 1; 4335bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3]; 4336bdb9230aSGarrett D'Amore leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */ 4337bdb9230aSGarrett D'Amore block = leaf->block; 4338bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD; 4339bdb9230aSGarrett D'Amore block->type = 0; 4340bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 4341bdb9230aSGarrett D'Amore block++; 4342bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP; 4343bdb9230aSGarrett D'Amore block->type = 0; 4344bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 4345bdb9230aSGarrett D'Amore block++; 4346bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD; 4347bdb9230aSGarrett D'Amore block->type = 0; 4348bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 4349bdb9230aSGarrett D'Amore block++; 4350bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR; 4351bdb9230aSGarrett D'Amore block->type = 0; 4352bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 4353bdb9230aSGarrett D'Amore 4354bdb9230aSGarrett D'Amore /* COGENT FAKE SROM */ 4355bdb9230aSGarrett D'Amore leaf = &leaf_cogent_100; 4356bdb9230aSGarrett D'Amore leaf->is_static = 1; 4357bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[4]; 4358bdb9230aSGarrett D'Amore leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */ 4359bdb9230aSGarrett D'Amore block = leaf->block; /* BNC */ 4360bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC; 4361bdb9230aSGarrett D'Amore block->type = 0; 4362bdb9230aSGarrett D'Amore block->command = 0x8000; /* No media sense, PCS, SCR, PS all off */ 4363bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4364bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4365bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f; 4366bdb9230aSGarrett D'Amore block->gprseq[1] = 1; 4367bdb9230aSGarrett D'Amore 4368bdb9230aSGarrett D'Amore block++; 4369bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD; 4370bdb9230aSGarrett D'Amore block->type = 0; 4371bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 4372bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4373bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4374bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f; 4375bdb9230aSGarrett D'Amore block->gprseq[1] = 0x26; 4376bdb9230aSGarrett D'Amore 4377bdb9230aSGarrett D'Amore block++; /* 10BaseT */ 4378bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP; 4379bdb9230aSGarrett D'Amore block->type = 0; 4380bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */ 4381bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4382bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4383bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f; 4384bdb9230aSGarrett D'Amore block->gprseq[1] = 0x3e; 4385bdb9230aSGarrett D'Amore 4386bdb9230aSGarrett D'Amore block++; /* 100BaseTX-FD */ 4387bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD; 4388bdb9230aSGarrett D'Amore block->type = 0; 4389bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 4390bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4391bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4392bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f; 4393bdb9230aSGarrett D'Amore block->gprseq[1] = 1; 4394bdb9230aSGarrett D'Amore 4395bdb9230aSGarrett D'Amore block++; /* 100BaseTX */ 4396bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR; 4397bdb9230aSGarrett D'Amore block->type = 0; 4398bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */ 4399bdb9230aSGarrett D'Amore block->gprseqlen = 2; 4400bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4401bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f; 4402bdb9230aSGarrett D'Amore block->gprseq[1] = 1; 4403bdb9230aSGarrett D'Amore 4404bdb9230aSGarrett D'Amore /* Generic legacy card with a PHY. */ 4405bdb9230aSGarrett D'Amore leaf = &leaf_phylegacy; 4406bdb9230aSGarrett D'Amore leaf->block_count = 1; 4407bdb9230aSGarrett D'Amore leaf->mii_block = leaf->block; 4408bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0]; 4409bdb9230aSGarrett D'Amore leaf->is_static = 1; 4410bdb9230aSGarrett D'Amore block = leaf->block; 4411bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII; 4412bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */ 4413bdb9230aSGarrett D'Amore block->command = 1; /* Port select */ 4414bdb9230aSGarrett D'Amore block->gprseqlen = 0; 4415bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4416bdb9230aSGarrett D'Amore 4417bdb9230aSGarrett D'Amore /* ASANTE FAKE SROM */ 4418bdb9230aSGarrett D'Amore leaf = &leaf_asante; 4419bdb9230aSGarrett D'Amore leaf->is_static = 1; 4420bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0]; 4421bdb9230aSGarrett D'Amore leaf->block_count = 1; 4422bdb9230aSGarrett D'Amore block = leaf->block; 4423bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII; 4424bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */ 4425bdb9230aSGarrett D'Amore block->command = 1; /* Port select */ 4426bdb9230aSGarrett D'Amore block->gprseqlen = 3; 4427bdb9230aSGarrett D'Amore block->rstseqlen = 0; 4428bdb9230aSGarrett D'Amore block->gprseq[0] = 0x180; 4429bdb9230aSGarrett D'Amore block->gprseq[1] = 0x80; 4430bdb9230aSGarrett D'Amore block->gprseq[2] = 0x0; 4431bdb9230aSGarrett D'Amore 4432bdb9230aSGarrett D'Amore /* LEGACY 21041 card FAKE SROM */ 4433bdb9230aSGarrett D'Amore leaf = &leaf_21041; 4434bdb9230aSGarrett D'Amore leaf->is_static = 1; 4435bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */ 4436bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3]; 4437bdb9230aSGarrett D'Amore 4438bdb9230aSGarrett D'Amore block = leaf->block; 4439bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI; 4440bdb9230aSGarrett D'Amore block->type = 2; 4441bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09; 4442bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4443bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e; 4444bdb9230aSGarrett D'Amore 4445bdb9230aSGarrett D'Amore block++; 4446bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD; 4447bdb9230aSGarrett D'Amore block->type = 2; 4448bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01; 4449bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d; 4450bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4451bdb9230aSGarrett D'Amore 4452bdb9230aSGarrett D'Amore block++; 4453bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC; 4454bdb9230aSGarrett D'Amore block->type = 2; 4455bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09; 4456bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4457bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006; 4458bdb9230aSGarrett D'Amore 4459bdb9230aSGarrett D'Amore block++; 4460bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP; 4461bdb9230aSGarrett D'Amore block->type = 2; 4462bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01; 4463bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f; 4464bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4465bdb9230aSGarrett D'Amore 4466bdb9230aSGarrett D'Amore /* LEGACY 21040 card FAKE SROM */ 4467bdb9230aSGarrett D'Amore leaf = &leaf_21040; 4468bdb9230aSGarrett D'Amore leaf->is_static = 1; 4469bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */ 4470bdb9230aSGarrett D'Amore block = leaf->block; 4471bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI; 4472bdb9230aSGarrett D'Amore block->type = 2; 4473bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f09; 4474bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4475bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e; 4476bdb9230aSGarrett D'Amore block++; 4477bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD; 4478bdb9230aSGarrett D'Amore block->type = 2; 4479bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0f01; 4480bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d; 4481bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4482bdb9230aSGarrett D'Amore block++; 4483bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC; 4484bdb9230aSGarrett D'Amore block->type = 2; 4485bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09; 4486bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705; 4487bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006; 4488bdb9230aSGarrett D'Amore block++; 4489bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP; 4490bdb9230aSGarrett D'Amore block->type = 2; 4491bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f01; 4492bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f; 4493bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008; 4494bdb9230aSGarrett D'Amore } 4495bdb9230aSGarrett D'Amore 4496bdb9230aSGarrett D'Amore static void 4497bdb9230aSGarrett D'Amore dnet_print_srom(SROM_FORMAT *sr) 4498bdb9230aSGarrett D'Amore { 4499bdb9230aSGarrett D'Amore int i; 4500bdb9230aSGarrett D'Amore uchar_t *a = sr->netaddr; 4501bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d," 4502bdb9230aSGarrett D'Amore "Addr:%x:%x:%x:%x:%x:%x", 4503bdb9230aSGarrett D'Amore sr->init_from_srom, sr->version, sr->adapters, 4504bdb9230aSGarrett D'Amore a[0], a[1], a[2], a[3], a[4], a[5]); 4505bdb9230aSGarrett D'Amore 4506bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++) 4507bdb9230aSGarrett D'Amore dnet_dump_leaf(sr->leaf+i); 4508bdb9230aSGarrett D'Amore } 4509bdb9230aSGarrett D'Amore 4510bdb9230aSGarrett D'Amore static void 4511bdb9230aSGarrett D'Amore dnet_dump_leaf(LEAF_FORMAT *leaf) 4512bdb9230aSGarrett D'Amore { 4513bdb9230aSGarrett D'Amore int i; 4514bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x", 4515bdb9230aSGarrett D'Amore leaf->device_number, leaf->block_count, leaf->gpr); 4516bdb9230aSGarrett D'Amore for (i = 0; i < leaf->block_count; i++) 4517bdb9230aSGarrett D'Amore dnet_dump_block(leaf->block+i); 4518bdb9230aSGarrett D'Amore } 4519bdb9230aSGarrett D'Amore 4520bdb9230aSGarrett D'Amore static void 4521bdb9230aSGarrett D'Amore dnet_dump_block(media_block_t *block) 4522bdb9230aSGarrett D'Amore { 4523bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ", 4524bdb9230aSGarrett D'Amore (void *)block, 4525bdb9230aSGarrett D'Amore block->type, media_str[block->media_code], block->command); 4526bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2, 4527bdb9230aSGarrett D'Amore block->gprseqlen *2); 4528bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2, 4529bdb9230aSGarrett D'Amore block->rstseqlen *2); 4530bdb9230aSGarrett D'Amore switch (block->type) { 4531bdb9230aSGarrett D'Amore case 1: case 3: 4532bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx" 4533bdb9230aSGarrett D'Amore "%x, ttm %x, mediacap %x", 4534bdb9230aSGarrett D'Amore block->un.mii.phy_num, block->un.mii.nwayadvert, 4535bdb9230aSGarrett D'Amore block->un.mii.fdxmask, block->un.mii.ttmmask, 4536bdb9230aSGarrett D'Amore block->un.mii.mediacaps); 4537bdb9230aSGarrett D'Amore break; 4538bdb9230aSGarrett D'Amore case 2: 4539bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x", 4540bdb9230aSGarrett D'Amore block->un.sia.csr13, block->un.sia.csr14, 4541bdb9230aSGarrett D'Amore block->un.sia.csr15); 4542bdb9230aSGarrett D'Amore break; 4543bdb9230aSGarrett D'Amore } 4544bdb9230aSGarrett D'Amore } 4545bdb9230aSGarrett D'Amore 4546bdb9230aSGarrett D'Amore 4547bdb9230aSGarrett D'Amore /* Utility to print out binary info dumps. Handy for SROMs, etc */ 4548bdb9230aSGarrett D'Amore 4549bdb9230aSGarrett D'Amore static int 4550bdb9230aSGarrett D'Amore hexcode(unsigned val) 4551bdb9230aSGarrett D'Amore { 4552bdb9230aSGarrett D'Amore if (val <= 9) 4553bdb9230aSGarrett D'Amore return (val +'0'); 4554bdb9230aSGarrett D'Amore if (val <= 15) 4555bdb9230aSGarrett D'Amore return (val + 'a' - 10); 4556bdb9230aSGarrett D'Amore return (-1); 4557bdb9230aSGarrett D'Amore } 4558bdb9230aSGarrett D'Amore 4559bdb9230aSGarrett D'Amore static void 4560bdb9230aSGarrett D'Amore dnet_dumpbin(char *msg, unsigned char *data, int size, int len) 4561bdb9230aSGarrett D'Amore { 4562bdb9230aSGarrett D'Amore char hex[128], *p = hex; 4563bdb9230aSGarrett D'Amore char ascii[128], *q = ascii; 4564bdb9230aSGarrett D'Amore int i, j; 4565bdb9230aSGarrett D'Amore 4566bdb9230aSGarrett D'Amore if (!len) 4567bdb9230aSGarrett D'Amore return; 4568bdb9230aSGarrett D'Amore 4569bdb9230aSGarrett D'Amore for (i = 0; i < len; i += size) { 4570bdb9230aSGarrett D'Amore for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */ 4571bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] >> 4); 4572bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] & 0xf); 4573bdb9230aSGarrett D'Amore *q++ = (data[i+j] < 32 || data[i+j] > 127) ? 4574bdb9230aSGarrett D'Amore '.' : data[i]; 4575bdb9230aSGarrett D'Amore } 4576bdb9230aSGarrett D'Amore *p++ = ' '; 4577bdb9230aSGarrett D'Amore if (q-ascii >= 8) { 4578bdb9230aSGarrett D'Amore *p = *q = 0; 4579bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii); 4580bdb9230aSGarrett D'Amore p = hex; 4581bdb9230aSGarrett D'Amore q = ascii; 4582bdb9230aSGarrett D'Amore } 4583bdb9230aSGarrett D'Amore } 4584bdb9230aSGarrett D'Amore if (p != hex) { 4585bdb9230aSGarrett D'Amore while ((p - hex) < 8*3) 4586bdb9230aSGarrett D'Amore *p++ = ' '; 4587bdb9230aSGarrett D'Amore *p = *q = 0; 4588bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii); 4589bdb9230aSGarrett D'Amore } 4590bdb9230aSGarrett D'Amore } 4591bdb9230aSGarrett D'Amore 4592bdb9230aSGarrett D'Amore #ifdef DNETDEBUG 4593bdb9230aSGarrett D'Amore void 4594bdb9230aSGarrett D'Amore dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin, 4595bdb9230aSGarrett D'Amore timercb_t cback) 4596bdb9230aSGarrett D'Amore { 4597bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock); 4598bdb9230aSGarrett D'Amore dnetp->timer.start_ticks = (usecs * 100) / 8192; 4599bdb9230aSGarrett D'Amore dnetp->timer.cb = cback; 4600bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG), 4601bdb9230aSGarrett D'Amore dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0)); 4602bdb9230aSGarrett D'Amore if (dnetp->timer.cb) 460398e8d175SSteven Stallion enable_interrupts(dnetp); 4604bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock); 4605bdb9230aSGarrett D'Amore } 4606bdb9230aSGarrett D'Amore 4607bdb9230aSGarrett D'Amore uint32_t 4608bdb9230aSGarrett D'Amore dnet_usecelapsed(struct dnetinstance *dnetp) 4609bdb9230aSGarrett D'Amore { 4610bdb9230aSGarrett D'Amore uint32_t ticks = dnetp->timer.start_ticks - 4611bdb9230aSGarrett D'Amore (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) & 4612bdb9230aSGarrett D'Amore 0xffff); 4613bdb9230aSGarrett D'Amore return ((ticks * 8192) / 100); 4614bdb9230aSGarrett D'Amore } 4615bdb9230aSGarrett D'Amore 4616bdb9230aSGarrett D'Amore /* ARGSUSED */ 4617bdb9230aSGarrett D'Amore void 4618bdb9230aSGarrett D'Amore dnet_timestamp(struct dnetinstance *dnetp, char *buf) 4619bdb9230aSGarrett D'Amore { 4620bdb9230aSGarrett D'Amore uint32_t elapsed = dnet_usecelapsed(dnetp); 4621bdb9230aSGarrett D'Amore char loc[32], *p = loc; 4622bdb9230aSGarrett D'Amore int firstdigit = 1; 4623bdb9230aSGarrett D'Amore uint32_t divisor; 4624bdb9230aSGarrett D'Amore 4625bdb9230aSGarrett D'Amore while (*p++ = *buf++) 4626bdb9230aSGarrett D'Amore ; 4627bdb9230aSGarrett D'Amore p--; 4628bdb9230aSGarrett D'Amore 4629bdb9230aSGarrett D'Amore for (divisor = 1000000000; divisor /= 10; ) { 4630bdb9230aSGarrett D'Amore int digit = (elapsed / divisor); 4631bdb9230aSGarrett D'Amore elapsed -= digit * divisor; 4632bdb9230aSGarrett D'Amore if (!firstdigit || digit) { 4633bdb9230aSGarrett D'Amore *p++ = digit + '0'; 4634bdb9230aSGarrett D'Amore firstdigit = 0; 4635bdb9230aSGarrett D'Amore } 4636bdb9230aSGarrett D'Amore 4637bdb9230aSGarrett D'Amore } 4638bdb9230aSGarrett D'Amore 4639bdb9230aSGarrett D'Amore /* Actual zero, output it */ 4640bdb9230aSGarrett D'Amore if (firstdigit) 4641bdb9230aSGarrett D'Amore *p++ = '0'; 4642bdb9230aSGarrett D'Amore 4643bdb9230aSGarrett D'Amore *p++ = '-'; 4644bdb9230aSGarrett D'Amore *p++ = '>'; 4645bdb9230aSGarrett D'Amore *p++ = 0; 4646bdb9230aSGarrett D'Amore 4647bdb9230aSGarrett D'Amore printf(loc); 4648bdb9230aSGarrett D'Amore dnet_usectimeout(dnetp, 1000000, 0, 0); 4649bdb9230aSGarrett D'Amore } 4650bdb9230aSGarrett D'Amore 4651bdb9230aSGarrett D'Amore #endif 4652