1*6716431bSRobert Mustacchi /* 2*6716431bSRobert Mustacchi * udmfE_usbgem.c : Davicom DM9601E USB to Fast Ethernet Driver for Solaris 3*6716431bSRobert Mustacchi * 4*6716431bSRobert Mustacchi * Copyright (c) 2009-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/strsun.h> 66*6716431bSRobert Mustacchi #include <sys/usb/usba.h> 67*6716431bSRobert Mustacchi #include "usbgem.h" 68*6716431bSRobert Mustacchi 69*6716431bSRobert Mustacchi /* hardware stuff */ 70*6716431bSRobert Mustacchi #include "usbgem_mii.h" 71*6716431bSRobert Mustacchi #include "dm9601reg.h" 72*6716431bSRobert Mustacchi 73*6716431bSRobert Mustacchi char ident[] = "dm9601 usbnic driver v" VERSION; 74*6716431bSRobert Mustacchi 75*6716431bSRobert Mustacchi /* 76*6716431bSRobert Mustacchi * Useful macros 77*6716431bSRobert Mustacchi */ 78*6716431bSRobert Mustacchi #define CHECK_AND_JUMP(err, label) if (err != USB_SUCCESS) goto label 79*6716431bSRobert Mustacchi #define LE16P(p) ((((uint8_t *)(p))[1] << 8) | ((uint8_t *)(p))[0]) 80*6716431bSRobert Mustacchi 81*6716431bSRobert Mustacchi /* 82*6716431bSRobert Mustacchi * Debugging 83*6716431bSRobert Mustacchi */ 84*6716431bSRobert Mustacchi #ifdef DEBUG_LEVEL 85*6716431bSRobert Mustacchi static int udmf_debug = DEBUG_LEVEL; 86*6716431bSRobert Mustacchi #define DPRINTF(n, args) if (udmf_debug > (n)) cmn_err args 87*6716431bSRobert Mustacchi #else 88*6716431bSRobert Mustacchi #define DPRINTF(n, args) 89*6716431bSRobert Mustacchi #endif 90*6716431bSRobert Mustacchi 91*6716431bSRobert Mustacchi /* 92*6716431bSRobert Mustacchi * Our configration for dm9601 93*6716431bSRobert Mustacchi */ 94*6716431bSRobert Mustacchi /* timeouts */ 95*6716431bSRobert Mustacchi #define ONESEC (drv_usectohz(1*1000000)) 96*6716431bSRobert Mustacchi 97*6716431bSRobert Mustacchi /* 98*6716431bSRobert Mustacchi * Local device definitions 99*6716431bSRobert Mustacchi */ 100*6716431bSRobert Mustacchi struct udmf_dev { 101*6716431bSRobert Mustacchi /* 102*6716431bSRobert Mustacchi * Misc HW information 103*6716431bSRobert Mustacchi */ 104*6716431bSRobert Mustacchi uint8_t rcr; 105*6716431bSRobert Mustacchi uint8_t last_nsr; 106*6716431bSRobert Mustacchi uint8_t mac_addr[ETHERADDRL]; 107*6716431bSRobert Mustacchi }; 108*6716431bSRobert Mustacchi 109*6716431bSRobert Mustacchi /* 110*6716431bSRobert Mustacchi * private functions 111*6716431bSRobert Mustacchi */ 112*6716431bSRobert Mustacchi 113*6716431bSRobert Mustacchi /* mii operations */ 114*6716431bSRobert Mustacchi static uint16_t udmf_mii_read(struct usbgem_dev *, uint_t, int *errp); 115*6716431bSRobert Mustacchi static void udmf_mii_write(struct usbgem_dev *, uint_t, uint16_t, int *errp); 116*6716431bSRobert Mustacchi 117*6716431bSRobert Mustacchi /* nic operations */ 118*6716431bSRobert Mustacchi static int udmf_reset_chip(struct usbgem_dev *); 119*6716431bSRobert Mustacchi static int udmf_init_chip(struct usbgem_dev *); 120*6716431bSRobert Mustacchi static int udmf_start_chip(struct usbgem_dev *); 121*6716431bSRobert Mustacchi static int udmf_stop_chip(struct usbgem_dev *); 122*6716431bSRobert Mustacchi static int udmf_set_media(struct usbgem_dev *); 123*6716431bSRobert Mustacchi static int udmf_set_rx_filter(struct usbgem_dev *); 124*6716431bSRobert Mustacchi static int udmf_get_stats(struct usbgem_dev *); 125*6716431bSRobert Mustacchi static void udmf_interrupt(struct usbgem_dev *, mblk_t *); 126*6716431bSRobert Mustacchi 127*6716431bSRobert Mustacchi /* packet operations */ 128*6716431bSRobert Mustacchi static mblk_t *udmf_tx_make_packet(struct usbgem_dev *, mblk_t *); 129*6716431bSRobert Mustacchi static mblk_t *udmf_rx_make_packet(struct usbgem_dev *, mblk_t *); 130*6716431bSRobert Mustacchi 131*6716431bSRobert Mustacchi /* =============================================================== */ 132*6716431bSRobert Mustacchi /* 133*6716431bSRobert Mustacchi * I/O functions 134*6716431bSRobert Mustacchi */ 135*6716431bSRobert Mustacchi /* =============================================================== */ 136*6716431bSRobert Mustacchi #define OUT(dp, ix, len, buf, errp, label) \ 137*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_out((dp), \ 138*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \ 139*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 140*6716431bSRobert Mustacchi /* bRequest */ 1, \ 141*6716431bSRobert Mustacchi /* wValue */ 0, \ 142*6716431bSRobert Mustacchi /* wIndex */ (ix), \ 143*6716431bSRobert Mustacchi /* wLength */ (len), \ 144*6716431bSRobert Mustacchi /* value */ (buf), \ 145*6716431bSRobert Mustacchi /* size */ (len))) != USB_SUCCESS) goto label 146*6716431bSRobert Mustacchi 147*6716431bSRobert Mustacchi #define OUTB(dp, ix, val, errp, label) \ 148*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_out((dp), \ 149*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \ 150*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 151*6716431bSRobert Mustacchi /* bRequest */ 3, \ 152*6716431bSRobert Mustacchi /* wValue */ (val), \ 153*6716431bSRobert Mustacchi /* wIndex */ (ix), \ 154*6716431bSRobert Mustacchi /* wLength */ 0, \ 155*6716431bSRobert Mustacchi /* value */ NULL, \ 156*6716431bSRobert Mustacchi /* size */ 0)) != USB_SUCCESS) goto label 157*6716431bSRobert Mustacchi 158*6716431bSRobert Mustacchi #define IN(dp, ix, len, buf, errp, label) \ 159*6716431bSRobert Mustacchi if ((*(errp) = usbgem_ctrl_in((dp), \ 160*6716431bSRobert Mustacchi /* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST \ 161*6716431bSRobert Mustacchi | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV, \ 162*6716431bSRobert Mustacchi /* bRequest */ 0, \ 163*6716431bSRobert Mustacchi /* wValue */ 0, \ 164*6716431bSRobert Mustacchi /* wIndex */ (ix), \ 165*6716431bSRobert Mustacchi /* wLength */ (len), \ 166*6716431bSRobert Mustacchi /* valuep */ (buf), \ 167*6716431bSRobert Mustacchi /* size */ (len))) != USB_SUCCESS) goto label 168*6716431bSRobert Mustacchi 169*6716431bSRobert Mustacchi /* =============================================================== */ 170*6716431bSRobert Mustacchi /* 171*6716431bSRobert Mustacchi * Hardware manupilation 172*6716431bSRobert Mustacchi */ 173*6716431bSRobert Mustacchi /* =============================================================== */ 174*6716431bSRobert Mustacchi static void 175*6716431bSRobert Mustacchi udmf_enable_phy(struct usbgem_dev *dp) 176*6716431bSRobert Mustacchi { 177*6716431bSRobert Mustacchi int err = USB_SUCCESS; 178*6716431bSRobert Mustacchi 179*6716431bSRobert Mustacchi /* de-assert reset signal to phy */ 180*6716431bSRobert Mustacchi OUTB(dp, GPCR, GPCR_OUT(0), &err, usberr); 181*6716431bSRobert Mustacchi OUTB(dp, GPR, 0, &err, usberr); 182*6716431bSRobert Mustacchi usberr: 183*6716431bSRobert Mustacchi ; 184*6716431bSRobert Mustacchi } 185*6716431bSRobert Mustacchi 186*6716431bSRobert Mustacchi static int 187*6716431bSRobert Mustacchi udmf_reset_chip(struct usbgem_dev *dp) 188*6716431bSRobert Mustacchi { 189*6716431bSRobert Mustacchi int err = USB_SUCCESS; 190*6716431bSRobert Mustacchi 191*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 192*6716431bSRobert Mustacchi 193*6716431bSRobert Mustacchi OUTB(dp, NCR, NCR_LBK_NORMAL | NCR_RST, &err, usberr); 194*6716431bSRobert Mustacchi drv_usecwait(100); 195*6716431bSRobert Mustacchi usberr: 196*6716431bSRobert Mustacchi return (err); 197*6716431bSRobert Mustacchi } 198*6716431bSRobert Mustacchi 199*6716431bSRobert Mustacchi /* 200*6716431bSRobert Mustacchi * Setup dm9601 201*6716431bSRobert Mustacchi */ 202*6716431bSRobert Mustacchi static int 203*6716431bSRobert Mustacchi udmf_init_chip(struct usbgem_dev *dp) 204*6716431bSRobert Mustacchi { 205*6716431bSRobert Mustacchi int i; 206*6716431bSRobert Mustacchi uint32_t val; 207*6716431bSRobert Mustacchi int err = USB_SUCCESS; 208*6716431bSRobert Mustacchi uint16_t reg; 209*6716431bSRobert Mustacchi uint8_t buf[2]; 210*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 211*6716431bSRobert Mustacchi 212*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 213*6716431bSRobert Mustacchi 214*6716431bSRobert Mustacchi OUTB(dp, NCR, NCR_LBK_NORMAL, &err, usberr); 215*6716431bSRobert Mustacchi 216*6716431bSRobert Mustacchi /* tx control regiser: enable padding and crc generation */ 217*6716431bSRobert Mustacchi OUTB(dp, TCR, 0, &err, usberr); 218*6716431bSRobert Mustacchi 219*6716431bSRobert Mustacchi /* rx control register: will be set later by udmf_set_rx_filer() */ 220*6716431bSRobert Mustacchi lp->rcr = RCR_RUNT; 221*6716431bSRobert Mustacchi 222*6716431bSRobert Mustacchi /* back pressure threshold: */ 223*6716431bSRobert Mustacchi OUTB(dp, BPTR, (2 << BPTR_BPHW_SHIFT) | BPTR_JPT_200us, 224*6716431bSRobert Mustacchi &err, usberr); 225*6716431bSRobert Mustacchi 226*6716431bSRobert Mustacchi /* flow control threshold: same as default */ 227*6716431bSRobert Mustacchi OUTB(dp, FCTR, (3 << FCTR_HWOT_SHIFT) | (8 << FCTR_LWOT_SHIFT), 228*6716431bSRobert Mustacchi &err, usberr); 229*6716431bSRobert Mustacchi 230*6716431bSRobert Mustacchi /* usb control register */ 231*6716431bSRobert Mustacchi OUTB(dp, USBC, USBC_EP3ACK | 0x06, &err, usberr); 232*6716431bSRobert Mustacchi 233*6716431bSRobert Mustacchi /* flow control: will be set later by udmf_set_media() */ 234*6716431bSRobert Mustacchi 235*6716431bSRobert Mustacchi /* wake up control register: */ 236*6716431bSRobert Mustacchi OUTB(dp, WCR, 0, &err, usberr); 237*6716431bSRobert Mustacchi 238*6716431bSRobert Mustacchi usberr: 239*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 240*6716431bSRobert Mustacchi dp->name, __func__, 241*6716431bSRobert Mustacchi err, err == USB_SUCCESS ? "success" : "error")); 242*6716431bSRobert Mustacchi return (err); 243*6716431bSRobert Mustacchi } 244*6716431bSRobert Mustacchi 245*6716431bSRobert Mustacchi static int 246*6716431bSRobert Mustacchi udmf_start_chip(struct usbgem_dev *dp) 247*6716431bSRobert Mustacchi { 248*6716431bSRobert Mustacchi int err = USB_SUCCESS; 249*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 250*6716431bSRobert Mustacchi 251*6716431bSRobert Mustacchi /* enable Rx */ 252*6716431bSRobert Mustacchi lp->rcr |= RCR_RXEN; 253*6716431bSRobert Mustacchi OUTB(dp, RCR, lp->rcr, &err, usberr); 254*6716431bSRobert Mustacchi 255*6716431bSRobert Mustacchi usberr: 256*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 257*6716431bSRobert Mustacchi dp->name, __func__, 258*6716431bSRobert Mustacchi err, err == USB_SUCCESS ? "success" : "error")); 259*6716431bSRobert Mustacchi return (err); 260*6716431bSRobert Mustacchi } 261*6716431bSRobert Mustacchi 262*6716431bSRobert Mustacchi static int 263*6716431bSRobert Mustacchi udmf_stop_chip(struct usbgem_dev *dp) 264*6716431bSRobert Mustacchi { 265*6716431bSRobert Mustacchi int err = USB_SUCCESS; 266*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 267*6716431bSRobert Mustacchi 268*6716431bSRobert Mustacchi /* disable rx */ 269*6716431bSRobert Mustacchi lp->rcr &= ~RCR_RXEN; 270*6716431bSRobert Mustacchi OUTB(dp, RCR, lp->rcr, &err, usberr); 271*6716431bSRobert Mustacchi 272*6716431bSRobert Mustacchi usberr: 273*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 274*6716431bSRobert Mustacchi dp->name, __func__, 275*6716431bSRobert Mustacchi err, err == USB_SUCCESS ? "success" : "error")); 276*6716431bSRobert Mustacchi return (err); 277*6716431bSRobert Mustacchi } 278*6716431bSRobert Mustacchi 279*6716431bSRobert Mustacchi static int 280*6716431bSRobert Mustacchi udmf_get_stats(struct usbgem_dev *dp) 281*6716431bSRobert Mustacchi { 282*6716431bSRobert Mustacchi /* empty */ 283*6716431bSRobert Mustacchi return (USB_SUCCESS); 284*6716431bSRobert Mustacchi } 285*6716431bSRobert Mustacchi 286*6716431bSRobert Mustacchi static uint_t 287*6716431bSRobert Mustacchi udmf_mcast_hash(struct usbgem_dev *dp, const uint8_t *addr) 288*6716431bSRobert Mustacchi { 289*6716431bSRobert Mustacchi return (usbgem_ether_crc_le(addr) & 0x3f); 290*6716431bSRobert Mustacchi } 291*6716431bSRobert Mustacchi 292*6716431bSRobert Mustacchi static int 293*6716431bSRobert Mustacchi udmf_set_rx_filter(struct usbgem_dev *dp) 294*6716431bSRobert Mustacchi { 295*6716431bSRobert Mustacchi int i; 296*6716431bSRobert Mustacchi uint8_t rcr; 297*6716431bSRobert Mustacchi uint8_t mode; 298*6716431bSRobert Mustacchi uint8_t mhash[8]; 299*6716431bSRobert Mustacchi uint8_t *mac; 300*6716431bSRobert Mustacchi uint_t h; 301*6716431bSRobert Mustacchi int err = USB_SUCCESS; 302*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 303*6716431bSRobert Mustacchi static uint8_t invalid_mac[ETHERADDRL] = {0, 0, 0, 0, 0, 0}; 304*6716431bSRobert Mustacchi 305*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called, rxmode:%x", 306*6716431bSRobert Mustacchi dp->name, __func__, dp->rxmode)); 307*6716431bSRobert Mustacchi 308*6716431bSRobert Mustacchi if (lp->rcr & RCR_RXEN) { 309*6716431bSRobert Mustacchi /* set promiscuous mode before changing rx filter mode */ 310*6716431bSRobert Mustacchi OUTB(dp, RCR, lp->rcr | RCR_PRMSC, &err, usberr); 311*6716431bSRobert Mustacchi } 312*6716431bSRobert Mustacchi 313*6716431bSRobert Mustacchi lp->rcr &= ~(RCR_ALL | RCR_PRMSC); 314*6716431bSRobert Mustacchi mode = 0; 315*6716431bSRobert Mustacchi bzero(mhash, sizeof (mhash)); 316*6716431bSRobert Mustacchi mac = dp->cur_addr.ether_addr_octet; 317*6716431bSRobert Mustacchi 318*6716431bSRobert Mustacchi if ((dp->rxmode & RXMODE_ENABLE) == 0) { 319*6716431bSRobert Mustacchi mac = invalid_mac; 320*6716431bSRobert Mustacchi } else if (dp->rxmode & RXMODE_PROMISC) { 321*6716431bSRobert Mustacchi /* promiscious mode implies all multicast and all physical */ 322*6716431bSRobert Mustacchi mode |= RCR_PRMSC; 323*6716431bSRobert Mustacchi } else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 32) { 324*6716431bSRobert Mustacchi /* accept all multicast packets */ 325*6716431bSRobert Mustacchi mode |= RCR_ALL; 326*6716431bSRobert Mustacchi } else if (dp->mc_count > 0) { 327*6716431bSRobert Mustacchi /* 328*6716431bSRobert Mustacchi * make hash table to select interresting 329*6716431bSRobert Mustacchi * multicast address only. 330*6716431bSRobert Mustacchi */ 331*6716431bSRobert Mustacchi for (i = 0; i < dp->mc_count; i++) { 332*6716431bSRobert Mustacchi /* hash table is 64 = 2^6 bit width */ 333*6716431bSRobert Mustacchi h = dp->mc_list[i].hash; 334*6716431bSRobert Mustacchi mhash[h / 8] |= 1 << (h % 8); 335*6716431bSRobert Mustacchi } 336*6716431bSRobert Mustacchi } 337*6716431bSRobert Mustacchi 338*6716431bSRobert Mustacchi /* set node address */ 339*6716431bSRobert Mustacchi if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) { 340*6716431bSRobert Mustacchi OUT(dp, PAR, ETHERADDRL, dp->cur_addr.ether_addr_octet, 341*6716431bSRobert Mustacchi &err, usberr); 342*6716431bSRobert Mustacchi bcopy(mac, lp->mac_addr, ETHERADDRL); 343*6716431bSRobert Mustacchi } 344*6716431bSRobert Mustacchi 345*6716431bSRobert Mustacchi /* set multicast hash table */ 346*6716431bSRobert Mustacchi OUT(dp, MAR, sizeof (mhash), &mhash[0], &err, usberr); 347*6716431bSRobert Mustacchi 348*6716431bSRobert Mustacchi /* update rcr */ 349*6716431bSRobert Mustacchi lp->rcr |= mode; 350*6716431bSRobert Mustacchi OUTB(dp, RCR, lp->rcr, &err, usberr); 351*6716431bSRobert Mustacchi 352*6716431bSRobert Mustacchi #if DEBUG_LEVEL > 1 353*6716431bSRobert Mustacchi /* verify rcr */ 354*6716431bSRobert Mustacchi IN(dp, RCR, 1, &rcr, &err, usberr); 355*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!%s: %s: rcr:%b returned", 356*6716431bSRobert Mustacchi dp->name, __func__, rcr, RCR_BITS); 357*6716431bSRobert Mustacchi #endif 358*6716431bSRobert Mustacchi usberr: 359*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 360*6716431bSRobert Mustacchi dp->name, __func__, 361*6716431bSRobert Mustacchi err, err == USB_SUCCESS ? "success" : "error")); 362*6716431bSRobert Mustacchi return (err); 363*6716431bSRobert Mustacchi } 364*6716431bSRobert Mustacchi 365*6716431bSRobert Mustacchi static int 366*6716431bSRobert Mustacchi udmf_set_media(struct usbgem_dev *dp) 367*6716431bSRobert Mustacchi { 368*6716431bSRobert Mustacchi int err = USB_SUCCESS; 369*6716431bSRobert Mustacchi uint8_t fcr; 370*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 371*6716431bSRobert Mustacchi 372*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 373*6716431bSRobert Mustacchi 374*6716431bSRobert Mustacchi /* setup flow control */ 375*6716431bSRobert Mustacchi fcr = 0; 376*6716431bSRobert Mustacchi if (dp->full_duplex) { 377*6716431bSRobert Mustacchi /* select flow control */ 378*6716431bSRobert Mustacchi switch (dp->flow_control) { 379*6716431bSRobert Mustacchi case FLOW_CONTROL_RX_PAUSE: 380*6716431bSRobert Mustacchi fcr |= FCR_FLCE; 381*6716431bSRobert Mustacchi break; 382*6716431bSRobert Mustacchi 383*6716431bSRobert Mustacchi case FLOW_CONTROL_TX_PAUSE: 384*6716431bSRobert Mustacchi fcr |= FCR_TXPEN; 385*6716431bSRobert Mustacchi break; 386*6716431bSRobert Mustacchi 387*6716431bSRobert Mustacchi case FLOW_CONTROL_SYMMETRIC: 388*6716431bSRobert Mustacchi fcr |= FCR_FLCE | FCR_TXPEN; 389*6716431bSRobert Mustacchi break; 390*6716431bSRobert Mustacchi } 391*6716431bSRobert Mustacchi } 392*6716431bSRobert Mustacchi 393*6716431bSRobert Mustacchi /* update flow control register */ 394*6716431bSRobert Mustacchi OUTB(dp, FCR, fcr, &err, usberr); 395*6716431bSRobert Mustacchi 396*6716431bSRobert Mustacchi usberr: 397*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 398*6716431bSRobert Mustacchi dp->name, __func__, 399*6716431bSRobert Mustacchi err, err == USB_SUCCESS ? "success" : "error")); 400*6716431bSRobert Mustacchi return (err); 401*6716431bSRobert Mustacchi } 402*6716431bSRobert Mustacchi 403*6716431bSRobert Mustacchi /* 404*6716431bSRobert Mustacchi * send/receive packet check 405*6716431bSRobert Mustacchi */ 406*6716431bSRobert Mustacchi static mblk_t * 407*6716431bSRobert Mustacchi udmf_tx_make_packet(struct usbgem_dev *dp, mblk_t *mp) 408*6716431bSRobert Mustacchi { 409*6716431bSRobert Mustacchi int n; 410*6716431bSRobert Mustacchi size_t pkt_size; 411*6716431bSRobert Mustacchi mblk_t *new; 412*6716431bSRobert Mustacchi mblk_t *tp; 413*6716431bSRobert Mustacchi uint8_t *bp; 414*6716431bSRobert Mustacchi uint8_t *last_pos; 415*6716431bSRobert Mustacchi uint_t align_mask; 416*6716431bSRobert Mustacchi 417*6716431bSRobert Mustacchi pkt_size = msgdsize(mp); 418*6716431bSRobert Mustacchi align_mask = 63; 419*6716431bSRobert Mustacchi 420*6716431bSRobert Mustacchi /* 421*6716431bSRobert Mustacchi * re-allocate the mp 422*6716431bSRobert Mustacchi */ 423*6716431bSRobert Mustacchi 424*6716431bSRobert Mustacchi /* minimum ethernet packet size of ETHERMIN */ 425*6716431bSRobert Mustacchi pkt_size = max(pkt_size, ETHERMIN); 426*6716431bSRobert Mustacchi 427*6716431bSRobert Mustacchi #if 0 /* CONFIG_ADD_TX_DELIMITOR_ALWAYS */ 428*6716431bSRobert Mustacchi pkt_size += TX_HEADER_SIZE; 429*6716431bSRobert Mustacchi #endif 430*6716431bSRobert Mustacchi if (((pkt_size + TX_HEADER_SIZE) & align_mask) == 0) { 431*6716431bSRobert Mustacchi /* padding is required in usb communication */ 432*6716431bSRobert Mustacchi pkt_size += TX_HEADER_SIZE; 433*6716431bSRobert Mustacchi } 434*6716431bSRobert Mustacchi 435*6716431bSRobert Mustacchi if ((new = allocb(TX_HEADER_SIZE + pkt_size, 0)) == NULL) { 436*6716431bSRobert Mustacchi return (NULL); 437*6716431bSRobert Mustacchi } 438*6716431bSRobert Mustacchi new->b_wptr = new->b_rptr + TX_HEADER_SIZE + pkt_size; 439*6716431bSRobert Mustacchi 440*6716431bSRobert Mustacchi /* add a header */ 441*6716431bSRobert Mustacchi bp = new->b_rptr; 442*6716431bSRobert Mustacchi bp[0] = (uint8_t)pkt_size; 443*6716431bSRobert Mustacchi bp[1] = (uint8_t)(pkt_size >> 8); 444*6716431bSRobert Mustacchi bp += TX_HEADER_SIZE; 445*6716431bSRobert Mustacchi 446*6716431bSRobert Mustacchi /* copy contents of the buffer */ 447*6716431bSRobert Mustacchi for (tp = mp; tp; tp = tp->b_cont) { 448*6716431bSRobert Mustacchi n = MBLKL(tp); 449*6716431bSRobert Mustacchi bcopy(tp->b_rptr, bp, n); 450*6716431bSRobert Mustacchi bp += n; 451*6716431bSRobert Mustacchi } 452*6716431bSRobert Mustacchi 453*6716431bSRobert Mustacchi /* clear the rest including the next zero length header */ 454*6716431bSRobert Mustacchi last_pos = new->b_wptr; 455*6716431bSRobert Mustacchi while (bp < last_pos) { 456*6716431bSRobert Mustacchi *bp++ = 0; 457*6716431bSRobert Mustacchi } 458*6716431bSRobert Mustacchi 459*6716431bSRobert Mustacchi return (new); 460*6716431bSRobert Mustacchi } 461*6716431bSRobert Mustacchi 462*6716431bSRobert Mustacchi static void 463*6716431bSRobert Mustacchi udmf_dump_packet(struct usbgem_dev *dp, uint8_t *bp, int n) 464*6716431bSRobert Mustacchi { 465*6716431bSRobert Mustacchi int i; 466*6716431bSRobert Mustacchi 467*6716431bSRobert Mustacchi for (i = 0; i < n; i += 8, bp += 8) { 468*6716431bSRobert Mustacchi cmn_err(CE_CONT, "%02x %02x %02x %02x %02x %02x %02x %02x", 469*6716431bSRobert Mustacchi bp[0], bp[1], bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]); 470*6716431bSRobert Mustacchi } 471*6716431bSRobert Mustacchi } 472*6716431bSRobert Mustacchi 473*6716431bSRobert Mustacchi static mblk_t * 474*6716431bSRobert Mustacchi udmf_rx_make_packet(struct usbgem_dev *dp, mblk_t *mp) 475*6716431bSRobert Mustacchi { 476*6716431bSRobert Mustacchi size_t len; 477*6716431bSRobert Mustacchi uint8_t rx_stat; 478*6716431bSRobert Mustacchi 479*6716431bSRobert Mustacchi len = MBLKL(mp); 480*6716431bSRobert Mustacchi 481*6716431bSRobert Mustacchi if (len <= RX_HEADER_SIZE) { 482*6716431bSRobert Mustacchi /* 483*6716431bSRobert Mustacchi * the usb bulk-in frame doesn't include a valid 484*6716431bSRobert Mustacchi * ethernet packet. 485*6716431bSRobert Mustacchi */ 486*6716431bSRobert Mustacchi return (NULL); 487*6716431bSRobert Mustacchi } 488*6716431bSRobert Mustacchi 489*6716431bSRobert Mustacchi /* remove rx header */ 490*6716431bSRobert Mustacchi rx_stat = mp->b_rptr[0]; 491*6716431bSRobert Mustacchi if (rx_stat & (RSR_RF | RSR_LCS | RSR_RWTO | 492*6716431bSRobert Mustacchi RSR_PLE | RSR_AE | RSR_CE | RSR_FOE)) { 493*6716431bSRobert Mustacchi if (rx_stat & RSR_RF) { 494*6716431bSRobert Mustacchi dp->stats.runt++; 495*6716431bSRobert Mustacchi } 496*6716431bSRobert Mustacchi if (rx_stat & RSR_LCS) { 497*6716431bSRobert Mustacchi /* late collision */ 498*6716431bSRobert Mustacchi dp->stats.rcv_internal_err++; 499*6716431bSRobert Mustacchi } 500*6716431bSRobert Mustacchi if (rx_stat & RSR_RWTO) { 501*6716431bSRobert Mustacchi /* rx timeout */ 502*6716431bSRobert Mustacchi dp->stats.rcv_internal_err++; 503*6716431bSRobert Mustacchi } 504*6716431bSRobert Mustacchi if (rx_stat & RSR_PLE) { 505*6716431bSRobert Mustacchi /* physical layer error */ 506*6716431bSRobert Mustacchi dp->stats.rcv_internal_err++; 507*6716431bSRobert Mustacchi } 508*6716431bSRobert Mustacchi if (rx_stat & RSR_AE) { 509*6716431bSRobert Mustacchi /* alignment error */ 510*6716431bSRobert Mustacchi dp->stats.frame++; 511*6716431bSRobert Mustacchi } 512*6716431bSRobert Mustacchi if (rx_stat & RSR_CE) { 513*6716431bSRobert Mustacchi /* crc error */ 514*6716431bSRobert Mustacchi dp->stats.crc++; 515*6716431bSRobert Mustacchi } 516*6716431bSRobert Mustacchi if (rx_stat & RSR_FOE) { 517*6716431bSRobert Mustacchi /* fifo overflow error */ 518*6716431bSRobert Mustacchi dp->stats.overflow++; 519*6716431bSRobert Mustacchi } 520*6716431bSRobert Mustacchi dp->stats.errrcv++; 521*6716431bSRobert Mustacchi } 522*6716431bSRobert Mustacchi len = LE16P(&mp->b_rptr[1]); 523*6716431bSRobert Mustacchi if (len >= ETHERFCSL) { 524*6716431bSRobert Mustacchi len -= ETHERFCSL; 525*6716431bSRobert Mustacchi } 526*6716431bSRobert Mustacchi mp->b_rptr += RX_HEADER_SIZE; 527*6716431bSRobert Mustacchi mp->b_wptr = mp->b_rptr + len; 528*6716431bSRobert Mustacchi 529*6716431bSRobert Mustacchi return (mp); 530*6716431bSRobert Mustacchi } 531*6716431bSRobert Mustacchi 532*6716431bSRobert Mustacchi /* 533*6716431bSRobert Mustacchi * MII Interfaces 534*6716431bSRobert Mustacchi */ 535*6716431bSRobert Mustacchi static uint16_t 536*6716431bSRobert Mustacchi udmf_ep_read(struct usbgem_dev *dp, uint_t which, uint_t addr, int *errp) 537*6716431bSRobert Mustacchi { 538*6716431bSRobert Mustacchi int i; 539*6716431bSRobert Mustacchi uint8_t epcr; 540*6716431bSRobert Mustacchi uint16_t val; 541*6716431bSRobert Mustacchi 542*6716431bSRobert Mustacchi DPRINTF(4, (CE_CONT, "!%s: %s: called, ix:%d", 543*6716431bSRobert Mustacchi dp->name, __func__, addr)); 544*6716431bSRobert Mustacchi 545*6716431bSRobert Mustacchi OUTB(dp, EPAR, addr, errp, usberr); 546*6716431bSRobert Mustacchi OUTB(dp, EPCR, which | EPCR_ERPRR, errp, usberr); 547*6716431bSRobert Mustacchi 548*6716431bSRobert Mustacchi for (i = 0; i < 100; i++) { 549*6716431bSRobert Mustacchi IN(dp, EPCR, sizeof (epcr), &epcr, errp, usberr); 550*6716431bSRobert Mustacchi if ((epcr & EPCR_ERRE) == 0) { 551*6716431bSRobert Mustacchi /* done */ 552*6716431bSRobert Mustacchi IN(dp, EPDR, sizeof (val), &val, errp, usberr); 553*6716431bSRobert Mustacchi val = LE_16(val); 554*6716431bSRobert Mustacchi goto done; 555*6716431bSRobert Mustacchi } 556*6716431bSRobert Mustacchi drv_usecwait(10); 557*6716431bSRobert Mustacchi } 558*6716431bSRobert Mustacchi /* timeout */ 559*6716431bSRobert Mustacchi cmn_err(CE_WARN, "!%s: %s: timeout", dp->name, __func__); 560*6716431bSRobert Mustacchi val = 0; 561*6716431bSRobert Mustacchi done: 562*6716431bSRobert Mustacchi OUTB(dp, EPCR, 0, errp, usberr); 563*6716431bSRobert Mustacchi return (val); 564*6716431bSRobert Mustacchi 565*6716431bSRobert Mustacchi usberr: 566*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 567*6716431bSRobert Mustacchi dp->name, __func__, 568*6716431bSRobert Mustacchi *errp, *errp == USB_SUCCESS ? "success" : "error")); 569*6716431bSRobert Mustacchi return (0); 570*6716431bSRobert Mustacchi } 571*6716431bSRobert Mustacchi 572*6716431bSRobert Mustacchi static void 573*6716431bSRobert Mustacchi udmf_ep_write(struct usbgem_dev *dp, uint_t which, uint_t addr, 574*6716431bSRobert Mustacchi uint16_t val, int *errp) 575*6716431bSRobert Mustacchi { 576*6716431bSRobert Mustacchi int i; 577*6716431bSRobert Mustacchi uint8_t epcr; 578*6716431bSRobert Mustacchi 579*6716431bSRobert Mustacchi DPRINTF(5, (CE_CONT, "!%s: %s called", dp->name, __func__)); 580*6716431bSRobert Mustacchi 581*6716431bSRobert Mustacchi val = LE_16(val); 582*6716431bSRobert Mustacchi OUT(dp, EPDR, sizeof (val), &val, errp, usberr); 583*6716431bSRobert Mustacchi 584*6716431bSRobert Mustacchi OUTB(dp, EPAR, addr, errp, usberr); 585*6716431bSRobert Mustacchi 586*6716431bSRobert Mustacchi OUTB(dp, EPCR, which | EPCR_WEP | EPCR_ERPRW, errp, usberr); 587*6716431bSRobert Mustacchi 588*6716431bSRobert Mustacchi for (i = 0; i < 100; i++) { 589*6716431bSRobert Mustacchi IN(dp, EPCR, 1, &epcr, errp, usberr); 590*6716431bSRobert Mustacchi if ((epcr & EPCR_ERRE) == 0) { 591*6716431bSRobert Mustacchi /* done */ 592*6716431bSRobert Mustacchi goto done; 593*6716431bSRobert Mustacchi } 594*6716431bSRobert Mustacchi drv_usecwait(10); 595*6716431bSRobert Mustacchi } 596*6716431bSRobert Mustacchi /* timeout */ 597*6716431bSRobert Mustacchi cmn_err(CE_WARN, "!%s: %s: timeout", dp->name, __func__); 598*6716431bSRobert Mustacchi done: 599*6716431bSRobert Mustacchi OUTB(dp, EPCR, 0, errp, usberr); 600*6716431bSRobert Mustacchi return; 601*6716431bSRobert Mustacchi 602*6716431bSRobert Mustacchi usberr: 603*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: end err:%d(%s)", 604*6716431bSRobert Mustacchi dp->name, __func__, 605*6716431bSRobert Mustacchi *errp, *errp == USB_SUCCESS ? "success" : "error")); 606*6716431bSRobert Mustacchi } 607*6716431bSRobert Mustacchi 608*6716431bSRobert Mustacchi static uint16_t 609*6716431bSRobert Mustacchi udmf_mii_read(struct usbgem_dev *dp, uint_t index, int *errp) 610*6716431bSRobert Mustacchi { 611*6716431bSRobert Mustacchi uint16_t val; 612*6716431bSRobert Mustacchi 613*6716431bSRobert Mustacchi val = udmf_ep_read(dp, EPCR_EPOS, 614*6716431bSRobert Mustacchi (dp->mii_phy_addr << EPAR_PHYADR_SHIFT) | index, errp); 615*6716431bSRobert Mustacchi 616*6716431bSRobert Mustacchi return (val); 617*6716431bSRobert Mustacchi } 618*6716431bSRobert Mustacchi 619*6716431bSRobert Mustacchi static void 620*6716431bSRobert Mustacchi udmf_mii_write(struct usbgem_dev *dp, uint_t index, uint16_t val, int *errp) 621*6716431bSRobert Mustacchi { 622*6716431bSRobert Mustacchi udmf_ep_write(dp, EPCR_EPOS, 623*6716431bSRobert Mustacchi (dp->mii_phy_addr << EPAR_PHYADR_SHIFT) | index, val, errp); 624*6716431bSRobert Mustacchi } 625*6716431bSRobert Mustacchi 626*6716431bSRobert Mustacchi static void 627*6716431bSRobert Mustacchi udmf_interrupt(struct usbgem_dev *dp, mblk_t *mp) 628*6716431bSRobert Mustacchi { 629*6716431bSRobert Mustacchi struct intr_msg *imp; 630*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 631*6716431bSRobert Mustacchi 632*6716431bSRobert Mustacchi imp = (struct intr_msg *)&mp->b_rptr[0]; 633*6716431bSRobert Mustacchi 634*6716431bSRobert Mustacchi DPRINTF(4, (CE_CONT, 635*6716431bSRobert Mustacchi "!%s: %s: size:%d, nsr:%b tsr1:%b tsr2:%b" 636*6716431bSRobert Mustacchi " rsr:%b rocr:%b rxc:%02x txc:%b gpr:%b", 637*6716431bSRobert Mustacchi dp->name, __func__, mp->b_wptr - mp->b_rptr, 638*6716431bSRobert Mustacchi imp->im_nsr, NSR_BITS, 639*6716431bSRobert Mustacchi imp->im_tsr1, TSR_BITS, 640*6716431bSRobert Mustacchi imp->im_tsr2, TSR_BITS, 641*6716431bSRobert Mustacchi imp->im_rsr, RSR_BITS, 642*6716431bSRobert Mustacchi imp->im_rocr, ROCR_BITS, 643*6716431bSRobert Mustacchi imp->im_rxc, 644*6716431bSRobert Mustacchi imp->im_txc, TUSR_BITS, 645*6716431bSRobert Mustacchi imp->im_gpr, GPR_BITS)); 646*6716431bSRobert Mustacchi 647*6716431bSRobert Mustacchi if ((lp->last_nsr ^ imp->im_nsr) & NSR_LINKST) { 648*6716431bSRobert Mustacchi usbgem_mii_update_link(dp); 649*6716431bSRobert Mustacchi } 650*6716431bSRobert Mustacchi 651*6716431bSRobert Mustacchi lp->last_nsr = imp->im_nsr; 652*6716431bSRobert Mustacchi } 653*6716431bSRobert Mustacchi 654*6716431bSRobert Mustacchi /* ======================================================== */ 655*6716431bSRobert Mustacchi /* 656*6716431bSRobert Mustacchi * OS depend (device driver DKI) routine 657*6716431bSRobert Mustacchi */ 658*6716431bSRobert Mustacchi /* ======================================================== */ 659*6716431bSRobert Mustacchi static uint16_t 660*6716431bSRobert Mustacchi udmf_eeprom_read(struct usbgem_dev *dp, uint_t index, int *errp) 661*6716431bSRobert Mustacchi { 662*6716431bSRobert Mustacchi uint16_t val; 663*6716431bSRobert Mustacchi 664*6716431bSRobert Mustacchi val = udmf_ep_read(dp, 0, index, errp); 665*6716431bSRobert Mustacchi 666*6716431bSRobert Mustacchi return (val); 667*6716431bSRobert Mustacchi } 668*6716431bSRobert Mustacchi 669*6716431bSRobert Mustacchi #ifdef DEBUG_LEVEL 670*6716431bSRobert Mustacchi static void 671*6716431bSRobert Mustacchi udmf_eeprom_dump(struct usbgem_dev *dp, int size) 672*6716431bSRobert Mustacchi { 673*6716431bSRobert Mustacchi int i; 674*6716431bSRobert Mustacchi int err; 675*6716431bSRobert Mustacchi uint16_t w0, w1, w2, w3; 676*6716431bSRobert Mustacchi 677*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!%s: eeprom dump:", dp->name); 678*6716431bSRobert Mustacchi 679*6716431bSRobert Mustacchi err = USB_SUCCESS; 680*6716431bSRobert Mustacchi 681*6716431bSRobert Mustacchi for (i = 0; i < size; i += 4) { 682*6716431bSRobert Mustacchi w0 = udmf_eeprom_read(dp, i + 0, &err); 683*6716431bSRobert Mustacchi w1 = udmf_eeprom_read(dp, i + 1, &err); 684*6716431bSRobert Mustacchi w2 = udmf_eeprom_read(dp, i + 2, &err); 685*6716431bSRobert Mustacchi w3 = udmf_eeprom_read(dp, i + 3, &err); 686*6716431bSRobert Mustacchi cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x", 687*6716431bSRobert Mustacchi i, w0, w1, w2, w3); 688*6716431bSRobert Mustacchi } 689*6716431bSRobert Mustacchi usberr: 690*6716431bSRobert Mustacchi ; 691*6716431bSRobert Mustacchi } 692*6716431bSRobert Mustacchi #endif 693*6716431bSRobert Mustacchi 694*6716431bSRobert Mustacchi static int 695*6716431bSRobert Mustacchi udmf_attach_chip(struct usbgem_dev *dp) 696*6716431bSRobert Mustacchi { 697*6716431bSRobert Mustacchi int i; 698*6716431bSRobert Mustacchi uint_t val; 699*6716431bSRobert Mustacchi uint8_t *m; 700*6716431bSRobert Mustacchi int err; 701*6716431bSRobert Mustacchi struct udmf_dev *lp = dp->private; 702*6716431bSRobert Mustacchi 703*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: %s enter", dp->name, __func__)); 704*6716431bSRobert Mustacchi 705*6716431bSRobert Mustacchi /* 706*6716431bSRobert Mustacchi * get mac address from EEPROM 707*6716431bSRobert Mustacchi */ 708*6716431bSRobert Mustacchi m = dp->dev_addr.ether_addr_octet; 709*6716431bSRobert Mustacchi for (i = 0; i < ETHERADDRL; i += 2) { 710*6716431bSRobert Mustacchi val = udmf_eeprom_read(dp, i/2, &err); 711*6716431bSRobert Mustacchi m[i + 0] = (uint8_t)val; 712*6716431bSRobert Mustacchi m[i + 1] = (uint8_t)(val >> 8); 713*6716431bSRobert Mustacchi } 714*6716431bSRobert Mustacchi 715*6716431bSRobert Mustacchi /* invalidate a private cache for mac addr */ 716*6716431bSRobert Mustacchi bzero(lp->mac_addr, sizeof (lp->mac_addr)); 717*6716431bSRobert Mustacchi #ifdef CONFIG_VLAN 718*6716431bSRobert Mustacchi dp->misc_flag = USBGEM_VLAN; 719*6716431bSRobert Mustacchi #endif 720*6716431bSRobert Mustacchi #if DEBUG_LEVEL > 0 721*6716431bSRobert Mustacchi udmf_eeprom_dump(dp, /* 0x3f + 1 */ 128); 722*6716431bSRobert Mustacchi #endif 723*6716431bSRobert Mustacchi { 724*6716431bSRobert Mustacchi static uint8_t bcst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 725*6716431bSRobert Mustacchi DPRINTF(0, (CE_CONT, "!%s: %s: hash of bcast:%x", 726*6716431bSRobert Mustacchi dp->name, __func__, usbgem_ether_crc_be(bcst))); 727*6716431bSRobert Mustacchi } 728*6716431bSRobert Mustacchi return (USB_SUCCESS); 729*6716431bSRobert Mustacchi 730*6716431bSRobert Mustacchi usberr: 731*6716431bSRobert Mustacchi cmn_err(CE_WARN, "%s: %s: usb error detected (%d)", 732*6716431bSRobert Mustacchi dp->name, __func__, err); 733*6716431bSRobert Mustacchi return (USB_FAILURE); 734*6716431bSRobert Mustacchi } 735*6716431bSRobert Mustacchi 736*6716431bSRobert Mustacchi static int 737*6716431bSRobert Mustacchi udmf_mii_probe(struct usbgem_dev *dp) 738*6716431bSRobert Mustacchi { 739*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 740*6716431bSRobert Mustacchi 741*6716431bSRobert Mustacchi udmf_enable_phy(dp); 742*6716431bSRobert Mustacchi return (usbgem_mii_probe_default(dp)); 743*6716431bSRobert Mustacchi } 744*6716431bSRobert Mustacchi 745*6716431bSRobert Mustacchi static int 746*6716431bSRobert Mustacchi udmf_mii_init(struct usbgem_dev *dp) 747*6716431bSRobert Mustacchi { 748*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__)); 749*6716431bSRobert Mustacchi udmf_enable_phy(dp); 750*6716431bSRobert Mustacchi return (USB_SUCCESS); 751*6716431bSRobert Mustacchi } 752*6716431bSRobert Mustacchi 753*6716431bSRobert Mustacchi static int 754*6716431bSRobert Mustacchi udmfattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 755*6716431bSRobert Mustacchi { 756*6716431bSRobert Mustacchi int i; 757*6716431bSRobert Mustacchi ddi_iblock_cookie_t c; 758*6716431bSRobert Mustacchi int ret; 759*6716431bSRobert Mustacchi int revid; 760*6716431bSRobert Mustacchi int unit; 761*6716431bSRobert Mustacchi int len; 762*6716431bSRobert Mustacchi const char *drv_name; 763*6716431bSRobert Mustacchi struct usbgem_dev *dp; 764*6716431bSRobert Mustacchi void *base; 765*6716431bSRobert Mustacchi struct usbgem_conf *ugcp; 766*6716431bSRobert Mustacchi struct udmf_dev *lp; 767*6716431bSRobert Mustacchi 768*6716431bSRobert Mustacchi unit = ddi_get_instance(dip); 769*6716431bSRobert Mustacchi drv_name = ddi_driver_name(dip); 770*6716431bSRobert Mustacchi 771*6716431bSRobert Mustacchi DPRINTF(3, (CE_CONT, "!%s%d: %s: called, cmd:%d", 772*6716431bSRobert Mustacchi drv_name, unit, __func__, cmd)); 773*6716431bSRobert Mustacchi 774*6716431bSRobert Mustacchi if (cmd == DDI_ATTACH) { 775*6716431bSRobert Mustacchi /* 776*6716431bSRobert Mustacchi * construct usbgem configration 777*6716431bSRobert Mustacchi */ 778*6716431bSRobert Mustacchi ugcp = kmem_zalloc(sizeof (*ugcp), KM_SLEEP); 779*6716431bSRobert Mustacchi 780*6716431bSRobert Mustacchi /* name */ 781*6716431bSRobert Mustacchi /* 782*6716431bSRobert Mustacchi * softmac requires that ppa is the instance number 783*6716431bSRobert Mustacchi * of the device, otherwise it hangs in seaching the device. 784*6716431bSRobert Mustacchi */ 785*6716431bSRobert Mustacchi (void) sprintf(ugcp->usbgc_name, "%s%d", drv_name, unit); 786*6716431bSRobert Mustacchi ugcp->usbgc_ppa = unit; 787*6716431bSRobert Mustacchi 788*6716431bSRobert Mustacchi ugcp->usbgc_ifnum = 0; 789*6716431bSRobert Mustacchi ugcp->usbgc_alt = 0; 790*6716431bSRobert Mustacchi 791*6716431bSRobert Mustacchi ugcp->usbgc_tx_list_max = 64; 792*6716431bSRobert Mustacchi 793*6716431bSRobert Mustacchi ugcp->usbgc_rx_header_len = RX_HEADER_SIZE; 794*6716431bSRobert Mustacchi ugcp->usbgc_rx_list_max = 64; 795*6716431bSRobert Mustacchi 796*6716431bSRobert Mustacchi /* time out parameters */ 797*6716431bSRobert Mustacchi ugcp->usbgc_tx_timeout = USBGEM_TX_TIMEOUT; 798*6716431bSRobert Mustacchi ugcp->usbgc_tx_timeout_interval = USBGEM_TX_TIMEOUT_INTERVAL; 799*6716431bSRobert Mustacchi #if 1 800*6716431bSRobert Mustacchi /* flow control */ 801*6716431bSRobert Mustacchi ugcp->usbgc_flow_control = FLOW_CONTROL_RX_PAUSE; 802*6716431bSRobert Mustacchi #else 803*6716431bSRobert Mustacchi /* 804*6716431bSRobert Mustacchi * XXX - flow control caused link down frequently under 805*6716431bSRobert Mustacchi * heavy traffic 806*6716431bSRobert Mustacchi */ 807*6716431bSRobert Mustacchi ugcp->usbgc_flow_control = FLOW_CONTROL_NONE; 808*6716431bSRobert Mustacchi #endif 809*6716431bSRobert Mustacchi /* MII timeout parameters */ 810*6716431bSRobert Mustacchi ugcp->usbgc_mii_link_watch_interval = 811*6716431bSRobert Mustacchi USBGEM_LINK_WATCH_INTERVAL; 812*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_watch_interval = 813*6716431bSRobert Mustacchi USBGEM_LINK_WATCH_INTERVAL/5; 814*6716431bSRobert Mustacchi ugcp->usbgc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */ 815*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_timeout = MII_AN_TIMEOUT; /* 5 sec */ 816*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_wait = (25*ONESEC)/10; 817*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT; 818*6716431bSRobert Mustacchi 819*6716431bSRobert Mustacchi ugcp->usbgc_mii_an_delay = ONESEC/10; 820*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_action = MII_ACTION_RSA; 821*6716431bSRobert Mustacchi ugcp->usbgc_mii_linkdown_timeout_action = MII_ACTION_RESET; 822*6716431bSRobert Mustacchi ugcp->usbgc_mii_dont_reset = B_FALSE; 823*6716431bSRobert Mustacchi ugcp->usbgc_mii_hw_link_detection = B_TRUE; 824*6716431bSRobert Mustacchi 825*6716431bSRobert Mustacchi /* I/O methods */ 826*6716431bSRobert Mustacchi 827*6716431bSRobert Mustacchi /* mac operation */ 828*6716431bSRobert Mustacchi ugcp->usbgc_attach_chip = &udmf_attach_chip; 829*6716431bSRobert Mustacchi ugcp->usbgc_reset_chip = &udmf_reset_chip; 830*6716431bSRobert Mustacchi ugcp->usbgc_init_chip = &udmf_init_chip; 831*6716431bSRobert Mustacchi ugcp->usbgc_start_chip = &udmf_start_chip; 832*6716431bSRobert Mustacchi ugcp->usbgc_stop_chip = &udmf_stop_chip; 833*6716431bSRobert Mustacchi ugcp->usbgc_multicast_hash = &udmf_mcast_hash; 834*6716431bSRobert Mustacchi 835*6716431bSRobert Mustacchi ugcp->usbgc_set_rx_filter = &udmf_set_rx_filter; 836*6716431bSRobert Mustacchi ugcp->usbgc_set_media = &udmf_set_media; 837*6716431bSRobert Mustacchi ugcp->usbgc_get_stats = &udmf_get_stats; 838*6716431bSRobert Mustacchi ugcp->usbgc_interrupt = &udmf_interrupt; 839*6716431bSRobert Mustacchi 840*6716431bSRobert Mustacchi /* packet operation */ 841*6716431bSRobert Mustacchi ugcp->usbgc_tx_make_packet = &udmf_tx_make_packet; 842*6716431bSRobert Mustacchi ugcp->usbgc_rx_make_packet = &udmf_rx_make_packet; 843*6716431bSRobert Mustacchi 844*6716431bSRobert Mustacchi /* mii operations */ 845*6716431bSRobert Mustacchi ugcp->usbgc_mii_probe = &udmf_mii_probe; 846*6716431bSRobert Mustacchi ugcp->usbgc_mii_init = &udmf_mii_init; 847*6716431bSRobert Mustacchi ugcp->usbgc_mii_config = &usbgem_mii_config_default; 848*6716431bSRobert Mustacchi ugcp->usbgc_mii_read = &udmf_mii_read; 849*6716431bSRobert Mustacchi ugcp->usbgc_mii_write = &udmf_mii_write; 850*6716431bSRobert Mustacchi ugcp->usbgc_mii_addr_min = 1; 851*6716431bSRobert Mustacchi 852*6716431bSRobert Mustacchi /* mtu */ 853*6716431bSRobert Mustacchi ugcp->usbgc_min_mtu = ETHERMTU; 854*6716431bSRobert Mustacchi ugcp->usbgc_max_mtu = ETHERMTU; 855*6716431bSRobert Mustacchi ugcp->usbgc_default_mtu = ETHERMTU; 856*6716431bSRobert Mustacchi 857*6716431bSRobert Mustacchi lp = kmem_zalloc(sizeof (struct udmf_dev), KM_SLEEP); 858*6716431bSRobert Mustacchi 859*6716431bSRobert Mustacchi ddi_set_driver_private(dip, NULL); 860*6716431bSRobert Mustacchi 861*6716431bSRobert Mustacchi dp = usbgem_do_attach(dip, ugcp, lp, sizeof (struct udmf_dev)); 862*6716431bSRobert Mustacchi 863*6716431bSRobert Mustacchi kmem_free(ugcp, sizeof (*ugcp)); 864*6716431bSRobert Mustacchi 865*6716431bSRobert Mustacchi if (dp != NULL) { 866*6716431bSRobert Mustacchi return (DDI_SUCCESS); 867*6716431bSRobert Mustacchi } 868*6716431bSRobert Mustacchi 869*6716431bSRobert Mustacchi err_free_mem: 870*6716431bSRobert Mustacchi kmem_free(lp, sizeof (struct udmf_dev)); 871*6716431bSRobert Mustacchi err_close_pipe: 872*6716431bSRobert Mustacchi err: 873*6716431bSRobert Mustacchi return (DDI_FAILURE); 874*6716431bSRobert Mustacchi } 875*6716431bSRobert Mustacchi 876*6716431bSRobert Mustacchi if (cmd == DDI_RESUME) { 877*6716431bSRobert Mustacchi return (usbgem_resume(dip)); 878*6716431bSRobert Mustacchi } 879*6716431bSRobert Mustacchi 880*6716431bSRobert Mustacchi return (DDI_FAILURE); 881*6716431bSRobert Mustacchi } 882*6716431bSRobert Mustacchi 883*6716431bSRobert Mustacchi static int 884*6716431bSRobert Mustacchi udmfdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 885*6716431bSRobert Mustacchi { 886*6716431bSRobert Mustacchi int ret; 887*6716431bSRobert Mustacchi 888*6716431bSRobert Mustacchi if (cmd == DDI_DETACH) { 889*6716431bSRobert Mustacchi ret = usbgem_do_detach(dip); 890*6716431bSRobert Mustacchi if (ret != DDI_SUCCESS) { 891*6716431bSRobert Mustacchi return (DDI_FAILURE); 892*6716431bSRobert Mustacchi } 893*6716431bSRobert Mustacchi return (DDI_SUCCESS); 894*6716431bSRobert Mustacchi } 895*6716431bSRobert Mustacchi if (cmd == DDI_SUSPEND) { 896*6716431bSRobert Mustacchi return (usbgem_suspend(dip)); 897*6716431bSRobert Mustacchi } 898*6716431bSRobert Mustacchi return (DDI_FAILURE); 899*6716431bSRobert Mustacchi } 900*6716431bSRobert Mustacchi 901*6716431bSRobert Mustacchi /* ======================================================== */ 902*6716431bSRobert Mustacchi /* 903*6716431bSRobert Mustacchi * OS depend (loadable streams driver) routine 904*6716431bSRobert Mustacchi */ 905*6716431bSRobert Mustacchi /* ======================================================== */ 906*6716431bSRobert Mustacchi #ifdef USBGEM_CONFIG_GLDv3 907*6716431bSRobert Mustacchi USBGEM_STREAM_OPS(udmf_ops, udmfattach, udmfdetach); 908*6716431bSRobert Mustacchi #else 909*6716431bSRobert Mustacchi static struct module_info udmfminfo = { 910*6716431bSRobert Mustacchi 0, /* mi_idnum */ 911*6716431bSRobert Mustacchi "udmf", /* mi_idname */ 912*6716431bSRobert Mustacchi 0, /* mi_minpsz */ 913*6716431bSRobert Mustacchi ETHERMTU, /* mi_maxpsz */ 914*6716431bSRobert Mustacchi ETHERMTU*128, /* mi_hiwat */ 915*6716431bSRobert Mustacchi 1, /* mi_lowat */ 916*6716431bSRobert Mustacchi }; 917*6716431bSRobert Mustacchi 918*6716431bSRobert Mustacchi static struct qinit udmfrinit = { 919*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_putp */ 920*6716431bSRobert Mustacchi usbgem_rsrv, /* qi_srvp */ 921*6716431bSRobert Mustacchi usbgem_open, /* qi_qopen */ 922*6716431bSRobert Mustacchi usbgem_close, /* qi_qclose */ 923*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qadmin */ 924*6716431bSRobert Mustacchi &udmfminfo, /* qi_minfo */ 925*6716431bSRobert Mustacchi NULL /* qi_mstat */ 926*6716431bSRobert Mustacchi }; 927*6716431bSRobert Mustacchi 928*6716431bSRobert Mustacchi static struct qinit udmfwinit = { 929*6716431bSRobert Mustacchi usbgem_wput, /* qi_putp */ 930*6716431bSRobert Mustacchi usbgem_wsrv, /* qi_srvp */ 931*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qopen */ 932*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qclose */ 933*6716431bSRobert Mustacchi (int (*)()) NULL, /* qi_qadmin */ 934*6716431bSRobert Mustacchi &udmfminfo, /* qi_minfo */ 935*6716431bSRobert Mustacchi NULL /* qi_mstat */ 936*6716431bSRobert Mustacchi }; 937*6716431bSRobert Mustacchi 938*6716431bSRobert Mustacchi static struct streamtab udmf_info = { 939*6716431bSRobert Mustacchi &udmfrinit, /* st_rdinit */ 940*6716431bSRobert Mustacchi &udmfwinit, /* st_wrinit */ 941*6716431bSRobert Mustacchi NULL, /* st_muxrinit */ 942*6716431bSRobert Mustacchi NULL /* st_muxwrinit */ 943*6716431bSRobert Mustacchi }; 944*6716431bSRobert Mustacchi 945*6716431bSRobert Mustacchi static struct cb_ops cb_udmf_ops = { 946*6716431bSRobert Mustacchi nulldev, /* cb_open */ 947*6716431bSRobert Mustacchi nulldev, /* cb_close */ 948*6716431bSRobert Mustacchi nodev, /* cb_strategy */ 949*6716431bSRobert Mustacchi nodev, /* cb_print */ 950*6716431bSRobert Mustacchi nodev, /* cb_dump */ 951*6716431bSRobert Mustacchi nodev, /* cb_read */ 952*6716431bSRobert Mustacchi nodev, /* cb_write */ 953*6716431bSRobert Mustacchi nodev, /* cb_ioctl */ 954*6716431bSRobert Mustacchi nodev, /* cb_devmap */ 955*6716431bSRobert Mustacchi nodev, /* cb_mmap */ 956*6716431bSRobert Mustacchi nodev, /* cb_segmap */ 957*6716431bSRobert Mustacchi nochpoll, /* cb_chpoll */ 958*6716431bSRobert Mustacchi ddi_prop_op, /* cb_prop_op */ 959*6716431bSRobert Mustacchi &udmf_info, /* cb_stream */ 960*6716431bSRobert Mustacchi D_NEW|D_MP /* cb_flag */ 961*6716431bSRobert Mustacchi }; 962*6716431bSRobert Mustacchi 963*6716431bSRobert Mustacchi static struct dev_ops udmf_ops = { 964*6716431bSRobert Mustacchi DEVO_REV, /* devo_rev */ 965*6716431bSRobert Mustacchi 0, /* devo_refcnt */ 966*6716431bSRobert Mustacchi usbgem_getinfo, /* devo_getinfo */ 967*6716431bSRobert Mustacchi nulldev, /* devo_identify */ 968*6716431bSRobert Mustacchi nulldev, /* devo_probe */ 969*6716431bSRobert Mustacchi udmfattach, /* devo_attach */ 970*6716431bSRobert Mustacchi udmfdetach, /* devo_detach */ 971*6716431bSRobert Mustacchi nodev, /* devo_reset */ 972*6716431bSRobert Mustacchi &cb_udmf_ops, /* devo_cb_ops */ 973*6716431bSRobert Mustacchi NULL, /* devo_bus_ops */ 974*6716431bSRobert Mustacchi usbgem_power, /* devo_power */ 975*6716431bSRobert Mustacchi #if DEVO_REV >= 4 976*6716431bSRobert Mustacchi usbgem_quiesce, /* devo_quiesce */ 977*6716431bSRobert Mustacchi #endif 978*6716431bSRobert Mustacchi }; 979*6716431bSRobert Mustacchi #endif 980*6716431bSRobert Mustacchi 981*6716431bSRobert Mustacchi static struct modldrv modldrv = { 982*6716431bSRobert Mustacchi &mod_driverops, /* Type of module. This one is a driver */ 983*6716431bSRobert Mustacchi ident, 984*6716431bSRobert Mustacchi &udmf_ops, /* driver ops */ 985*6716431bSRobert Mustacchi }; 986*6716431bSRobert Mustacchi 987*6716431bSRobert Mustacchi static struct modlinkage modlinkage = { 988*6716431bSRobert Mustacchi MODREV_1, &modldrv, NULL 989*6716431bSRobert Mustacchi }; 990*6716431bSRobert Mustacchi 991*6716431bSRobert Mustacchi /* ======================================================== */ 992*6716431bSRobert Mustacchi /* 993*6716431bSRobert Mustacchi * _init : done 994*6716431bSRobert Mustacchi */ 995*6716431bSRobert Mustacchi /* ======================================================== */ 996*6716431bSRobert Mustacchi int 997*6716431bSRobert Mustacchi _init(void) 998*6716431bSRobert Mustacchi { 999*6716431bSRobert Mustacchi int status; 1000*6716431bSRobert Mustacchi 1001*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!udmf: _init: called")); 1002*6716431bSRobert Mustacchi 1003*6716431bSRobert Mustacchi status = usbgem_mod_init(&udmf_ops, "udmf"); 1004*6716431bSRobert Mustacchi if (status != DDI_SUCCESS) { 1005*6716431bSRobert Mustacchi return (status); 1006*6716431bSRobert Mustacchi } 1007*6716431bSRobert Mustacchi status = mod_install(&modlinkage); 1008*6716431bSRobert Mustacchi if (status != DDI_SUCCESS) { 1009*6716431bSRobert Mustacchi usbgem_mod_fini(&udmf_ops); 1010*6716431bSRobert Mustacchi } 1011*6716431bSRobert Mustacchi return (status); 1012*6716431bSRobert Mustacchi } 1013*6716431bSRobert Mustacchi 1014*6716431bSRobert Mustacchi /* 1015*6716431bSRobert Mustacchi * _fini : done 1016*6716431bSRobert Mustacchi */ 1017*6716431bSRobert Mustacchi int 1018*6716431bSRobert Mustacchi _fini(void) 1019*6716431bSRobert Mustacchi { 1020*6716431bSRobert Mustacchi int status; 1021*6716431bSRobert Mustacchi 1022*6716431bSRobert Mustacchi DPRINTF(2, (CE_CONT, "!udmf: _fini: called")); 1023*6716431bSRobert Mustacchi status = mod_remove(&modlinkage); 1024*6716431bSRobert Mustacchi if (status == DDI_SUCCESS) { 1025*6716431bSRobert Mustacchi usbgem_mod_fini(&udmf_ops); 1026*6716431bSRobert Mustacchi } 1027*6716431bSRobert Mustacchi return (status); 1028*6716431bSRobert Mustacchi } 1029*6716431bSRobert Mustacchi 1030*6716431bSRobert Mustacchi int 1031*6716431bSRobert Mustacchi _info(struct modinfo *modinfop) 1032*6716431bSRobert Mustacchi { 1033*6716431bSRobert Mustacchi return (mod_info(&modlinkage, modinfop)); 1034*6716431bSRobert Mustacchi } 1035