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