1*6716431bSRobert Mustacchi /* 2*6716431bSRobert Mustacchi * urf_usbgem.c : Realtek RTL8150 USB to Fast Ethernet Driver for Solaris 3*6716431bSRobert Mustacchi * 4*6716431bSRobert Mustacchi * Copyright (c) 2003-2012 Masayuki Murayama. All rights reserved. 5*6716431bSRobert Mustacchi * 6*6716431bSRobert Mustacchi * Redistribution and use in source and binary forms, with or without 7*6716431bSRobert Mustacchi * modification, are permitted provided that the following conditions are met: 8*6716431bSRobert Mustacchi * 9*6716431bSRobert Mustacchi * 1. Redistributions of source code must retain the above copyright notice, 10*6716431bSRobert Mustacchi * this list of conditions and the following disclaimer. 11*6716431bSRobert Mustacchi * 12*6716431bSRobert Mustacchi * 2. Redistributions in binary form must reproduce the above copyright notice, 13*6716431bSRobert Mustacchi * this list of conditions and the following disclaimer in the documentation 14*6716431bSRobert Mustacchi * and/or other materials provided with the distribution. 15*6716431bSRobert Mustacchi * 16*6716431bSRobert Mustacchi * 3. Neither the name of the author nor the names of its contributors may be 17*6716431bSRobert Mustacchi * used to endorse or promote products derived from this software without 18*6716431bSRobert Mustacchi * specific prior written permission. 19*6716431bSRobert Mustacchi * 20*6716431bSRobert Mustacchi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21*6716431bSRobert Mustacchi * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*6716431bSRobert Mustacchi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*6716431bSRobert Mustacchi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24*6716431bSRobert Mustacchi * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*6716431bSRobert Mustacchi * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*6716431bSRobert Mustacchi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*6716431bSRobert Mustacchi * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*6716431bSRobert Mustacchi * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*6716431bSRobert Mustacchi * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30*6716431bSRobert Mustacchi * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31*6716431bSRobert Mustacchi * DAMAGE. 32*6716431bSRobert Mustacchi */ 33*6716431bSRobert Mustacchi 34*6716431bSRobert Mustacchi /* 35*6716431bSRobert Mustacchi * Changelog: 36*6716431bSRobert Mustacchi */ 37*6716431bSRobert Mustacchi 38*6716431bSRobert Mustacchi /* 39*6716431bSRobert Mustacchi * TODO 40*6716431bSRobert Mustacchi */ 41*6716431bSRobert Mustacchi /* ======================================================= */ 42*6716431bSRobert Mustacchi 43*6716431bSRobert Mustacchi /* 44*6716431bSRobert Mustacchi * Solaris system header files and macros 45*6716431bSRobert Mustacchi */ 46*6716431bSRobert Mustacchi 47*6716431bSRobert Mustacchi /* minimum kernel headers for drivers */ 48*6716431bSRobert Mustacchi #include <sys/types.h> 49*6716431bSRobert Mustacchi #include <sys/conf.h> 50*6716431bSRobert Mustacchi #include <sys/debug.h> 51*6716431bSRobert Mustacchi #include <sys/kmem.h> 52*6716431bSRobert Mustacchi #include <sys/modctl.h> 53*6716431bSRobert Mustacchi #include <sys/errno.h> 54*6716431bSRobert Mustacchi #include <sys/ddi.h> 55*6716431bSRobert Mustacchi #include <sys/sunddi.h> 56*6716431bSRobert Mustacchi #include <sys/byteorder.h> 57*6716431bSRobert Mustacchi 58*6716431bSRobert Mustacchi /* ethernet stuff */ 59*6716431bSRobert Mustacchi #include <sys/ethernet.h> 60*6716431bSRobert Mustacchi 61*6716431bSRobert Mustacchi /* interface card depend stuff */ 62*6716431bSRobert Mustacchi #include <sys/stropts.h> 63*6716431bSRobert Mustacchi #include <sys/stream.h> 64*6716431bSRobert Mustacchi #include <sys/strlog.h> 65*6716431bSRobert Mustacchi #include <sys/usb/usba.h> 66*6716431bSRobert Mustacchi #include "usbgem.h" 67*6716431bSRobert Mustacchi #include "usbgem_mii.h" 68*6716431bSRobert Mustacchi #include "rtl8150reg.h" 69*6716431bSRobert Mustacchi 70*6716431bSRobert Mustacchi char ident[] = "rtl8150 usbnic driver v" VERSION; 71*6716431bSRobert Mustacchi 72*6716431bSRobert Mustacchi /* 73*6716431bSRobert Mustacchi * Useful macros 74*6716431bSRobert Mustacchi */ 75*6716431bSRobert Mustacchi #define ROUNDUP2(x, y) (((x)+(y)-1) & ~((y)-1)) 76*6716431bSRobert Mustacchi #define CHECK_AND_JUMP(err, label) if (err != USB_SUCCESS) goto label 77*6716431bSRobert Mustacchi 78*6716431bSRobert Mustacchi /* 79*6716431bSRobert Mustacchi * Debugging 80*6716431bSRobert Mustacchi */ 81*6716431bSRobert Mustacchi #ifdef DEBUG_LEVEL 82*6716431bSRobert Mustacchi static int urf_debug = DEBUG_LEVEL; 83*6716431bSRobert Mustacchi #define DPRINTF(n, args) if (urf_debug > (n)) cmn_err args 84*6716431bSRobert Mustacchi #else 85*6716431bSRobert Mustacchi #define DPRINTF(n, args) 86*6716431bSRobert Mustacchi #endif 87*6716431bSRobert Mustacchi 88*6716431bSRobert Mustacchi /* 89*6716431bSRobert Mustacchi * Our configration for rtl8150 90*6716431bSRobert Mustacchi */ 91*6716431bSRobert Mustacchi /* timeouts */ 92*6716431bSRobert Mustacchi #define ONESEC (drv_usectohz(1*1000000)) 93*6716431bSRobert Mustacchi 94*6716431bSRobert Mustacchi /* 95*6716431bSRobert Mustacchi * Local device definitions 96*6716431bSRobert Mustacchi */ 97*6716431bSRobert Mustacchi struct chip_info { 98*6716431bSRobert Mustacchi int flags; 99*6716431bSRobert Mustacchi char *name; 100*6716431bSRobert Mustacchi int type; 101*6716431bSRobert Mustacchi }; 102*6716431bSRobert Mustacchi 103*6716431bSRobert Mustacchi #define CHIPTABLESIZE (sizeof (chiptbl_8150) / sizeof (struct chip_info)) 104*6716431bSRobert Mustacchi 105*6716431bSRobert Mustacchi struct urf_dev { 106*6716431bSRobert Mustacchi /* 107*6716431bSRobert Mustacchi * Misc HW information 108*6716431bSRobert Mustacchi */ 109*6716431bSRobert Mustacchi struct chip_info *chip; 110*6716431bSRobert Mustacchi uint8_t cr; 111*6716431bSRobert Mustacchi uint8_t tsr; 112*6716431bSRobert Mustacchi uint16_t rcr; 113*6716431bSRobert Mustacchi uint8_t txok_cnt; 114*6716431bSRobert Mustacchi }; 115*6716431bSRobert Mustacchi 116*6716431bSRobert Mustacchi /* 117*6716431bSRobert Mustacchi * private functions 118*6716431bSRobert Mustacchi */ 119*6716431bSRobert Mustacchi 120*6716431bSRobert Mustacchi /* mii operations */ 121*6716431bSRobert Mustacchi static uint16_t urf_mii_read(struct usbgem_dev *, uint_t, int *errp); 122*6716431bSRobert Mustacchi static void urf_mii_write(struct usbgem_dev *, uint_t, uint16_t, int *errp); 123*6716431bSRobert Mustacchi 124*6716431bSRobert Mustacchi /* nic operations */ 125*6716431bSRobert Mustacchi static int urf_attach_chip(struct usbgem_dev *); 126*6716431bSRobert Mustacchi static int urf_reset_chip(struct usbgem_dev *); 127*6716431bSRobert Mustacchi static int urf_init_chip(struct usbgem_dev *); 128*6716431bSRobert Mustacchi static int urf_start_chip(struct usbgem_dev *); 129*6716431bSRobert Mustacchi static int urf_stop_chip(struct usbgem_dev *); 130*6716431bSRobert Mustacchi static int urf_set_media(struct usbgem_dev *); 131*6716431bSRobert Mustacchi static int urf_set_rx_filter(struct usbgem_dev *); 132*6716431bSRobert Mustacchi static int urf_get_stats(struct usbgem_dev *); 133*6716431bSRobert Mustacchi 134*6716431bSRobert Mustacchi /* packet operations */ 135*6716431bSRobert Mustacchi static mblk_t *urf_tx_make_packet(struct usbgem_dev *, mblk_t *); 136*6716431bSRobert Mustacchi static mblk_t *urf_rx_make_packet(struct usbgem_dev *, mblk_t *); 137*6716431bSRobert Mustacchi 138*6716431bSRobert Mustacchi /* =============================================================== */ 139*6716431bSRobert Mustacchi /* 140*6716431bSRobert Mustacchi * I/O functions 141*6716431bSRobert Mustacchi */ 142*6716431bSRobert Mustacchi /* =============================================================== */ 143*6716431bSRobert Mustacchi #define OUTB(dp, p, v, errp, label) \ 144*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_out_val((dp), \ 145*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \ 146*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 147*6716431bSRobert Mustacchi /* bRequest */ USB_REQ_SET_ADDRESS, \ 148*6716431bSRobert Mustacchi /* wValue */ (p), \ 149*6716431bSRobert Mustacchi /* wIndex */ 0, \ 150*6716431bSRobert Mustacchi /* wLength */ 1, \ 151*6716431bSRobert Mustacchi /* value */ (v))) != USB_SUCCESS) goto label 152*6716431bSRobert Mustacchi 153*6716431bSRobert Mustacchi #define OUTW(dp, p, v, errp, label) \ 154*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_out_val((dp), \ 155*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \ 156*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 157*6716431bSRobert Mustacchi /* bRequest */ USB_REQ_SET_ADDRESS, \ 158*6716431bSRobert Mustacchi /* wValue */ (p), \ 159*6716431bSRobert Mustacchi /* wIndex */ 0, \ 160*6716431bSRobert Mustacchi /* wLength */ 2, \ 161*6716431bSRobert Mustacchi /* value */ (v))) != USB_SUCCESS) goto label 162*6716431bSRobert Mustacchi 163*6716431bSRobert Mustacchi /* BEGIN CSTYLED */ 164*6716431bSRobert Mustacchi #define OUTS(dp, p, buf, len, errp, label) \ 165*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_out((dp), \ 166*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \ 167*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 168*6716431bSRobert Mustacchi /* bRequest */ USB_REQ_SET_ADDRESS, \ 169*6716431bSRobert Mustacchi /* wValue */ (p), \ 170*6716431bSRobert Mustacchi /* wIndex */ 0, \ 171*6716431bSRobert Mustacchi /* wLength */ (len), \ 172*6716431bSRobert Mustacchi /* value */ (buf), \ 173*6716431bSRobert Mustacchi /* size */ (len))) != USB_SUCCESS) goto label 174*6716431bSRobert Mustacchi /* END CSTYLED */ 175*6716431bSRobert Mustacchi 176*6716431bSRobert Mustacchi #define IN(dp, p, vp, errp, label) \ 177*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_in_val((dp), \ 178*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST \ 179*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 180*6716431bSRobert Mustacchi /* bRequest */ USB_REQ_SET_ADDRESS, \ 181*6716431bSRobert Mustacchi /* wValue */ (p), \ 182*6716431bSRobert Mustacchi /* wIndex */ 0, \ 183*6716431bSRobert Mustacchi /* wLength */ sizeof ((*vp)), \ 184*6716431bSRobert Mustacchi /* valuep */ (vp))) != USB_SUCCESS) goto label 185*6716431bSRobert Mustacchi 186*6716431bSRobert Mustacchi #define INS(dp, p, buf, len, errp, label) \ 187*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_in((dp), \ 188*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST \ 189*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 190*6716431bSRobert Mustacchi /* bRequest */ USB_REQ_SET_ADDRESS, \ 191*6716431bSRobert Mustacchi /* wValue */ (p), \ 192*6716431bSRobert Mustacchi /* wIndex */ 0, \ 193*6716431bSRobert Mustacchi /* wLength */ (len), \ 194*6716431bSRobert Mustacchi /* valuep */ (buf), \ 195*6716431bSRobert Mustacchi /* size */ (len))) != USB_SUCCESS) goto label 196*6716431bSRobert Mustacchi 197*6716431bSRobert Mustacchi /* =============================================================== */ 198*6716431bSRobert Mustacchi /* 199*6716431bSRobert Mustacchi * variables 200*6716431bSRobert Mustacchi */ 201*6716431bSRobert Mustacchi /* =============================================================== */ 202*6716431bSRobert Mustacchi static int urf_ppa = 0; 203*6716431bSRobert Mustacchi 204*6716431bSRobert Mustacchi /* =============================================================== */ 205*6716431bSRobert Mustacchi /* 206*6716431bSRobert Mustacchi * Hardware manupilation 207*6716431bSRobert Mustacchi */ 208*6716431bSRobert Mustacchi /* =============================================================== */ 209*6716431bSRobert Mustacchi static int 210*6716431bSRobert Mustacchi urf_reset_chip(struct usbgem_dev *dp) 211*6716431bSRobert Mustacchi { 212*6716431bSRobert Mustacchi int i; 213*6716431bSRobert Mustacchi int err; 214*6716431bSRobert Mustacchi uint8_t reg; 215*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 216*6716431bSRobert Mustacchi 217*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 218*6716431bSRobert Mustacchi 219*6716431bSRobert Mustacchi lp->cr = 0; 220*6716431bSRobert Mustacchi OUTB(dp, CR, lp->cr | CR_SOFT_RST, &err, usberr); 221*6716431bSRobert Mustacchi 222*6716431bSRobert Mustacchi for (i = 0; i < 100; i++) { 223*6716431bSRobert Mustacchi IN(dp, CR, ®, &err, usberr); 224*6716431bSRobert Mustacchi if ((reg & CR_SOFT_RST) == 0) { 225*6716431bSRobert Mustacchi return (USB_SUCCESS); 226*6716431bSRobert Mustacchi } 227*6716431bSRobert Mustacchi } 228*6716431bSRobert Mustacchi /* time out */ 229*6716431bSRobert Mustacchi cmn_err(CE_WARN, "%s: failed to reset: timeout", dp->name); 230*6716431bSRobert Mustacchi return (USB_FAILURE); 231*6716431bSRobert Mustacchi 232*6716431bSRobert Mustacchi usberr: 233*6716431bSRobert Mustacchi cmn_err(CE_NOTE, "!%s: %s: usberr detected", dp->name, __func__); 234*6716431bSRobert Mustacchi return (USB_FAILURE); 235*6716431bSRobert Mustacchi } 236*6716431bSRobert Mustacchi 237*6716431bSRobert Mustacchi /* 238*6716431bSRobert Mustacchi * Setup rtl8150 239*6716431bSRobert Mustacchi */ 240*6716431bSRobert Mustacchi static int 241*6716431bSRobert Mustacchi urf_init_chip(struct usbgem_dev *dp) 242*6716431bSRobert Mustacchi { 243*6716431bSRobert Mustacchi int i; 244*6716431bSRobert Mustacchi uint32_t val; 245*6716431bSRobert Mustacchi int err; 246*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 247*6716431bSRobert Mustacchi 248*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 249*6716431bSRobert Mustacchi 250*6716431bSRobert Mustacchi /* ID registers: set later by urf_set_rx_filter */ 251*6716431bSRobert Mustacchi 252*6716431bSRobert Mustacchi /* Multicast registers: set later by urf_set_rx_filter */ 253*6716431bSRobert Mustacchi 254*6716431bSRobert Mustacchi /* Command register : Enable Tx and Rx before writing TCR and RCR */ 255*6716431bSRobert Mustacchi lp->cr |= CR_RE | CR_TE; 256*6716431bSRobert Mustacchi OUTB(dp, CR, lp->cr, &err, usberr); 257*6716431bSRobert Mustacchi 258*6716431bSRobert Mustacchi /* Transmit configration register : */ 259*6716431bSRobert Mustacchi OUTB(dp, TCR, TCR_IFG_802_3, &err, usberr); 260*6716431bSRobert Mustacchi 261*6716431bSRobert Mustacchi /* Receive configuration register : disable rx filter */ 262*6716431bSRobert Mustacchi lp->rcr = RCR_TAIL | RCR_AER | RCR_AR; 263*6716431bSRobert Mustacchi OUTW(dp, RCR, lp->rcr, &err, usberr); 264*6716431bSRobert Mustacchi #ifdef notdef 265*6716431bSRobert Mustacchi /* Media status register */ 266*6716431bSRobert Mustacchi err = urf_set_media(dp); 267*6716431bSRobert Mustacchi CHECK_AND_JUMP(err, usberr); 268*6716431bSRobert Mustacchi #endif 269*6716431bSRobert Mustacchi /* Configuration register 0: no need to change */ 270*6716431bSRobert Mustacchi 271*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end (success)", dp->name, __func__)); 272*6716431bSRobert Mustacchi return (USB_SUCCESS); 273*6716431bSRobert Mustacchi 274*6716431bSRobert Mustacchi usberr: 275*6716431bSRobert Mustacchi cmn_err(CE_NOTE, "!%s: %s: usberr detected", dp->name, __func__); 276*6716431bSRobert Mustacchi return (USB_FAILURE); 277*6716431bSRobert Mustacchi } 278*6716431bSRobert Mustacchi 279*6716431bSRobert Mustacchi static int 280*6716431bSRobert Mustacchi urf_start_chip(struct usbgem_dev *dp) 281*6716431bSRobert Mustacchi { 282*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 283*6716431bSRobert Mustacchi 284*6716431bSRobert Mustacchi /* do nothing */ 285*6716431bSRobert Mustacchi return (USB_SUCCESS); 286*6716431bSRobert Mustacchi } 287*6716431bSRobert Mustacchi 288*6716431bSRobert Mustacchi static int 289*6716431bSRobert Mustacchi urf_stop_chip(struct usbgem_dev *dp) 290*6716431bSRobert Mustacchi { 291*6716431bSRobert Mustacchi return (urf_reset_chip(dp)); 292*6716431bSRobert Mustacchi } 293*6716431bSRobert Mustacchi 294*6716431bSRobert Mustacchi static int 295*6716431bSRobert Mustacchi urf_get_stats(struct usbgem_dev *dp) 296*6716431bSRobert Mustacchi { 297*6716431bSRobert Mustacchi /* do nothing */ 298*6716431bSRobert Mustacchi return (USB_SUCCESS); 299*6716431bSRobert Mustacchi } 300*6716431bSRobert Mustacchi 301*6716431bSRobert Mustacchi static uint_t 302*6716431bSRobert Mustacchi urf_mcast_hash(struct usbgem_dev *dp, const uint8_t *addr) 303*6716431bSRobert Mustacchi { 304*6716431bSRobert Mustacchi return (usbgem_ether_crc_be(addr)); 305*6716431bSRobert Mustacchi } 306*6716431bSRobert Mustacchi 307*6716431bSRobert Mustacchi static int 308*6716431bSRobert Mustacchi urf_set_rx_filter(struct usbgem_dev *dp) 309*6716431bSRobert Mustacchi { 310*6716431bSRobert Mustacchi int i; 311*6716431bSRobert Mustacchi uint16_t mode; 312*6716431bSRobert Mustacchi uint8_t mhash[8]; 313*6716431bSRobert Mustacchi int err; 314*6716431bSRobert Mustacchi int16_t rcr; 315*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 316*6716431bSRobert Mustacchi 317*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called, rxmode:%x", 318*6716431bSRobert Mustacchi dp->name, __func__, dp->rxmode)); 319*6716431bSRobert Mustacchi 320*6716431bSRobert Mustacchi if (lp->rcr & (RCR_AB | RCR_AD | RCR_AAM | RCR_AAP | RCR_AM)) { 321*6716431bSRobert Mustacchi #ifdef notdef 322*6716431bSRobert Mustacchi /* disable rx filter before changing it. */ 323*6716431bSRobert Mustacchi lp->rcr &= ~(RCR_AB | RCR_AD | RCR_AAM | RCR_AAP | RCR_AM); 324*6716431bSRobert Mustacchi OUTW(dp, RCR, lp->rcr, &err, usberr); 325*6716431bSRobert Mustacchi #else 326*6716431bSRobert Mustacchi /* receive all packets while we change rx filter */ 327*6716431bSRobert Mustacchi OUTW(dp, RCR, lp->rcr | RCR_AAM | RCR_AAP, &err, usberr); 328*6716431bSRobert Mustacchi #endif 329*6716431bSRobert Mustacchi } 330*6716431bSRobert Mustacchi 331*6716431bSRobert Mustacchi mode = RCR_AB /* accept broadcast */ 332*6716431bSRobert Mustacchi | RCR_AD; /* accept physical match */ 333*6716431bSRobert Mustacchi bzero(mhash, sizeof (mhash)); 334*6716431bSRobert Mustacchi 335*6716431bSRobert Mustacchi if (dp->rxmode & RXMODE_PROMISC) { 336*6716431bSRobert Mustacchi /* promiscious mode implies all multicast and all physical */ 337*6716431bSRobert Mustacchi mode |= RCR_AAM | RCR_AAP; 338*6716431bSRobert Mustacchi } else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 64/2) { 339*6716431bSRobert Mustacchi /* accept all multicast packets */ 340*6716431bSRobert Mustacchi mode |= RCR_AAM; 341*6716431bSRobert Mustacchi } else if (dp->mc_count > 0) { 342*6716431bSRobert Mustacchi /* 343*6716431bSRobert Mustacchi * make hash table to select interresting 344*6716431bSRobert Mustacchi * multicast address only. 345*6716431bSRobert Mustacchi */ 346*6716431bSRobert Mustacchi mode |= RCR_AM; 347*6716431bSRobert Mustacchi for (i = 0; i < dp->mc_count; i++) { 348*6716431bSRobert Mustacchi uint_t h; 349*6716431bSRobert Mustacchi /* hash table is 64 = 2^6 bit width */ 350*6716431bSRobert Mustacchi h = dp->mc_list[i].hash >> (32 - 6); 351*6716431bSRobert Mustacchi mhash[h / 8] |= 1 << (h % 8); 352*6716431bSRobert Mustacchi } 353*6716431bSRobert Mustacchi } 354*6716431bSRobert Mustacchi lp->rcr |= mode; 355*6716431bSRobert Mustacchi 356*6716431bSRobert Mustacchi /* set mac address */ 357*6716431bSRobert Mustacchi OUTS(dp, IDR, dp->cur_addr.ether_addr_octet, ETHERADDRL, &err, usberr); 358*6716431bSRobert Mustacchi 359*6716431bSRobert Mustacchi /* set multicast hash table */ 360*6716431bSRobert Mustacchi if (mode & RCR_AM) { 361*6716431bSRobert Mustacchi /* need to set up multicast hash table */ 362*6716431bSRobert Mustacchi OUTS(dp, MAR, mhash, sizeof (mhash), &err, usberr); 363*6716431bSRobert Mustacchi } 364*6716431bSRobert Mustacchi 365*6716431bSRobert Mustacchi OUTW(dp, RCR, lp->rcr, &err, usberr); 366*6716431bSRobert Mustacchi 367*6716431bSRobert Mustacchi #if DEBUG_LEVEL > 2 368*6716431bSRobert Mustacchi IN(dp, RCR, &rcr, &err, usberr); 369*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!%s: %s: rcr:%b returned", 370*6716431bSRobert Mustacchi dp->name, __func__, rcr, RCR_BITS); 371*6716431bSRobert Mustacchi #endif 372*6716431bSRobert Mustacchi return (USB_SUCCESS); 373*6716431bSRobert Mustacchi 374*6716431bSRobert Mustacchi usberr: 375*6716431bSRobert Mustacchi cmn_err(CE_NOTE, "!%s: %s: usberr detected", dp->name, __func__); 376*6716431bSRobert Mustacchi return (USB_FAILURE); 377*6716431bSRobert Mustacchi } 378*6716431bSRobert Mustacchi 379*6716431bSRobert Mustacchi static int 380*6716431bSRobert Mustacchi urf_set_media(struct usbgem_dev *dp) 381*6716431bSRobert Mustacchi { 382*6716431bSRobert Mustacchi uint8_t new; 383*6716431bSRobert Mustacchi uint8_t old; 384*6716431bSRobert Mustacchi int err; 385*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 386*6716431bSRobert Mustacchi 387*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 388*6716431bSRobert Mustacchi 389*6716431bSRobert Mustacchi /* select duplex: do nothing */ 390*6716431bSRobert Mustacchi 391*6716431bSRobert Mustacchi /* select speed: do nothing */ 392*6716431bSRobert Mustacchi 393*6716431bSRobert Mustacchi /* flow control */ 394*6716431bSRobert Mustacchi IN(dp, MSR, &old, &err, usberr); 395*6716431bSRobert Mustacchi 396*6716431bSRobert Mustacchi 397*6716431bSRobert Mustacchi /* setup flow control */ 398*6716431bSRobert Mustacchi new = old & ~(MSR_TXFCE | MSR_RXFCE); 399*6716431bSRobert Mustacchi switch (dp->flow_control) { 400*6716431bSRobert Mustacchi case FLOW_CONTROL_SYMMETRIC: 401*6716431bSRobert Mustacchi new |= MSR_TXFCE | MSR_RXFCE; 402*6716431bSRobert Mustacchi break; 403*6716431bSRobert Mustacchi 404*6716431bSRobert Mustacchi case FLOW_CONTROL_TX_PAUSE: 405*6716431bSRobert Mustacchi new |= MSR_TXFCE; 406*6716431bSRobert Mustacchi break; 407*6716431bSRobert Mustacchi 408*6716431bSRobert Mustacchi case FLOW_CONTROL_RX_PAUSE: 409*6716431bSRobert Mustacchi new |= MSR_RXFCE; 410*6716431bSRobert Mustacchi break; 411*6716431bSRobert Mustacchi 412*6716431bSRobert Mustacchi case FLOW_CONTROL_NONE: 413*6716431bSRobert Mustacchi default: 414*6716431bSRobert Mustacchi break; 415*6716431bSRobert Mustacchi } 416*6716431bSRobert Mustacchi 417*6716431bSRobert Mustacchi if (new != old) { 418*6716431bSRobert Mustacchi OUTB(dp, MSR, new, &err, usberr); 419*6716431bSRobert Mustacchi } 420*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: returned", dp->name, __func__)); 421*6716431bSRobert Mustacchi return (USB_SUCCESS); 422*6716431bSRobert Mustacchi 423*6716431bSRobert Mustacchi usberr: 424*6716431bSRobert Mustacchi cmn_err(CE_NOTE, "!%s: %s: usberr detected", dp->name, __func__); 425*6716431bSRobert Mustacchi return (USB_FAILURE); 426*6716431bSRobert Mustacchi } 427*6716431bSRobert Mustacchi 428*6716431bSRobert Mustacchi /* 429*6716431bSRobert Mustacchi * send/receive packet check 430*6716431bSRobert Mustacchi */ 431*6716431bSRobert Mustacchi static mblk_t * 432*6716431bSRobert Mustacchi urf_tx_make_packet(struct usbgem_dev *dp, mblk_t *mp) 433*6716431bSRobert Mustacchi { 434*6716431bSRobert Mustacchi size_t len; 435*6716431bSRobert Mustacchi mblk_t *new; 436*6716431bSRobert Mustacchi mblk_t *tp; 437*6716431bSRobert Mustacchi uint8_t *bp; 438*6716431bSRobert Mustacchi uint8_t *last_pos; 439*6716431bSRobert Mustacchi 440*6716431bSRobert Mustacchi len = msgdsize(mp); 441*6716431bSRobert Mustacchi 442*6716431bSRobert Mustacchi if (len < ETHERMIN || mp->b_cont != NULL || (len & 0x3f) == 0) { 443*6716431bSRobert Mustacchi /* 444*6716431bSRobert Mustacchi * re-allocate mp 445*6716431bSRobert Mustacchi */ 446*6716431bSRobert Mustacchi len = max(len, ETHERMIN); 447*6716431bSRobert Mustacchi 448*6716431bSRobert Mustacchi if ((len & 0x3f) == 0) { 449*6716431bSRobert Mustacchi /* workaround for buggy USB hba */ 450*6716431bSRobert Mustacchi len++; 451*6716431bSRobert Mustacchi } 452*6716431bSRobert Mustacchi 453*6716431bSRobert Mustacchi if ((new = allocb(len, 0)) == NULL) { 454*6716431bSRobert Mustacchi return (NULL); 455*6716431bSRobert Mustacchi } 456*6716431bSRobert Mustacchi 457*6716431bSRobert Mustacchi /* copy contents of the buffer */ 458*6716431bSRobert Mustacchi new->b_wptr = new->b_rptr + len; 459*6716431bSRobert Mustacchi bp = new->b_rptr; 460*6716431bSRobert Mustacchi for (tp = mp; tp; tp = tp->b_cont) { 461*6716431bSRobert Mustacchi len = (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr; 462*6716431bSRobert Mustacchi bcopy(tp->b_rptr, bp, len); 463*6716431bSRobert Mustacchi bp += len; 464*6716431bSRobert Mustacchi } 465*6716431bSRobert Mustacchi 466*6716431bSRobert Mustacchi last_pos = new->b_wptr; 467*6716431bSRobert Mustacchi while (bp < last_pos) { 468*6716431bSRobert Mustacchi *bp++ = 0; 469*6716431bSRobert Mustacchi } 470*6716431bSRobert Mustacchi 471*6716431bSRobert Mustacchi mp = new; 472*6716431bSRobert Mustacchi } 473*6716431bSRobert Mustacchi 474*6716431bSRobert Mustacchi return (mp); 475*6716431bSRobert Mustacchi } 476*6716431bSRobert Mustacchi 477*6716431bSRobert Mustacchi static void 478*6716431bSRobert Mustacchi urf_dump_packet(struct usbgem_dev *dp, uint8_t *bp, int n) 479*6716431bSRobert Mustacchi { 480*6716431bSRobert Mustacchi int i; 481*6716431bSRobert Mustacchi 482*6716431bSRobert Mustacchi for (i = 0; i < n; i += 8, bp += 8) { 483*6716431bSRobert Mustacchi cmn_err(CE_CONT, "%02x %02x %02x %02x %02x %02x %02x %02x", 484*6716431bSRobert Mustacchi bp[0], bp[1], bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]); 485*6716431bSRobert Mustacchi } 486*6716431bSRobert Mustacchi } 487*6716431bSRobert Mustacchi 488*6716431bSRobert Mustacchi static mblk_t * 489*6716431bSRobert Mustacchi urf_rx_make_packet(struct usbgem_dev *dp, mblk_t *mp) 490*6716431bSRobert Mustacchi { 491*6716431bSRobert Mustacchi uint8_t *p; 492*6716431bSRobert Mustacchi uint16_t rxhd; 493*6716431bSRobert Mustacchi uint_t len; 494*6716431bSRobert Mustacchi 495*6716431bSRobert Mustacchi ASSERT(mp != NULL); 496*6716431bSRobert Mustacchi len = msgdsize(mp); 497*6716431bSRobert Mustacchi #ifdef DEBUG_LEVEL 498*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: time:%d %s: len:%d cont:%p", 499*6716431bSRobert Mustacchi dp->name, ddi_get_lbolt(), __func__, len, mp->b_cont)); 500*6716431bSRobert Mustacchi 501*6716431bSRobert Mustacchi if (urf_debug > 2) { 502*6716431bSRobert Mustacchi urf_dump_packet(dp, mp->b_rptr, max(6, len)); 503*6716431bSRobert Mustacchi } 504*6716431bSRobert Mustacchi #endif 505*6716431bSRobert Mustacchi if (len < ETHERMIN + ETHERFCSL) { 506*6716431bSRobert Mustacchi /* Too short */ 507*6716431bSRobert Mustacchi dp->stats.runt++; 508*6716431bSRobert Mustacchi dp->stats.errrcv++; 509*6716431bSRobert Mustacchi return (NULL); 510*6716431bSRobert Mustacchi } 511*6716431bSRobert Mustacchi 512*6716431bSRobert Mustacchi /* get Rx header which is placed at tail of the packet. */ 513*6716431bSRobert Mustacchi p = mp->b_wptr - 4; 514*6716431bSRobert Mustacchi rxhd = (p[1] << 8) | p[0]; 515*6716431bSRobert Mustacchi len = rxhd & RXHD_BYTECNT; 516*6716431bSRobert Mustacchi 517*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: rsr:%b len:%d", 518*6716431bSRobert Mustacchi dp->name, __func__, rxhd, RXHD_BITS, len)); 519*6716431bSRobert Mustacchi 520*6716431bSRobert Mustacchi /* check if error happen */ 521*6716431bSRobert Mustacchi if ((rxhd & (RXHD_VALID)) == 0) { 522*6716431bSRobert Mustacchi DPRINTF(-1, (CE_CONT, "!%s: %s: rxhd:%b", 523*6716431bSRobert Mustacchi dp->name, __func__, rxhd, RXHD_BITS)); 524*6716431bSRobert Mustacchi if (rxhd & RXHD_RUNT) { 525*6716431bSRobert Mustacchi dp->stats.runt++; 526*6716431bSRobert Mustacchi } 527*6716431bSRobert Mustacchi 528*6716431bSRobert Mustacchi dp->stats.errrcv++; 529*6716431bSRobert Mustacchi return (NULL); 530*6716431bSRobert Mustacchi } 531*6716431bSRobert Mustacchi #ifdef notdef 532*6716431bSRobert Mustacchi /* check packet size */ 533*6716431bSRobert Mustacchi if (len > ETHERMAX + ETHERFCSL) { 534*6716431bSRobert Mustacchi /* too long */ 535*6716431bSRobert Mustacchi dp->stats.frame_too_long++; 536*6716431bSRobert Mustacchi dp->stats.errrcv++; 537*6716431bSRobert Mustacchi return (NULL); 538*6716431bSRobert Mustacchi } else if (len < ETHERMIN + ETHERFCSL) { 539*6716431bSRobert Mustacchi dp->stats.runt++; 540*6716431bSRobert Mustacchi dp->stats.errrcv++; 541*6716431bSRobert Mustacchi return (NULL); 542*6716431bSRobert Mustacchi } 543*6716431bSRobert Mustacchi #endif 544*6716431bSRobert Mustacchi /* remove tailing crc field */ 545*6716431bSRobert Mustacchi mp->b_wptr -= ETHERFCSL; 546*6716431bSRobert Mustacchi return (mp); 547*6716431bSRobert Mustacchi } 548*6716431bSRobert Mustacchi 549*6716431bSRobert Mustacchi /* 550*6716431bSRobert Mustacchi * MII Interfaces 551*6716431bSRobert Mustacchi */ 552*6716431bSRobert Mustacchi static uint16_t 553*6716431bSRobert Mustacchi urf_mii_read(struct usbgem_dev *dp, uint_t index, int *errp) 554*6716431bSRobert Mustacchi { 555*6716431bSRobert Mustacchi int reg; 556*6716431bSRobert Mustacchi uint16_t val; 557*6716431bSRobert Mustacchi 558*6716431bSRobert Mustacchi DPRINTF(4, (CE_CONT, "!%s: %s: called, ix:%d", 559*6716431bSRobert Mustacchi dp->name, __func__, index)); 560*6716431bSRobert Mustacchi 561*6716431bSRobert Mustacchi *errp = USB_SUCCESS; 562*6716431bSRobert Mustacchi 563*6716431bSRobert Mustacchi switch (index) { 564*6716431bSRobert Mustacchi case MII_CONTROL: 565*6716431bSRobert Mustacchi reg = BMCR; 566*6716431bSRobert Mustacchi break; 567*6716431bSRobert Mustacchi 568*6716431bSRobert Mustacchi case MII_STATUS: 569*6716431bSRobert Mustacchi reg = BMSR; 570*6716431bSRobert Mustacchi break; 571*6716431bSRobert Mustacchi 572*6716431bSRobert Mustacchi case MII_AN_ADVERT: 573*6716431bSRobert Mustacchi reg = ANAR; 574*6716431bSRobert Mustacchi break; 575*6716431bSRobert Mustacchi 576*6716431bSRobert Mustacchi case MII_AN_LPABLE: 577*6716431bSRobert Mustacchi reg = ANLP; 578*6716431bSRobert Mustacchi break; 579*6716431bSRobert Mustacchi 580*6716431bSRobert Mustacchi case MII_AN_EXPANSION: 581*6716431bSRobert Mustacchi reg = ANER; 582*6716431bSRobert Mustacchi break; 583*6716431bSRobert Mustacchi 584*6716431bSRobert Mustacchi default: 585*6716431bSRobert Mustacchi return (0); 586*6716431bSRobert Mustacchi } 587*6716431bSRobert Mustacchi 588*6716431bSRobert Mustacchi IN(dp, reg, &val, errp, usberr); 589*6716431bSRobert Mustacchi 590*6716431bSRobert Mustacchi if (index == MII_STATUS) { 591*6716431bSRobert Mustacchi uint8_t msr; 592*6716431bSRobert Mustacchi /* 593*6716431bSRobert Mustacchi * Fix MII status register as it does't have LINKUP and 594*6716431bSRobert Mustacchi * MFPRMBLSUPR bits. 595*6716431bSRobert Mustacchi */ 596*6716431bSRobert Mustacchi IN(dp, MSR, &msr, errp, usberr); 597*6716431bSRobert Mustacchi 598*6716431bSRobert Mustacchi val |= (MII_STATUS_MFPRMBLSUPR | MII_STATUS_LINKUP); 599*6716431bSRobert Mustacchi if ((msr & MSR_LINK) == 0) { 600*6716431bSRobert Mustacchi val &= ~MII_STATUS_LINKUP; 601*6716431bSRobert Mustacchi } 602*6716431bSRobert Mustacchi } 603*6716431bSRobert Mustacchi 604*6716431bSRobert Mustacchi return (val); 605*6716431bSRobert Mustacchi 606*6716431bSRobert Mustacchi usberr: 607*6716431bSRobert Mustacchi cmn_err(CE_CONT, 608*6716431bSRobert Mustacchi "!%s: %s: usberr(%d) detected", dp->name, __func__, *errp); 609*6716431bSRobert Mustacchi 610*6716431bSRobert Mustacchi return (0); 611*6716431bSRobert Mustacchi } 612*6716431bSRobert Mustacchi 613*6716431bSRobert Mustacchi static void 614*6716431bSRobert Mustacchi urf_mii_write(struct usbgem_dev *dp, uint_t index, uint16_t val, int *errp) 615*6716431bSRobert Mustacchi { 616*6716431bSRobert Mustacchi int reg; 617*6716431bSRobert Mustacchi 618*6716431bSRobert Mustacchi DPRINTF(5, (CE_CONT, "!%s: %s called", dp->name, __func__)); 619*6716431bSRobert Mustacchi 620*6716431bSRobert Mustacchi *errp = USB_SUCCESS; 621*6716431bSRobert Mustacchi 622*6716431bSRobert Mustacchi switch (index) { 623*6716431bSRobert Mustacchi case MII_CONTROL: 624*6716431bSRobert Mustacchi reg = BMCR; 625*6716431bSRobert Mustacchi break; 626*6716431bSRobert Mustacchi 627*6716431bSRobert Mustacchi case MII_STATUS: 628*6716431bSRobert Mustacchi reg = BMSR; 629*6716431bSRobert Mustacchi break; 630*6716431bSRobert Mustacchi 631*6716431bSRobert Mustacchi case MII_AN_ADVERT: 632*6716431bSRobert Mustacchi reg = ANAR; 633*6716431bSRobert Mustacchi break; 634*6716431bSRobert Mustacchi 635*6716431bSRobert Mustacchi case MII_AN_LPABLE: 636*6716431bSRobert Mustacchi reg = ANLP; 637*6716431bSRobert Mustacchi break; 638*6716431bSRobert Mustacchi 639*6716431bSRobert Mustacchi case MII_AN_EXPANSION: 640*6716431bSRobert Mustacchi reg = ANER; 641*6716431bSRobert Mustacchi break; 642*6716431bSRobert Mustacchi 643*6716431bSRobert Mustacchi default: 644*6716431bSRobert Mustacchi return; 645*6716431bSRobert Mustacchi } 646*6716431bSRobert Mustacchi 647*6716431bSRobert Mustacchi OUTW(dp, reg, val, errp, usberr); 648*6716431bSRobert Mustacchi usberr: 649*6716431bSRobert Mustacchi ; 650*6716431bSRobert Mustacchi } 651*6716431bSRobert Mustacchi 652*6716431bSRobert Mustacchi /* ======================================================== */ 653*6716431bSRobert Mustacchi /* 654*6716431bSRobert Mustacchi * OS depend (device driver DKI) routine 655*6716431bSRobert Mustacchi */ 656*6716431bSRobert Mustacchi /* ======================================================== */ 657*6716431bSRobert Mustacchi static void 658*6716431bSRobert Mustacchi urf_eeprom_dump(struct usbgem_dev *dp, int size) 659*6716431bSRobert Mustacchi { 660*6716431bSRobert Mustacchi int i; 661*6716431bSRobert Mustacchi int err; 662*6716431bSRobert Mustacchi uint16_t w0, w1, w2, w3; 663*6716431bSRobert Mustacchi 664*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!%s: eeprom dump:", dp->name); 665*6716431bSRobert Mustacchi for (i = URF_EEPROM_BASE; i < size + URF_EEPROM_BASE; i += 8) { 666*6716431bSRobert Mustacchi IN(dp, i + 0, &w0, &err, usberr); 667*6716431bSRobert Mustacchi IN(dp, i + 2, &w1, &err, usberr); 668*6716431bSRobert Mustacchi IN(dp, i + 4, &w2, &err, usberr); 669*6716431bSRobert Mustacchi IN(dp, i + 6, &w3, &err, usberr); 670*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x", 671*6716431bSRobert Mustacchi i - URF_EEPROM_BASE, w0, w1, w2, w3); 672*6716431bSRobert Mustacchi } 673*6716431bSRobert Mustacchi usberr: 674*6716431bSRobert Mustacchi ; 675*6716431bSRobert Mustacchi } 676*6716431bSRobert Mustacchi 677*6716431bSRobert Mustacchi static int 678*6716431bSRobert Mustacchi urf_attach_chip(struct usbgem_dev *dp) 679*6716431bSRobert Mustacchi { 680*6716431bSRobert Mustacchi int i; 681*6716431bSRobert Mustacchi uint8_t old; 682*6716431bSRobert Mustacchi uint_t new; 683*6716431bSRobert Mustacchi uint8_t reg; 684*6716431bSRobert Mustacchi int err; 685*6716431bSRobert Mustacchi struct urf_dev *lp = dp->private; 686*6716431bSRobert Mustacchi 687*6716431bSRobert Mustacchi /* 688*6716431bSRobert Mustacchi * setup flow control bit in eeprom 689*6716431bSRobert Mustacchi */ 690*6716431bSRobert Mustacchi IN(dp, URF_EEPROM_BASE + 9, &old, &err, usberr); 691*6716431bSRobert Mustacchi 692*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: eeprom offset 9: %02x", dp->name, old)); 693*6716431bSRobert Mustacchi 694*6716431bSRobert Mustacchi if (dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE) { 695*6716431bSRobert Mustacchi /* enable PAUSE bit */ 696*6716431bSRobert Mustacchi new = old | 0x04; 697*6716431bSRobert Mustacchi } else { 698*6716431bSRobert Mustacchi /* clear PAUSE bit */ 699*6716431bSRobert Mustacchi new = old & ~0x04; 700*6716431bSRobert Mustacchi } 701*6716431bSRobert Mustacchi if (new != old) { 702*6716431bSRobert Mustacchi /* make eeprom writable */ 703*6716431bSRobert Mustacchi OUTB(dp, CR, lp->cr | CR_WEPROM, &err, usberr); 704*6716431bSRobert Mustacchi 705*6716431bSRobert Mustacchi /* eerom allows only word access for writing */ 706*6716431bSRobert Mustacchi IN(dp, URF_EEPROM_BASE + 8, ®, &err, usberr); 707*6716431bSRobert Mustacchi new = (new << 8) | reg; 708*6716431bSRobert Mustacchi 709*6716431bSRobert Mustacchi OUTW(dp, URF_EEPROM_BASE + 8, new, &err, usberr); 710*6716431bSRobert Mustacchi 711*6716431bSRobert Mustacchi /* make eeprom non-writable */ 712*6716431bSRobert Mustacchi OUTB(dp, CR, lp->cr, &err, usberr); 713*6716431bSRobert Mustacchi } 714*6716431bSRobert Mustacchi 715*6716431bSRobert Mustacchi /* 716*6716431bSRobert Mustacchi * load EEPROM contents into nic 717*6716431bSRobert Mustacchi */ 718*6716431bSRobert Mustacchi OUTB(dp, CR, lp->cr | CR_AUTOLOAD, &err, usberr); 719*6716431bSRobert Mustacchi CHECK_AND_JUMP(err, usberr); 720*6716431bSRobert Mustacchi 721*6716431bSRobert Mustacchi for (i = 0; i < 100; i++) { 722*6716431bSRobert Mustacchi IN(dp, CR, ®, &err, usberr); 723*6716431bSRobert Mustacchi if ((reg & CR_AUTOLOAD) == 0) { 724*6716431bSRobert Mustacchi goto autoload_done; 725*6716431bSRobert Mustacchi } 726*6716431bSRobert Mustacchi } 727*6716431bSRobert Mustacchi /* timeout */ 728*6716431bSRobert Mustacchi cmn_err(CE_WARN, "%s: %s: failed to autoload: timeout", 729*6716431bSRobert Mustacchi dp->name, __func__); 730*6716431bSRobert Mustacchi goto usberr; 731*6716431bSRobert Mustacchi 732*6716431bSRobert Mustacchi autoload_done: 733*6716431bSRobert Mustacchi /* 734*6716431bSRobert Mustacchi * mac address in EEPROM has loaded to ID registers. 735*6716431bSRobert Mustacchi */ 736*6716431bSRobert Mustacchi INS(dp, IDR, dp->dev_addr.ether_addr_octet, ETHERADDRL, &err, usberr); 737*6716431bSRobert Mustacchi 738*6716431bSRobert Mustacchi /* no need to scan phy */ 739*6716431bSRobert Mustacchi dp->mii_phy_addr = -1; 740*6716431bSRobert Mustacchi 741*6716431bSRobert Mustacchi #if DEBUG_LEVEL > 2 742*6716431bSRobert Mustacchi urf_eeprom_dump(dp, 0x80); 743*6716431bSRobert Mustacchi #endif 744*6716431bSRobert Mustacchi 745*6716431bSRobert Mustacchi #ifdef CONFIG_VLAN 746*6716431bSRobert Mustacchi dp->misc_flag = USBGEM_VLAN; 747*6716431bSRobert Mustacchi #endif 748*6716431bSRobert Mustacchi return (USB_SUCCESS); 749*6716431bSRobert Mustacchi 750*6716431bSRobert Mustacchi usberr: 751*6716431bSRobert Mustacchi cmn_err(CE_WARN, "%s: urf_attach_chip: usb error detected", dp->name); 752*6716431bSRobert Mustacchi return (USB_FAILURE); 753*6716431bSRobert Mustacchi } 754*6716431bSRobert Mustacchi 755*6716431bSRobert Mustacchi static int 756*6716431bSRobert Mustacchi urfattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 757*6716431bSRobert Mustacchi { 758*6716431bSRobert Mustacchi int i; 759*6716431bSRobert Mustacchi ddi_iblock_cookie_t c; 760*6716431bSRobert Mustacchi int ret; 761*6716431bSRobert Mustacchi int unit; 762*6716431bSRobert Mustacchi struct chip_info *p; 763*6716431bSRobert Mustacchi const char *drv_name; 764*6716431bSRobert Mustacchi struct usbgem_dev *dp; 765*6716431bSRobert Mustacchi void *base; 766*6716431bSRobert Mustacchi struct usbgem_conf *ugcp; 767*6716431bSRobert Mustacchi struct urf_dev *lp; 768*6716431bSRobert Mustacchi 769*6716431bSRobert Mustacchi unit = ddi_get_instance(dip); 770*6716431bSRobert Mustacchi drv_name = ddi_driver_name(dip); 771*6716431bSRobert Mustacchi 772*6716431bSRobert Mustacchi DPRINTF(3, (CE_CONT, "!%s%d: %s: called, cmd:%d", 773*6716431bSRobert Mustacchi drv_name, __func__, unit, cmd)); 774*6716431bSRobert Mustacchi 775*6716431bSRobert Mustacchi if (cmd == DDI_ATTACH) { 776*6716431bSRobert Mustacchi /* 777*6716431bSRobert Mustacchi * Check if the chip is supported. 778*6716431bSRobert Mustacchi */ 779*6716431bSRobert Mustacchi 780*6716431bSRobert Mustacchi /* 781*6716431bSRobert Mustacchi * Check the chip if it is really realtek rtl8150 782*6716431bSRobert Mustacchi */ 783*6716431bSRobert Mustacchi 784*6716431bSRobert Mustacchi /* 785*6716431bSRobert Mustacchi * construct usbgem configration 786*6716431bSRobert Mustacchi */ 787*6716431bSRobert Mustacchi ugcp = kmem_zalloc(sizeof (*ugcp), KM_SLEEP); 788*6716431bSRobert Mustacchi 789*6716431bSRobert Mustacchi /* name */ 790*6716431bSRobert Mustacchi (void) sprintf(ugcp->usbgc_name, 791*6716431bSRobert Mustacchi "%s%d(ppa=%d)", drv_name, unit, urf_ppa); 792*6716431bSRobert Mustacchi #ifdef USBGEM_CONFIG_GLDv3 793*6716431bSRobert Mustacchi ugcp->usbgc_ppa = urf_ppa; 794*6716431bSRobert Mustacchi #else 795*6716431bSRobert Mustacchi ugcp->usbgc_ppa = unit; 796*6716431bSRobert Mustacchi #endif 797*6716431bSRobert Mustacchi ugcp->usbgc_ifnum = 0; 798*6716431bSRobert Mustacchi ugcp->usbgc_alt = 0; 799*6716431bSRobert Mustacchi 800*6716431bSRobert Mustacchi ugcp->usbgc_tx_list_max = 16; 801*6716431bSRobert Mustacchi 802*6716431bSRobert Mustacchi /* the rx status partially replaces FCS */ 803*6716431bSRobert Mustacchi ugcp->usbgc_rx_header_len = 0; 804*6716431bSRobert Mustacchi ugcp->usbgc_rx_list_max = 64; 805*6716431bSRobert Mustacchi 806*6716431bSRobert Mustacchi /* time out parameters */ 807*6716431bSRobert Mustacchi ugcp->usbgc_tx_timeout = USBGEM_TX_TIMEOUT; 808*6716431bSRobert Mustacchi ugcp->usbgc_tx_timeout_interval = ONESEC; 809*6716431bSRobert Mustacchi 810*6716431bSRobert Mustacchi /* flow control */ 811*6716431bSRobert Mustacchi ugcp->usbgc_flow_control = FLOW_CONTROL_RX_PAUSE; 812*6716431bSRobert Mustacchi 813*6716431bSRobert Mustacchi /* MII timeout parameters */ 814*6716431bSRobert Mustacchi ugcp->usbgc_mii_link_watch_interval = ONESEC; 815*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_watch_interval = ONESEC/5; 816*6716431bSRobert Mustacchi ugcp->usbgc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */ 817*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_timeout = MII_AN_TIMEOUT; /* 5 sec */ 818*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_wait = (25*ONESEC)/10; 819*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT; 820*6716431bSRobert Mustacchi 821*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_delay = ONESEC/10; 822*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_action = MII_ACTION_RSA; 823*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_timeout_action = MII_ACTION_RESET; 824*6716431bSRobert Mustacchi ugcp->usbgc_mii_dont_reset = B_FALSE; 825*6716431bSRobert Mustacchi 826*6716431bSRobert Mustacchi /* I/O methods */ 827*6716431bSRobert Mustacchi 828*6716431bSRobert Mustacchi /* mac operation */ 829*6716431bSRobert Mustacchi ugcp->usbgc_attach_chip = &urf_attach_chip; 830*6716431bSRobert Mustacchi ugcp->usbgc_reset_chip = &urf_reset_chip; 831*6716431bSRobert Mustacchi ugcp->usbgc_init_chip = &urf_init_chip; 832*6716431bSRobert Mustacchi ugcp->usbgc_start_chip = &urf_start_chip; 833*6716431bSRobert Mustacchi ugcp->usbgc_stop_chip = &urf_stop_chip; 834*6716431bSRobert Mustacchi ugcp->usbgc_multicast_hash = &urf_mcast_hash; 835*6716431bSRobert Mustacchi 836*6716431bSRobert Mustacchi ugcp->usbgc_set_rx_filter = &urf_set_rx_filter; 837*6716431bSRobert Mustacchi ugcp->usbgc_set_media = &urf_set_media; 838*6716431bSRobert Mustacchi ugcp->usbgc_get_stats = &urf_get_stats; 839*6716431bSRobert Mustacchi #ifdef notdef 840*6716431bSRobert Mustacchi ugcp->usbgc_interrupt = &urf_interrupt; 841*6716431bSRobert Mustacchi #else 842*6716431bSRobert Mustacchi ugcp->usbgc_interrupt = NULL; 843*6716431bSRobert Mustacchi #endif 844*6716431bSRobert Mustacchi /* packet operation */ 845*6716431bSRobert Mustacchi ugcp->usbgc_tx_make_packet = &urf_tx_make_packet; 846*6716431bSRobert Mustacchi ugcp->usbgc_rx_make_packet = &urf_rx_make_packet; 847*6716431bSRobert Mustacchi 848*6716431bSRobert Mustacchi /* mii operations */ 849*6716431bSRobert Mustacchi ugcp->usbgc_mii_probe = &usbgem_mii_probe_default; 850*6716431bSRobert Mustacchi ugcp->usbgc_mii_init = &usbgem_mii_init_default; 851*6716431bSRobert Mustacchi ugcp->usbgc_mii_config = &usbgem_mii_config_default; 852*6716431bSRobert Mustacchi ugcp->usbgc_mii_read = &urf_mii_read; 853*6716431bSRobert Mustacchi ugcp->usbgc_mii_write = &urf_mii_write; 854*6716431bSRobert Mustacchi 855*6716431bSRobert Mustacchi /* mtu */ 856*6716431bSRobert Mustacchi ugcp->usbgc_min_mtu = ETHERMTU; 857*6716431bSRobert Mustacchi ugcp->usbgc_max_mtu = ETHERMTU; 858*6716431bSRobert Mustacchi ugcp->usbgc_default_mtu = ETHERMTU; 859*6716431bSRobert Mustacchi 860*6716431bSRobert Mustacchi lp = kmem_zalloc(sizeof (struct urf_dev), KM_SLEEP); 861*6716431bSRobert Mustacchi lp->chip = NULL; 862*6716431bSRobert Mustacchi 863*6716431bSRobert Mustacchi ddi_set_driver_private(dip, NULL); 864*6716431bSRobert Mustacchi 865*6716431bSRobert Mustacchi dp = usbgem_do_attach(dip, ugcp, lp, sizeof (struct urf_dev)); 866*6716431bSRobert Mustacchi 867*6716431bSRobert Mustacchi kmem_free(ugcp, sizeof (*ugcp)); 868*6716431bSRobert Mustacchi 869*6716431bSRobert Mustacchi if (dp != NULL) { 870*6716431bSRobert Mustacchi urf_ppa++; 871*6716431bSRobert Mustacchi return (DDI_SUCCESS); 872*6716431bSRobert Mustacchi } 873*6716431bSRobert Mustacchi 874*6716431bSRobert Mustacchi err_free_mem: 875*6716431bSRobert Mustacchi kmem_free(lp, sizeof (struct urf_dev)); 876*6716431bSRobert Mustacchi err_close_pipe: 877*6716431bSRobert Mustacchi err: 878*6716431bSRobert Mustacchi return (DDI_FAILURE); 879*6716431bSRobert Mustacchi } 880*6716431bSRobert Mustacchi if (cmd == DDI_RESUME) { 881*6716431bSRobert Mustacchi return (usbgem_resume(dip)); 882*6716431bSRobert Mustacchi } 883*6716431bSRobert Mustacchi return (DDI_FAILURE); 884*6716431bSRobert Mustacchi } 885*6716431bSRobert Mustacchi 886*6716431bSRobert Mustacchi static int 887*6716431bSRobert Mustacchi urfdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 888*6716431bSRobert Mustacchi { 889*6716431bSRobert Mustacchi int ret; 890*6716431bSRobert Mustacchi 891*6716431bSRobert Mustacchi if (cmd == DDI_DETACH) { 892*6716431bSRobert Mustacchi ret = usbgem_do_detach(dip); 893*6716431bSRobert Mustacchi if (ret != DDI_SUCCESS) { 894*6716431bSRobert Mustacchi return (DDI_FAILURE); 895*6716431bSRobert Mustacchi } 896*6716431bSRobert Mustacchi urf_ppa--; 897*6716431bSRobert Mustacchi return (DDI_SUCCESS); 898*6716431bSRobert Mustacchi } 899*6716431bSRobert Mustacchi if (cmd == DDI_SUSPEND) { 900*6716431bSRobert Mustacchi return (usbgem_suspend(dip)); 901*6716431bSRobert Mustacchi } 902*6716431bSRobert Mustacchi return (DDI_FAILURE); 903*6716431bSRobert Mustacchi } 904*6716431bSRobert Mustacchi 905*6716431bSRobert Mustacchi /* ======================================================== */ 906*6716431bSRobert Mustacchi /* 907*6716431bSRobert Mustacchi * OS depend (loadable streams driver) routine 908*6716431bSRobert Mustacchi */ 909*6716431bSRobert Mustacchi /* ======================================================== */ 910*6716431bSRobert Mustacchi #ifdef USBGEM_CONFIG_GLDv3 911*6716431bSRobert Mustacchi USBGEM_STREAM_OPS(urf_ops, urfattach, urfdetach); 912*6716431bSRobert Mustacchi #else 913*6716431bSRobert Mustacchi static struct module_info urfminfo = { 914*6716431bSRobert Mustacchi 0, /* mi_idnum */ 915*6716431bSRobert Mustacchi "urf", /* mi_idname */ 916*6716431bSRobert Mustacchi 0, /* mi_minpsz */ 917*6716431bSRobert Mustacchi ETHERMTU, /* mi_maxpsz */ 918*6716431bSRobert Mustacchi ETHERMTU*128, /* mi_hiwat */ 919*6716431bSRobert Mustacchi 1, /* mi_lowat */ 920*6716431bSRobert Mustacchi }; 921*6716431bSRobert Mustacchi 922*6716431bSRobert Mustacchi static struct qinit urfrinit = { 923*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_putp */ 924*6716431bSRobert Mustacchi usbgem_rsrv, /* qi_srvp */ 925*6716431bSRobert Mustacchi usbgem_open, /* qi_qopen */ 926*6716431bSRobert Mustacchi usbgem_close, /* qi_qclose */ 927*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qadmin */ 928*6716431bSRobert Mustacchi &urfminfo, /* qi_minfo */ 929*6716431bSRobert Mustacchi NULL /* qi_mstat */ 930*6716431bSRobert Mustacchi }; 931*6716431bSRobert Mustacchi 932*6716431bSRobert Mustacchi static struct qinit urfwinit = { 933*6716431bSRobert Mustacchi usbgem_wput, /* qi_putp */ 934*6716431bSRobert Mustacchi usbgem_wsrv, /* qi_srvp */ 935*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qopen */ 936*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qclose */ 937*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qadmin */ 938*6716431bSRobert Mustacchi &urfminfo, /* qi_minfo */ 939*6716431bSRobert Mustacchi NULL /* qi_mstat */ 940*6716431bSRobert Mustacchi }; 941*6716431bSRobert Mustacchi 942*6716431bSRobert Mustacchi static struct streamtab urf_info = { 943*6716431bSRobert Mustacchi &urfrinit, /* st_rdinit */ 944*6716431bSRobert Mustacchi &urfwinit, /* st_wrinit */ 945*6716431bSRobert Mustacchi NULL, /* st_muxrinit */ 946*6716431bSRobert Mustacchi NULL /* st_muxwrinit */ 947*6716431bSRobert Mustacchi }; 948*6716431bSRobert Mustacchi 949*6716431bSRobert Mustacchi static struct cb_ops cb_urf_ops = { 950*6716431bSRobert Mustacchi nulldev, /* cb_open */ 951*6716431bSRobert Mustacchi nulldev, /* cb_close */ 952*6716431bSRobert Mustacchi nodev, /* cb_strategy */ 953*6716431bSRobert Mustacchi nodev, /* cb_print */ 954*6716431bSRobert Mustacchi nodev, /* cb_dump */ 955*6716431bSRobert Mustacchi nodev, /* cb_read */ 956*6716431bSRobert Mustacchi nodev, /* cb_write */ 957*6716431bSRobert Mustacchi nodev, /* cb_ioctl */ 958*6716431bSRobert Mustacchi nodev, /* cb_devmap */ 959*6716431bSRobert Mustacchi nodev, /* cb_mmap */ 960*6716431bSRobert Mustacchi nodev, /* cb_segmap */ 961*6716431bSRobert Mustacchi nochpoll, /* cb_chpoll */ 962*6716431bSRobert Mustacchi ddi_prop_op, /* cb_prop_op */ 963*6716431bSRobert Mustacchi &urf_info, /* cb_stream */ 964*6716431bSRobert Mustacchi D_NEW|D_MP /* cb_flag */ 965*6716431bSRobert Mustacchi }; 966*6716431bSRobert Mustacchi 967*6716431bSRobert Mustacchi static struct dev_ops urf_ops = { 968*6716431bSRobert Mustacchi DEVO_REV, /* devo_rev */ 969*6716431bSRobert Mustacchi 0, /* devo_refcnt */ 970*6716431bSRobert Mustacchi usbgem_getinfo, /* devo_getinfo */ 971*6716431bSRobert Mustacchi nulldev, /* devo_identify */ 972*6716431bSRobert Mustacchi nulldev, /* devo_probe */ 973*6716431bSRobert Mustacchi urfattach, /* devo_attach */ 974*6716431bSRobert Mustacchi urfdetach, /* devo_detach */ 975*6716431bSRobert Mustacchi nodev, /* devo_reset */ 976*6716431bSRobert Mustacchi &cb_urf_ops, /* devo_cb_ops */ 977*6716431bSRobert Mustacchi NULL, /* devo_bus_ops */ 978*6716431bSRobert Mustacchi usbgem_power, /* devo_power */ 979*6716431bSRobert Mustacchi #if DEVO_REV >= 4 980*6716431bSRobert Mustacchi usbgem_quiesce, /* devo_quiesce */ 981*6716431bSRobert Mustacchi #endif 982*6716431bSRobert Mustacchi 983*6716431bSRobert Mustacchi }; 984*6716431bSRobert Mustacchi #endif 985*6716431bSRobert Mustacchi 986*6716431bSRobert Mustacchi static struct modldrv modldrv = { 987*6716431bSRobert Mustacchi &mod_driverops, /* Type of module. This one is a driver */ 988*6716431bSRobert Mustacchi ident, 989*6716431bSRobert Mustacchi &urf_ops, /* driver ops */ 990*6716431bSRobert Mustacchi }; 991*6716431bSRobert Mustacchi 992*6716431bSRobert Mustacchi static struct modlinkage modlinkage = { 993*6716431bSRobert Mustacchi MODREV_1, &modldrv, NULL 994*6716431bSRobert Mustacchi }; 995*6716431bSRobert Mustacchi 996*6716431bSRobert Mustacchi /* ======================================================== */ 997*6716431bSRobert Mustacchi /* 998*6716431bSRobert Mustacchi * _init : done 999*6716431bSRobert Mustacchi */ 1000*6716431bSRobert Mustacchi /* ======================================================== */ 1001*6716431bSRobert Mustacchi int 1002*6716431bSRobert Mustacchi _init(void) 1003*6716431bSRobert Mustacchi { 1004*6716431bSRobert Mustacchi int status; 1005*6716431bSRobert Mustacchi 1006*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!urf: _init: called")); 1007*6716431bSRobert Mustacchi 1008*6716431bSRobert Mustacchi status = usbgem_mod_init(&urf_ops, "urf"); 1009*6716431bSRobert Mustacchi if (status != DDI_SUCCESS) { 1010*6716431bSRobert Mustacchi return (status); 1011*6716431bSRobert Mustacchi } 1012*6716431bSRobert Mustacchi status = mod_install(&modlinkage); 1013*6716431bSRobert Mustacchi if (status != DDI_SUCCESS) { 1014*6716431bSRobert Mustacchi usbgem_mod_fini(&urf_ops); 1015*6716431bSRobert Mustacchi } 1016*6716431bSRobert Mustacchi return (status); 1017*6716431bSRobert Mustacchi } 1018*6716431bSRobert Mustacchi 1019*6716431bSRobert Mustacchi /* 1020*6716431bSRobert Mustacchi * _fini : done 1021*6716431bSRobert Mustacchi */ 1022*6716431bSRobert Mustacchi int 1023*6716431bSRobert Mustacchi _fini(void) 1024*6716431bSRobert Mustacchi { 1025*6716431bSRobert Mustacchi int status; 1026*6716431bSRobert Mustacchi 1027*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!urf: _fini: called")); 1028*6716431bSRobert Mustacchi status = mod_remove(&modlinkage); 1029*6716431bSRobert Mustacchi if (status == DDI_SUCCESS) { 1030*6716431bSRobert Mustacchi usbgem_mod_fini(&urf_ops); 1031*6716431bSRobert Mustacchi } 1032*6716431bSRobert Mustacchi return (status); 1033*6716431bSRobert Mustacchi } 1034*6716431bSRobert Mustacchi 1035*6716431bSRobert Mustacchi int 1036*6716431bSRobert Mustacchi _info(struct modinfo *modinfop) 1037*6716431bSRobert Mustacchi { 1038*6716431bSRobert Mustacchi return (mod_info(&modlinkage, modinfop)); 1039*6716431bSRobert Mustacchi } 1040