1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 #include "nge.h"
  29 
  30 /*
  31  * Describes the chip's DMA engine
  32  */
  33 
  34 static ddi_dma_attr_t hot_dma_attr = {
  35         DMA_ATTR_V0,                    /* dma_attr version     */
  36         0x0000000000000000ull,          /* dma_attr_addr_lo     */
  37         0x000000FFFFFFFFFFull,          /* dma_attr_addr_hi     */
  38         0x000000007FFFFFFFull,          /* dma_attr_count_max   */
  39         0x0000000000000010ull,          /* dma_attr_align       */
  40         0x00000FFF,                     /* dma_attr_burstsizes  */
  41         0x00000001,                     /* dma_attr_minxfer     */
  42         0x000000000000FFFFull,          /* dma_attr_maxxfer     */
  43         0x000000FFFFFFFFFFull,          /* dma_attr_seg         */
  44         1,                              /* dma_attr_sgllen      */
  45         0x00000001,                     /* dma_attr_granular    */
  46         0
  47 };
  48 
  49 static ddi_dma_attr_t hot_tx_dma_attr = {
  50         DMA_ATTR_V0,                    /* dma_attr version     */
  51         0x0000000000000000ull,          /* dma_attr_addr_lo     */
  52         0x000000FFFFFFFFFFull,          /* dma_attr_addr_hi     */
  53         0x0000000000003FFFull,          /* dma_attr_count_max   */
  54         0x0000000000000010ull,          /* dma_attr_align       */
  55         0x00000FFF,                     /* dma_attr_burstsizes  */
  56         0x00000001,                     /* dma_attr_minxfer     */
  57         0x0000000000003FFFull,          /* dma_attr_maxxfer     */
  58         0x000000FFFFFFFFFFull,          /* dma_attr_seg         */
  59         NGE_MAX_COOKIES,                /* dma_attr_sgllen      */
  60         1,                              /* dma_attr_granular    */
  61         0
  62 };
  63 
  64 static ddi_dma_attr_t sum_dma_attr = {
  65         DMA_ATTR_V0,                    /* dma_attr version     */
  66         0x0000000000000000ull,          /* dma_attr_addr_lo     */
  67         0x00000000FFFFFFFFull,          /* dma_attr_addr_hi     */
  68         0x000000007FFFFFFFull,          /* dma_attr_count_max   */
  69         0x0000000000000010ull,          /* dma_attr_align       */
  70         0x00000FFF,                     /* dma_attr_burstsizes  */
  71         0x00000001,                     /* dma_attr_minxfer     */
  72         0x000000000000FFFFull,          /* dma_attr_maxxfer     */
  73         0x00000000FFFFFFFFull,          /* dma_attr_seg         */
  74         1,                              /* dma_attr_sgllen      */
  75         0x00000001,                     /* dma_attr_granular    */
  76         0
  77 };
  78 
  79 static ddi_dma_attr_t sum_tx_dma_attr = {
  80         DMA_ATTR_V0,                    /* dma_attr version     */
  81         0x0000000000000000ull,          /* dma_attr_addr_lo     */
  82         0x00000000FFFFFFFFull,          /* dma_attr_addr_hi     */
  83         0x0000000000003FFFull,          /* dma_attr_count_max   */
  84         0x0000000000000010ull,          /* dma_attr_align       */
  85         0x00000FFF,                     /* dma_attr_burstsizes  */
  86         0x00000001,                     /* dma_attr_minxfer     */
  87         0x0000000000003FFFull,          /* dma_attr_maxxfer     */
  88         0x00000000FFFFFFFFull,          /* dma_attr_seg         */
  89         NGE_MAX_COOKIES,                /* dma_attr_sgllen      */
  90         1,                              /* dma_attr_granular    */
  91         0
  92 };
  93 
  94 /*
  95  * DMA access attributes for data.
  96  */
  97 ddi_device_acc_attr_t nge_data_accattr = {
  98         DDI_DEVICE_ATTR_V0,
  99         DDI_STRUCTURE_LE_ACC,
 100         DDI_STRICTORDER_ACC,
 101         DDI_DEFAULT_ACC
 102 };
 103 
 104 /*
 105  * DMA access attributes for descriptors.
 106  */
 107 static ddi_device_acc_attr_t nge_desc_accattr = {
 108         DDI_DEVICE_ATTR_V0,
 109         DDI_STRUCTURE_LE_ACC,
 110         DDI_STRICTORDER_ACC,
 111         DDI_DEFAULT_ACC
 112 };
 113 
 114 /*
 115  * PIO access attributes for registers
 116  */
 117 static ddi_device_acc_attr_t nge_reg_accattr = {
 118         DDI_DEVICE_ATTR_V0,
 119         DDI_STRUCTURE_LE_ACC,
 120         DDI_STRICTORDER_ACC,
 121         DDI_DEFAULT_ACC
 122 };
 123 
 124 /*
 125  * NIC DESC MODE 2
 126  */
 127 
 128 static const nge_desc_attr_t nge_sum_desc = {
 129 
 130         sizeof (sum_rx_bd),
 131         sizeof (sum_tx_bd),
 132         &sum_dma_attr,
 133         &sum_tx_dma_attr,
 134         nge_sum_rxd_fill,
 135         nge_sum_rxd_check,
 136         nge_sum_txd_fill,
 137         nge_sum_txd_check,
 138 };
 139 
 140 /*
 141  * NIC DESC MODE 3
 142  */
 143 
 144 static const nge_desc_attr_t nge_hot_desc = {
 145 
 146         sizeof (hot_rx_bd),
 147         sizeof (hot_tx_bd),
 148         &hot_dma_attr,
 149         &hot_tx_dma_attr,
 150         nge_hot_rxd_fill,
 151         nge_hot_rxd_check,
 152         nge_hot_txd_fill,
 153         nge_hot_txd_check,
 154 };
 155 
 156 static char nge_ident[] = "nVidia 1Gb Ethernet";
 157 static char clsize_propname[] = "cache-line-size";
 158 static char latency_propname[] = "latency-timer";
 159 static char debug_propname[]    = "nge-debug-flags";
 160 static char intr_moderation[] = "intr-moderation";
 161 static char rx_data_hw[] = "rx-data-hw";
 162 static char rx_prd_lw[] = "rx-prd-lw";
 163 static char rx_prd_hw[] = "rx-prd-hw";
 164 static char sw_intr_intv[] = "sw-intr-intvl";
 165 static char nge_desc_mode[] = "desc-mode";
 166 static char default_mtu[] = "default_mtu";
 167 static char low_memory_mode[] = "minimal-memory-usage";
 168 extern kmutex_t nge_log_mutex[1];
 169 
 170 static int              nge_m_start(void *);
 171 static void             nge_m_stop(void *);
 172 static int              nge_m_promisc(void *, boolean_t);
 173 static int              nge_m_multicst(void *, boolean_t, const uint8_t *);
 174 static int              nge_m_unicst(void *, const uint8_t *);
 175 static void             nge_m_ioctl(void *, queue_t *, mblk_t *);
 176 static boolean_t        nge_m_getcapab(void *, mac_capab_t, void *);
 177 static int              nge_m_setprop(void *, const char *, mac_prop_id_t,
 178         uint_t, const void *);
 179 static int              nge_m_getprop(void *, const char *, mac_prop_id_t,
 180         uint_t, void *);
 181 static void             nge_m_propinfo(void *, const char *, mac_prop_id_t,
 182         mac_prop_info_handle_t);
 183 static int              nge_set_priv_prop(nge_t *, const char *, uint_t,
 184         const void *);
 185 static int              nge_get_priv_prop(nge_t *, const char *, uint_t,
 186         void *);
 187 
 188 #define         NGE_M_CALLBACK_FLAGS\
 189                 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \
 190                 MC_PROPINFO)
 191 
 192 static mac_callbacks_t nge_m_callbacks = {
 193         NGE_M_CALLBACK_FLAGS,
 194         nge_m_stat,
 195         nge_m_start,
 196         nge_m_stop,
 197         nge_m_promisc,
 198         nge_m_multicst,
 199         nge_m_unicst,
 200         nge_m_tx,
 201         NULL,
 202         nge_m_ioctl,
 203         nge_m_getcapab,
 204         NULL,
 205         NULL,
 206         nge_m_setprop,
 207         nge_m_getprop,
 208         nge_m_propinfo
 209 };
 210 
 211 char *nge_priv_props[] = {
 212         "_tx_bcopy_threshold",
 213         "_rx_bcopy_threshold",
 214         "_recv_max_packet",
 215         "_poll_quiet_time",
 216         "_poll_busy_time",
 217         "_rx_intr_hwater",
 218         "_rx_intr_lwater",
 219         NULL
 220 };
 221 
 222 static int nge_add_intrs(nge_t *, int);
 223 static void nge_rem_intrs(nge_t *);
 224 static int nge_register_intrs_and_init_locks(nge_t *);
 225 
 226 /*
 227  * NGE MSI tunable:
 228  */
 229 boolean_t nge_enable_msi = B_FALSE;
 230 
 231 static enum ioc_reply
 232 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
 233 {
 234         /*
 235          * If the mode isn't being changed, there's nothing to do ...
 236          */
 237         if (mode == ngep->param_loop_mode)
 238                 return (IOC_ACK);
 239 
 240         /*
 241          * Validate the requested mode and prepare a suitable message
 242          * to explain the link down/up cycle that the change will
 243          * probably induce ...
 244          */
 245         switch (mode) {
 246         default:
 247                 return (IOC_INVAL);
 248 
 249         case NGE_LOOP_NONE:
 250         case NGE_LOOP_EXTERNAL_100:
 251         case NGE_LOOP_EXTERNAL_10:
 252         case NGE_LOOP_INTERNAL_PHY:
 253                 break;
 254         }
 255 
 256         /*
 257          * All OK; tell the caller to reprogram
 258          * the PHY and/or MAC for the new mode ...
 259          */
 260         ngep->param_loop_mode = mode;
 261         return (IOC_RESTART_ACK);
 262 }
 263 
 264 #undef  NGE_DBG
 265 #define NGE_DBG         NGE_DBG_INIT
 266 
 267 /*
 268  * Utility routine to carve a slice off a chunk of allocated memory,
 269  * updating the chunk descriptor accordingly.  The size of the slice
 270  * is given by the product of the <qty> and <size> parameters.
 271  */
 272 void
 273 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
 274     uint32_t qty, uint32_t size)
 275 {
 276         size_t totsize;
 277 
 278         totsize = qty*size;
 279         ASSERT(size > 0);
 280         ASSERT(totsize <= chunk->alength);
 281 
 282         *slice = *chunk;
 283         slice->nslots = qty;
 284         slice->size = size;
 285         slice->alength = totsize;
 286 
 287         chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
 288         chunk->alength -= totsize;
 289         chunk->offset += totsize;
 290         chunk->cookie.dmac_laddress += totsize;
 291         chunk->cookie.dmac_size -= totsize;
 292 }
 293 
 294 /*
 295  * Allocate an area of memory and a DMA handle for accessing it
 296  */
 297 int
 298 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
 299     uint_t dma_flags, dma_area_t *dma_p)
 300 {
 301         int err;
 302         caddr_t va;
 303 
 304         NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
 305             (void *)ngep, memsize, attr_p, dma_flags, dma_p));
 306         /*
 307          * Allocate handle
 308          */
 309         err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
 310             DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
 311         if (err != DDI_SUCCESS)
 312                 goto fail;
 313 
 314         /*
 315          * Allocate memory
 316          */
 317         err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
 318             dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
 319             DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
 320         if (err != DDI_SUCCESS)
 321                 goto fail;
 322 
 323         /*
 324          * Bind the two together
 325          */
 326         dma_p->mem_va = va;
 327         err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
 328             va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
 329             &dma_p->cookie, &dma_p->ncookies);
 330 
 331         if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
 332                 goto fail;
 333 
 334         dma_p->nslots = ~0U;
 335         dma_p->size = ~0U;
 336         dma_p->offset = 0;
 337 
 338         return (DDI_SUCCESS);
 339 
 340 fail:
 341         nge_free_dma_mem(dma_p);
 342         NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
 343 
 344         return (DDI_FAILURE);
 345 }
 346 
 347 /*
 348  * Free one allocated area of DMAable memory
 349  */
 350 void
 351 nge_free_dma_mem(dma_area_t *dma_p)
 352 {
 353         if (dma_p->dma_hdl != NULL) {
 354                 if (dma_p->ncookies) {
 355                         (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
 356                         dma_p->ncookies = 0;
 357                 }
 358         }
 359         if (dma_p->acc_hdl != NULL) {
 360                 ddi_dma_mem_free(&dma_p->acc_hdl);
 361                 dma_p->acc_hdl = NULL;
 362         }
 363         if (dma_p->dma_hdl != NULL) {
 364                 ddi_dma_free_handle(&dma_p->dma_hdl);
 365                 dma_p->dma_hdl = NULL;
 366         }
 367 }
 368 
 369 #define ALLOC_TX_BUF    0x1
 370 #define ALLOC_TX_DESC   0x2
 371 #define ALLOC_RX_DESC   0x4
 372 
 373 int
 374 nge_alloc_bufs(nge_t *ngep)
 375 {
 376         int err;
 377         int split;
 378         int progress;
 379         size_t txbuffsize;
 380         size_t rxdescsize;
 381         size_t txdescsize;
 382 
 383         txbuffsize = ngep->tx_desc * ngep->buf_size;
 384         rxdescsize = ngep->rx_desc;
 385         txdescsize = ngep->tx_desc;
 386         rxdescsize *= ngep->desc_attr.rxd_size;
 387         txdescsize *= ngep->desc_attr.txd_size;
 388         progress = 0;
 389 
 390         NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
 391         /*
 392          * Allocate memory & handles for TX buffers
 393          */
 394         ASSERT((txbuffsize % ngep->nge_split) == 0);
 395         for (split = 0; split < ngep->nge_split; ++split) {
 396                 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
 397                     &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
 398                     &ngep->send->buf[split]);
 399                 if (err != DDI_SUCCESS)
 400                         goto fail;
 401         }
 402 
 403         progress |= ALLOC_TX_BUF;
 404 
 405         /*
 406          * Allocate memory & handles for receive return rings and
 407          * buffer (producer) descriptor rings
 408          */
 409         err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
 410             DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
 411         if (err != DDI_SUCCESS)
 412                 goto fail;
 413         progress |= ALLOC_RX_DESC;
 414 
 415         /*
 416          * Allocate memory & handles for TX descriptor rings,
 417          */
 418         err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
 419             DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
 420         if (err != DDI_SUCCESS)
 421                 goto fail;
 422         return (DDI_SUCCESS);
 423 
 424 fail:
 425         if (progress & ALLOC_RX_DESC)
 426                 nge_free_dma_mem(&ngep->recv->desc);
 427         if (progress & ALLOC_TX_BUF) {
 428                 for (split = 0; split < ngep->nge_split; ++split)
 429                         nge_free_dma_mem(&ngep->send->buf[split]);
 430         }
 431 
 432         return (DDI_FAILURE);
 433 }
 434 
 435 /*
 436  * This routine frees the transmit and receive buffers and descriptors.
 437  * Make sure the chip is stopped before calling it!
 438  */
 439 void
 440 nge_free_bufs(nge_t *ngep)
 441 {
 442         int split;
 443 
 444         NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
 445 
 446         nge_free_dma_mem(&ngep->recv->desc);
 447         nge_free_dma_mem(&ngep->send->desc);
 448 
 449         for (split = 0; split < ngep->nge_split; ++split)
 450                 nge_free_dma_mem(&ngep->send->buf[split]);
 451 }
 452 
 453 /*
 454  * Clean up initialisation done above before the memory is freed
 455  */
 456 static void
 457 nge_fini_send_ring(nge_t *ngep)
 458 {
 459         uint32_t slot;
 460         size_t dmah_num;
 461         send_ring_t *srp;
 462         sw_tx_sbd_t *ssbdp;
 463 
 464         srp = ngep->send;
 465         ssbdp = srp->sw_sbds;
 466 
 467         NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
 468 
 469         dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
 470 
 471         for (slot = 0; slot < dmah_num; ++slot) {
 472                 if (srp->dmahndl[slot].hndl) {
 473                         (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
 474                         ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
 475                         srp->dmahndl[slot].hndl = NULL;
 476                         srp->dmahndl[slot].next = NULL;
 477                 }
 478         }
 479 
 480         srp->dmah_free.head = NULL;
 481         srp->dmah_free.tail = NULL;
 482 
 483         kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
 484 
 485 }
 486 
 487 /*
 488  * Initialise the specified Send Ring, using the information in the
 489  * <dma_area> descriptors that it contains to set up all the other
 490  * fields. This routine should be called only once for each ring.
 491  */
 492 static int
 493 nge_init_send_ring(nge_t *ngep)
 494 {
 495         size_t dmah_num;
 496         uint32_t nslots;
 497         uint32_t err;
 498         uint32_t slot;
 499         uint32_t split;
 500         send_ring_t *srp;
 501         sw_tx_sbd_t *ssbdp;
 502         dma_area_t desc;
 503         dma_area_t pbuf;
 504 
 505         srp = ngep->send;
 506         srp->desc.nslots = ngep->tx_desc;
 507         nslots = srp->desc.nslots;
 508 
 509         NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
 510         /*
 511          * Other one-off initialisation of per-ring data
 512          */
 513         srp->ngep = ngep;
 514 
 515         /*
 516          * Allocate the array of s/w Send Buffer Descriptors
 517          */
 518         ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
 519         srp->sw_sbds = ssbdp;
 520 
 521         /*
 522          * Now initialise each array element once and for all
 523          */
 524         desc = srp->desc;
 525         for (split = 0; split < ngep->nge_split; ++split) {
 526                 pbuf = srp->buf[split];
 527                 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
 528                         nge_slice_chunk(&ssbdp->desc, &desc, 1,
 529                             ngep->desc_attr.txd_size);
 530                         nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
 531                             ngep->buf_size);
 532                 }
 533                 ASSERT(pbuf.alength == 0);
 534         }
 535         ASSERT(desc.alength == 0);
 536 
 537         dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
 538 
 539         /* preallocate dma handles for tx buffer */
 540         for (slot = 0; slot < dmah_num; ++slot) {
 541 
 542                 err = ddi_dma_alloc_handle(ngep->devinfo,
 543                     ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
 544                     NULL, &srp->dmahndl[slot].hndl);
 545 
 546                 if (err != DDI_SUCCESS) {
 547                         nge_fini_send_ring(ngep);
 548                         nge_error(ngep,
 549                             "nge_init_send_ring: alloc dma handle fails");
 550                         return (DDI_FAILURE);
 551                 }
 552                 srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
 553         }
 554 
 555         srp->dmah_free.head = srp->dmahndl;
 556         srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
 557         srp->dmah_free.tail->next = NULL;
 558 
 559         return (DDI_SUCCESS);
 560 }
 561 
 562 /*
 563  * Intialize the tx recycle pointer and tx sending pointer of tx ring
 564  * and set the type of tx's data descriptor by default.
 565  */
 566 static void
 567 nge_reinit_send_ring(nge_t *ngep)
 568 {
 569         size_t dmah_num;
 570         uint32_t slot;
 571         send_ring_t *srp;
 572         sw_tx_sbd_t *ssbdp;
 573 
 574         srp = ngep->send;
 575 
 576         /*
 577          * Reinitialise control variables ...
 578          */
 579 
 580         srp->tx_hwmark = NGE_DESC_MIN;
 581         srp->tx_lwmark = NGE_DESC_MIN;
 582 
 583         srp->tx_next = 0;
 584         srp->tx_free = srp->desc.nslots;
 585         srp->tc_next = 0;
 586 
 587         dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
 588 
 589         for (slot = 0; slot - dmah_num != 0; ++slot)
 590                 srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
 591 
 592         srp->dmah_free.head = srp->dmahndl;
 593         srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
 594         srp->dmah_free.tail->next = NULL;
 595 
 596         /*
 597          * Zero and sync all the h/w Send Buffer Descriptors
 598          */
 599         for (slot = 0; slot < srp->desc.nslots; ++slot) {
 600                 ssbdp = &srp->sw_sbds[slot];
 601                 ssbdp->flags = HOST_OWN;
 602         }
 603 
 604         DMA_ZERO(srp->desc);
 605         DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
 606 }
 607 
 608 /*
 609  * Initialize the slot number of rx's ring
 610  */
 611 static void
 612 nge_init_recv_ring(nge_t *ngep)
 613 {
 614         recv_ring_t *rrp;
 615 
 616         rrp = ngep->recv;
 617         rrp->desc.nslots = ngep->rx_desc;
 618         rrp->ngep = ngep;
 619 }
 620 
 621 /*
 622  * Intialize the rx recycle pointer and rx sending pointer of rx ring
 623  */
 624 static void
 625 nge_reinit_recv_ring(nge_t *ngep)
 626 {
 627         recv_ring_t *rrp;
 628 
 629         rrp = ngep->recv;
 630 
 631         /*
 632          * Reinitialise control variables ...
 633          */
 634         rrp->prod_index = 0;
 635         /*
 636          * Zero and sync all the h/w Send Buffer Descriptors
 637          */
 638         DMA_ZERO(rrp->desc);
 639         DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
 640 }
 641 
 642 /*
 643  * Clean up initialisation done above before the memory is freed
 644  */
 645 static void
 646 nge_fini_buff_ring(nge_t *ngep)
 647 {
 648         uint32_t i;
 649         buff_ring_t *brp;
 650         dma_area_t *bufp;
 651         sw_rx_sbd_t *bsbdp;
 652 
 653         brp = ngep->buff;
 654         bsbdp = brp->sw_rbds;
 655 
 656         NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
 657 
 658         mutex_enter(brp->recycle_lock);
 659         brp->buf_sign++;
 660         mutex_exit(brp->recycle_lock);
 661         for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
 662                 if (bsbdp->bufp) {
 663                         if (bsbdp->bufp->mp)
 664                                 freemsg(bsbdp->bufp->mp);
 665                         nge_free_dma_mem(bsbdp->bufp);
 666                         kmem_free(bsbdp->bufp, sizeof (dma_area_t));
 667                         bsbdp->bufp = NULL;
 668                 }
 669         }
 670         while (brp->free_list != NULL) {
 671                 bufp = brp->free_list;
 672                 brp->free_list = bufp->next;
 673                 bufp->next = NULL;
 674                 if (bufp->mp)
 675                         freemsg(bufp->mp);
 676                 nge_free_dma_mem(bufp);
 677                 kmem_free(bufp, sizeof (dma_area_t));
 678         }
 679         while (brp->recycle_list != NULL) {
 680                 bufp = brp->recycle_list;
 681                 brp->recycle_list = bufp->next;
 682                 bufp->next = NULL;
 683                 if (bufp->mp)
 684                         freemsg(bufp->mp);
 685                 nge_free_dma_mem(bufp);
 686                 kmem_free(bufp, sizeof (dma_area_t));
 687         }
 688 
 689 
 690         kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
 691         brp->sw_rbds = NULL;
 692 }
 693 
 694 /*
 695  * Intialize the Rx's data ring and free ring
 696  */
 697 static int
 698 nge_init_buff_ring(nge_t *ngep)
 699 {
 700         uint32_t err;
 701         uint32_t slot;
 702         uint32_t nslots_buff;
 703         uint32_t nslots_recv;
 704         buff_ring_t *brp;
 705         recv_ring_t *rrp;
 706         dma_area_t desc;
 707         dma_area_t *bufp;
 708         sw_rx_sbd_t *bsbdp;
 709 
 710         rrp = ngep->recv;
 711         brp = ngep->buff;
 712         brp->nslots = ngep->rx_buf;
 713         brp->rx_bcopy = B_FALSE;
 714         nslots_recv = rrp->desc.nslots;
 715         nslots_buff = brp->nslots;
 716         brp->ngep = ngep;
 717 
 718         NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
 719 
 720         /*
 721          * Allocate the array of s/w Recv Buffer Descriptors
 722          */
 723         bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
 724         brp->sw_rbds = bsbdp;
 725         brp->free_list = NULL;
 726         brp->recycle_list = NULL;
 727         for (slot = 0; slot < nslots_buff; ++slot) {
 728                 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
 729                 err = nge_alloc_dma_mem(ngep, (ngep->buf_size
 730                     + NGE_HEADROOM),
 731                     &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
 732                 if (err != DDI_SUCCESS) {
 733                         kmem_free(bufp, sizeof (dma_area_t));
 734                         return (DDI_FAILURE);
 735                 }
 736 
 737                 bufp->alength -= NGE_HEADROOM;
 738                 bufp->offset += NGE_HEADROOM;
 739                 bufp->private = (caddr_t)ngep;
 740                 bufp->rx_recycle.free_func = nge_recv_recycle;
 741                 bufp->rx_recycle.free_arg = (caddr_t)bufp;
 742                 bufp->signature = brp->buf_sign;
 743                 bufp->rx_delivered = B_FALSE;
 744                 bufp->mp = desballoc(DMA_VPTR(*bufp),
 745                     ngep->buf_size + NGE_HEADROOM,
 746                     0, &bufp->rx_recycle);
 747 
 748                 if (bufp->mp == NULL) {
 749                         return (DDI_FAILURE);
 750                 }
 751                 bufp->next = brp->free_list;
 752                 brp->free_list = bufp;
 753         }
 754 
 755         /*
 756          * Now initialise each array element once and for all
 757          */
 758         desc = rrp->desc;
 759         for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
 760                 nge_slice_chunk(&bsbdp->desc, &desc, 1,
 761                     ngep->desc_attr.rxd_size);
 762                 bufp = brp->free_list;
 763                 brp->free_list = bufp->next;
 764                 bsbdp->bufp = bufp;
 765                 bsbdp->flags = CONTROLER_OWN;
 766                 bufp->next = NULL;
 767         }
 768 
 769         ASSERT(desc.alength == 0);
 770         return (DDI_SUCCESS);
 771 }
 772 
 773 /*
 774  * Fill the host address of data in rx' descriptor
 775  * and initialize free pointers of rx free ring
 776  */
 777 static int
 778 nge_reinit_buff_ring(nge_t *ngep)
 779 {
 780         uint32_t slot;
 781         uint32_t nslots_recv;
 782         buff_ring_t *brp;
 783         recv_ring_t *rrp;
 784         sw_rx_sbd_t *bsbdp;
 785         void *hw_bd_p;
 786 
 787         brp = ngep->buff;
 788         rrp = ngep->recv;
 789         bsbdp = brp->sw_rbds;
 790         nslots_recv = rrp->desc.nslots;
 791         for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
 792                 hw_bd_p = DMA_VPTR(bsbdp->desc);
 793         /*
 794          * There is a scenario: When the traffic of small tcp
 795          * packet is heavy, suspending the tcp traffic will
 796          * cause the preallocated buffers for rx not to be
 797          * released in time by tcp taffic and cause rx's buffer
 798          * pointers not to be refilled in time.
 799          *
 800          * At this point, if we reinitialize the driver, the bufp
 801          * pointer for rx's traffic will be NULL.
 802          * So the result of the reinitializion fails.
 803          */
 804                 if (bsbdp->bufp == NULL)
 805                         return (DDI_FAILURE);
 806 
 807                 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
 808                     bsbdp->bufp->alength);
 809         }
 810         return (DDI_SUCCESS);
 811 }
 812 
 813 static void
 814 nge_init_ring_param_lock(nge_t *ngep)
 815 {
 816         buff_ring_t *brp;
 817         send_ring_t *srp;
 818 
 819         srp = ngep->send;
 820         brp = ngep->buff;
 821 
 822         /* Init the locks for send ring */
 823         mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
 824             DDI_INTR_PRI(ngep->intr_pri));
 825         mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
 826             DDI_INTR_PRI(ngep->intr_pri));
 827         mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
 828             DDI_INTR_PRI(ngep->intr_pri));
 829 
 830         /* Init parameters of buffer ring */
 831         brp->free_list = NULL;
 832         brp->recycle_list = NULL;
 833         brp->rx_hold = 0;
 834         brp->buf_sign = 0;
 835 
 836         /* Init recycle list lock */
 837         mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
 838             DDI_INTR_PRI(ngep->intr_pri));
 839 }
 840 
 841 int
 842 nge_init_rings(nge_t *ngep)
 843 {
 844         uint32_t err;
 845 
 846         err = nge_init_send_ring(ngep);
 847         if (err != DDI_SUCCESS) {
 848                 return (err);
 849         }
 850         nge_init_recv_ring(ngep);
 851 
 852         err = nge_init_buff_ring(ngep);
 853         if (err != DDI_SUCCESS) {
 854                 nge_fini_send_ring(ngep);
 855                 return (DDI_FAILURE);
 856         }
 857 
 858         return (err);
 859 }
 860 
 861 static int
 862 nge_reinit_ring(nge_t *ngep)
 863 {
 864         int err;
 865 
 866         nge_reinit_recv_ring(ngep);
 867         nge_reinit_send_ring(ngep);
 868         err = nge_reinit_buff_ring(ngep);
 869         return (err);
 870 }
 871 
 872 
 873 void
 874 nge_fini_rings(nge_t *ngep)
 875 {
 876         /*
 877          * For receive ring, nothing need to be finished.
 878          * So only finish buffer ring and send ring here.
 879          */
 880         nge_fini_buff_ring(ngep);
 881         nge_fini_send_ring(ngep);
 882 }
 883 
 884 /*
 885  * Loopback ioctl code
 886  */
 887 
 888 static lb_property_t loopmodes[] = {
 889         { normal,       "normal",       NGE_LOOP_NONE           },
 890         { external,     "100Mbps",      NGE_LOOP_EXTERNAL_100   },
 891         { external,     "10Mbps",       NGE_LOOP_EXTERNAL_10    },
 892         { internal,     "PHY",          NGE_LOOP_INTERNAL_PHY   },
 893 };
 894 
 895 enum ioc_reply
 896 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
 897 {
 898         int cmd;
 899         uint32_t *lbmp;
 900         lb_info_sz_t *lbsp;
 901         lb_property_t *lbpp;
 902 
 903         /*
 904          * Validate format of ioctl
 905          */
 906         if (mp->b_cont == NULL)
 907                 return (IOC_INVAL);
 908 
 909         cmd = iocp->ioc_cmd;
 910 
 911         switch (cmd) {
 912         default:
 913                 return (IOC_INVAL);
 914 
 915         case LB_GET_INFO_SIZE:
 916                 if (iocp->ioc_count != sizeof (lb_info_sz_t))
 917                         return (IOC_INVAL);
 918                 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
 919                 *lbsp = sizeof (loopmodes);
 920                 return (IOC_REPLY);
 921 
 922         case LB_GET_INFO:
 923                 if (iocp->ioc_count != sizeof (loopmodes))
 924                         return (IOC_INVAL);
 925                 lbpp = (lb_property_t *)mp->b_cont->b_rptr;
 926                 bcopy(loopmodes, lbpp, sizeof (loopmodes));
 927                 return (IOC_REPLY);
 928 
 929         case LB_GET_MODE:
 930                 if (iocp->ioc_count != sizeof (uint32_t))
 931                         return (IOC_INVAL);
 932                 lbmp = (uint32_t *)mp->b_cont->b_rptr;
 933                 *lbmp = ngep->param_loop_mode;
 934                 return (IOC_REPLY);
 935 
 936         case LB_SET_MODE:
 937                 if (iocp->ioc_count != sizeof (uint32_t))
 938                         return (IOC_INVAL);
 939                 lbmp = (uint32_t *)mp->b_cont->b_rptr;
 940                 return (nge_set_loop_mode(ngep, *lbmp));
 941         }
 942 }
 943 
 944 #undef  NGE_DBG
 945 #define NGE_DBG NGE_DBG_NEMO
 946 
 947 
 948 static void
 949 nge_check_desc_prop(nge_t *ngep)
 950 {
 951         if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
 952                 ngep->desc_mode = DESC_HOT;
 953 
 954         if (ngep->desc_mode == DESC_OFFLOAD) {
 955 
 956                 ngep->desc_attr = nge_sum_desc;
 957 
 958         }       else if (ngep->desc_mode == DESC_HOT)        {
 959 
 960                 ngep->desc_attr = nge_hot_desc;
 961         }
 962 }
 963 
 964 /*
 965  * nge_get_props -- get the parameters to tune the driver
 966  */
 967 static void
 968 nge_get_props(nge_t *ngep)
 969 {
 970         chip_info_t *infop;
 971         dev_info_t *devinfo;
 972         nge_dev_spec_param_t *dev_param_p;
 973 
 974         devinfo = ngep->devinfo;
 975         infop = (chip_info_t *)&ngep->chipinfo;
 976         dev_param_p = &ngep->dev_spec_param;
 977 
 978         infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 979             DDI_PROP_DONTPASS, clsize_propname, 32);
 980 
 981         infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 982             DDI_PROP_DONTPASS, latency_propname, 64);
 983         ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 984             DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
 985         ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 986             DDI_PROP_DONTPASS, rx_data_hw, 0x20);
 987         ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 988             DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
 989         ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 990             DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
 991 
 992         ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 993             DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
 994         ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 995             DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
 996         ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 997             DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
 998         ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
 999             DDI_PROP_DONTPASS, low_memory_mode, 0);
1000 
1001         if (dev_param_p->jumbo) {
1002                 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
1003                     DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
1004         } else
1005                 ngep->default_mtu = ETHERMTU;
1006         if (dev_param_p->tx_pause_frame)
1007                         ngep->param_link_tx_pause = B_TRUE;
1008         else
1009                         ngep->param_link_tx_pause = B_FALSE;
1010 
1011         if (dev_param_p->rx_pause_frame)
1012                         ngep->param_link_rx_pause = B_TRUE;
1013         else
1014                         ngep->param_link_rx_pause = B_FALSE;
1015 
1016         if (ngep->default_mtu > ETHERMTU &&
1017             ngep->default_mtu <= NGE_MTU_2500) {
1018                 ngep->buf_size = NGE_JB2500_BUFSZ;
1019                 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
1020                 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
1021                 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
1022                 ngep->nge_split = NGE_SPLIT_256;
1023         } else if (ngep->default_mtu > NGE_MTU_2500 &&
1024             ngep->default_mtu <= NGE_MTU_4500) {
1025                 ngep->buf_size = NGE_JB4500_BUFSZ;
1026                 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
1027                 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
1028                 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
1029                 ngep->nge_split = NGE_SPLIT_256;
1030         } else if (ngep->default_mtu > NGE_MTU_4500 &&
1031             ngep->default_mtu <= NGE_MAX_MTU) {
1032                 ngep->buf_size = NGE_JB9000_BUFSZ;
1033                 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1034                 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1035                 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1036                 ngep->nge_split = NGE_SPLIT_256;
1037         } else if (ngep->default_mtu > NGE_MAX_MTU) {
1038                 ngep->default_mtu = NGE_MAX_MTU;
1039                 ngep->buf_size = NGE_JB9000_BUFSZ;
1040                 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1041                 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1042                 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1043                 ngep->nge_split = NGE_SPLIT_256;
1044         } else if (ngep->lowmem_mode != 0) {
1045                 ngep->default_mtu = ETHERMTU;
1046                 ngep->buf_size = NGE_STD_BUFSZ;
1047                 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
1048                 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
1049                 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
1050                 ngep->nge_split = NGE_SPLIT_32;
1051         } else {
1052                 ngep->default_mtu = ETHERMTU;
1053                 ngep->buf_size = NGE_STD_BUFSZ;
1054                 ngep->tx_desc = dev_param_p->tx_desc_num;
1055                 ngep->rx_desc = dev_param_p->rx_desc_num;
1056                 ngep->rx_buf = dev_param_p->rx_desc_num * 2;
1057                 ngep->nge_split = dev_param_p->nge_split;
1058         }
1059 
1060         nge_check_desc_prop(ngep);
1061 }
1062 
1063 
1064 static int
1065 nge_reset_dev(nge_t *ngep)
1066 {
1067         int err;
1068         nge_mul_addr1 maddr1;
1069         nge_sw_statistics_t *sw_stp;
1070         sw_stp = &ngep->statistics.sw_statistics;
1071         send_ring_t *srp = ngep->send;
1072 
1073         ASSERT(mutex_owned(ngep->genlock));
1074         mutex_enter(srp->tc_lock);
1075         mutex_enter(srp->tx_lock);
1076 
1077         nge_tx_recycle_all(ngep);
1078         err = nge_reinit_ring(ngep);
1079         if (err == DDI_FAILURE) {
1080                 mutex_exit(srp->tx_lock);
1081                 mutex_exit(srp->tc_lock);
1082                 return (err);
1083         }
1084         err = nge_chip_reset(ngep);
1085         /*
1086          * Clear the Multicast mac address table
1087          */
1088         nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
1089         maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
1090         maddr1.addr_bits.addr = 0;
1091         nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
1092 
1093         mutex_exit(srp->tx_lock);
1094         mutex_exit(srp->tc_lock);
1095         if (err == DDI_FAILURE)
1096                 return (err);
1097         ngep->watchdog = 0;
1098         ngep->resched_needed = B_FALSE;
1099         ngep->promisc = B_FALSE;
1100         ngep->param_loop_mode = NGE_LOOP_NONE;
1101         ngep->factotum_flag = 0;
1102         ngep->resched_needed = 0;
1103         ngep->nge_mac_state = NGE_MAC_RESET;
1104         ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
1105         ngep->max_sdu += VTAG_SIZE;
1106         ngep->rx_def = 0x16;
1107 
1108         /* Clear the software statistics */
1109         sw_stp->recv_count = 0;
1110         sw_stp->xmit_count = 0;
1111         sw_stp->rbytes = 0;
1112         sw_stp->obytes = 0;
1113 
1114         return (DDI_SUCCESS);
1115 }
1116 
1117 static void
1118 nge_m_stop(void *arg)
1119 {
1120         nge_t *ngep = arg;              /* private device info  */
1121         int err;
1122 
1123         NGE_TRACE(("nge_m_stop($%p)", arg));
1124 
1125         /*
1126          * Just stop processing, then record new MAC state
1127          */
1128         mutex_enter(ngep->genlock);
1129         /* If suspended, the adapter is already stopped, just return. */
1130         if (ngep->suspended) {
1131                 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
1132                 mutex_exit(ngep->genlock);
1133                 return;
1134         }
1135         rw_enter(ngep->rwlock, RW_WRITER);
1136 
1137         err = nge_chip_stop(ngep, B_FALSE);
1138         if (err == DDI_FAILURE)
1139                 err = nge_chip_reset(ngep);
1140         if (err == DDI_FAILURE)
1141                 nge_problem(ngep, "nge_m_stop: stop chip failed");
1142         ngep->nge_mac_state = NGE_MAC_STOPPED;
1143 
1144         /* Recycle all the TX BD */
1145         nge_tx_recycle_all(ngep);
1146         nge_fini_rings(ngep);
1147         nge_free_bufs(ngep);
1148 
1149         NGE_DEBUG(("nge_m_stop($%p) done", arg));
1150 
1151         rw_exit(ngep->rwlock);
1152         mutex_exit(ngep->genlock);
1153 }
1154 
1155 static int
1156 nge_m_start(void *arg)
1157 {
1158         int err;
1159         nge_t *ngep = arg;
1160 
1161         NGE_TRACE(("nge_m_start($%p)", arg));
1162 
1163         /*
1164          * Start processing and record new MAC state
1165          */
1166         mutex_enter(ngep->genlock);
1167         /*
1168          * If suspended, don't start, as the resume processing
1169          * will recall this function with the suspended flag off.
1170          */
1171         if (ngep->suspended) {
1172                 mutex_exit(ngep->genlock);
1173                 return (EIO);
1174         }
1175         rw_enter(ngep->rwlock, RW_WRITER);
1176         err = nge_alloc_bufs(ngep);
1177         if (err != DDI_SUCCESS) {
1178                 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
1179                 goto finish;
1180         }
1181         err = nge_init_rings(ngep);
1182         if (err != DDI_SUCCESS) {
1183                 nge_free_bufs(ngep);
1184                 nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
1185                 goto finish;
1186         }
1187         err = nge_restart(ngep);
1188 
1189         NGE_DEBUG(("nge_m_start($%p) done", arg));
1190 finish:
1191         rw_exit(ngep->rwlock);
1192         mutex_exit(ngep->genlock);
1193 
1194         return (err == DDI_SUCCESS ? 0 : EIO);
1195 }
1196 
1197 static int
1198 nge_m_unicst(void *arg, const uint8_t *macaddr)
1199 {
1200         nge_t *ngep = arg;
1201 
1202         NGE_TRACE(("nge_m_unicst($%p)", arg));
1203         /*
1204          * Remember the new current address in the driver state
1205          * Sync the chip's idea of the address too ...
1206          */
1207         mutex_enter(ngep->genlock);
1208 
1209         ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
1210         ngep->cur_uni_addr.set = 1;
1211 
1212         /*
1213          * If we are suspended, we want to quit now, and not update
1214          * the chip.  Doing so might put it in a bad state, but the
1215          * resume will get the unicast address installed.
1216          */
1217         if (ngep->suspended) {
1218                 mutex_exit(ngep->genlock);
1219                 return (DDI_SUCCESS);
1220         }
1221         nge_chip_sync(ngep);
1222 
1223         NGE_DEBUG(("nge_m_unicst($%p) done", arg));
1224         mutex_exit(ngep->genlock);
1225 
1226         return (0);
1227 }
1228 
1229 static int
1230 nge_m_promisc(void *arg, boolean_t on)
1231 {
1232         nge_t *ngep = arg;
1233 
1234         NGE_TRACE(("nge_m_promisc($%p)", arg));
1235 
1236         /*
1237          * Store specified mode and pass to chip layer to update h/w
1238          */
1239         mutex_enter(ngep->genlock);
1240         /*
1241          * If suspended, there is no need to do anything, even
1242          * recording the promiscuious mode is not neccessary, as
1243          * it won't be properly set on resume.  Just return failing.
1244          */
1245         if (ngep->suspended) {
1246                 mutex_exit(ngep->genlock);
1247                 return (DDI_FAILURE);
1248         }
1249         if (ngep->promisc == on) {
1250                 mutex_exit(ngep->genlock);
1251                 NGE_DEBUG(("nge_m_promisc($%p) done", arg));
1252                 return (0);
1253         }
1254         ngep->promisc = on;
1255         ngep->record_promisc = ngep->promisc;
1256         nge_chip_sync(ngep);
1257         NGE_DEBUG(("nge_m_promisc($%p) done", arg));
1258         mutex_exit(ngep->genlock);
1259 
1260         return (0);
1261 }
1262 
1263 static void nge_mulparam(nge_t *ngep)
1264 {
1265         uint8_t number;
1266         ether_addr_t pand;
1267         ether_addr_t por;
1268         mul_item *plist;
1269 
1270         for (number = 0; number < ETHERADDRL; number++) {
1271                 pand[number] = 0x00;
1272                 por[number] = 0x00;
1273         }
1274         for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
1275                 for (number = 0; number < ETHERADDRL; number++) {
1276                         pand[number] &= plist->mul_addr[number];
1277                         por[number] |= plist->mul_addr[number];
1278                 }
1279         }
1280         for (number = 0; number < ETHERADDRL; number++) {
1281                 ngep->cur_mul_addr.addr[number]
1282                     = pand[number] & por[number];
1283                 ngep->cur_mul_mask.addr[number]
1284                     = pand [number] | (~por[number]);
1285         }
1286 }
1287 static int
1288 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1289 {
1290         boolean_t update;
1291         boolean_t b_eq;
1292         nge_t *ngep = arg;
1293         mul_item *plist;
1294         mul_item *plist_prev;
1295         mul_item *pitem;
1296 
1297         NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
1298             (add) ? "add" : "remove", ether_sprintf((void *)mca)));
1299 
1300         update = B_FALSE;
1301         plist = plist_prev = NULL;
1302         mutex_enter(ngep->genlock);
1303         if (add) {
1304                 if (ngep->pcur_mulist != NULL) {
1305                         for (plist = ngep->pcur_mulist; plist != NULL;
1306                             plist = plist->next) {
1307                                 b_eq = ether_eq(plist->mul_addr, mca);
1308                                 if (b_eq) {
1309                                         plist->ref_cnt++;
1310                                         break;
1311                                 }
1312                                 plist_prev = plist;
1313                         }
1314                 }
1315 
1316                 if (plist == NULL) {
1317                         pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
1318                         ether_copy(mca, pitem->mul_addr);
1319                         pitem ->ref_cnt++;
1320                         pitem ->next = NULL;
1321                         if (plist_prev == NULL)
1322                                 ngep->pcur_mulist = pitem;
1323                         else
1324                                 plist_prev->next = pitem;
1325                         update = B_TRUE;
1326                 }
1327         } else {
1328                 if (ngep->pcur_mulist != NULL) {
1329                         for (plist = ngep->pcur_mulist; plist != NULL;
1330                             plist = plist->next) {
1331                                 b_eq = ether_eq(plist->mul_addr, mca);
1332                                 if (b_eq) {
1333                                         update = B_TRUE;
1334                                         break;
1335                                 }
1336                                 plist_prev = plist;
1337                         }
1338 
1339                         if (update) {
1340                                 if ((plist_prev == NULL) &&
1341                                     (plist->next == NULL))
1342                                         ngep->pcur_mulist = NULL;
1343                                 else if ((plist_prev == NULL) &&
1344                                     (plist->next != NULL))
1345                                         ngep->pcur_mulist = plist->next;
1346                                 else
1347                                         plist_prev->next = plist->next;
1348                                 kmem_free(plist, sizeof (mul_item));
1349                         }
1350                 }
1351         }
1352 
1353         if (update && !ngep->suspended) {
1354                 nge_mulparam(ngep);
1355                 nge_chip_sync(ngep);
1356         }
1357         NGE_DEBUG(("nge_m_multicst($%p) done", arg));
1358         mutex_exit(ngep->genlock);
1359 
1360         return (0);
1361 }
1362 
1363 static void
1364 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1365 {
1366         int err;
1367         int cmd;
1368         nge_t *ngep = arg;
1369         struct iocblk *iocp;
1370         enum ioc_reply status;
1371         boolean_t need_privilege;
1372 
1373         /*
1374          * If suspended, we might actually be able to do some of
1375          * these ioctls, but it is harder to make sure they occur
1376          * without actually putting the hardware in an undesireable
1377          * state.  So just NAK it.
1378          */
1379         mutex_enter(ngep->genlock);
1380         if (ngep->suspended) {
1381                 miocnak(wq, mp, 0, EINVAL);
1382                 mutex_exit(ngep->genlock);
1383                 return;
1384         }
1385         mutex_exit(ngep->genlock);
1386 
1387         /*
1388          * Validate the command before bothering with the mutex ...
1389          */
1390         iocp = (struct iocblk *)mp->b_rptr;
1391         iocp->ioc_error = 0;
1392         need_privilege = B_TRUE;
1393         cmd = iocp->ioc_cmd;
1394 
1395         NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
1396         switch (cmd) {
1397         default:
1398                 NGE_LDB(NGE_DBG_BADIOC,
1399                     ("nge_m_ioctl: unknown cmd 0x%x", cmd));
1400 
1401                 miocnak(wq, mp, 0, EINVAL);
1402                 return;
1403 
1404         case NGE_MII_READ:
1405         case NGE_MII_WRITE:
1406         case NGE_SEE_READ:
1407         case NGE_SEE_WRITE:
1408         case NGE_DIAG:
1409         case NGE_PEEK:
1410         case NGE_POKE:
1411         case NGE_PHY_RESET:
1412         case NGE_SOFT_RESET:
1413         case NGE_HARD_RESET:
1414                 break;
1415 
1416         case LB_GET_INFO_SIZE:
1417         case LB_GET_INFO:
1418         case LB_GET_MODE:
1419                 need_privilege = B_FALSE;
1420                 break;
1421         case LB_SET_MODE:
1422                 break;
1423         }
1424 
1425         if (need_privilege) {
1426                 /*
1427                  * Check for specific net_config privilege.
1428                  */
1429                 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1430                 if (err != 0) {
1431                         NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
1432                             cmd, err));
1433                         miocnak(wq, mp, 0, err);
1434                         return;
1435                 }
1436         }
1437 
1438         mutex_enter(ngep->genlock);
1439 
1440         switch (cmd) {
1441         default:
1442                 _NOTE(NOTREACHED)
1443                 status = IOC_INVAL;
1444         break;
1445 
1446         case NGE_MII_READ:
1447         case NGE_MII_WRITE:
1448         case NGE_SEE_READ:
1449         case NGE_SEE_WRITE:
1450         case NGE_DIAG:
1451         case NGE_PEEK:
1452         case NGE_POKE:
1453         case NGE_PHY_RESET:
1454         case NGE_SOFT_RESET:
1455         case NGE_HARD_RESET:
1456                 status = nge_chip_ioctl(ngep, mp, iocp);
1457         break;
1458 
1459         case LB_GET_INFO_SIZE:
1460         case LB_GET_INFO:
1461         case LB_GET_MODE:
1462         case LB_SET_MODE:
1463                 status = nge_loop_ioctl(ngep, mp, iocp);
1464         break;
1465 
1466         }
1467 
1468         /*
1469          * Do we need to reprogram the PHY and/or the MAC?
1470          * Do it now, while we still have the mutex.
1471          *
1472          * Note: update the PHY first, 'cos it controls the
1473          * speed/duplex parameters that the MAC code uses.
1474          */
1475 
1476         NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
1477 
1478         switch (status) {
1479         case IOC_RESTART_REPLY:
1480         case IOC_RESTART_ACK:
1481                 (*ngep->physops->phys_update)(ngep);
1482                 nge_chip_sync(ngep);
1483                 break;
1484 
1485         default:
1486         break;
1487         }
1488 
1489         mutex_exit(ngep->genlock);
1490 
1491         /*
1492          * Finally, decide how to reply
1493          */
1494         switch (status) {
1495 
1496         default:
1497         case IOC_INVAL:
1498                 miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
1499                     EINVAL : iocp->ioc_error);
1500                 break;
1501 
1502         case IOC_DONE:
1503                 break;
1504 
1505         case IOC_RESTART_ACK:
1506         case IOC_ACK:
1507                 miocack(wq, mp, 0, 0);
1508                 break;
1509 
1510         case IOC_RESTART_REPLY:
1511         case IOC_REPLY:
1512                 mp->b_datap->db_type = iocp->ioc_error == 0 ?
1513                     M_IOCACK : M_IOCNAK;
1514                 qreply(wq, mp);
1515                 break;
1516         }
1517 }
1518 
1519 static boolean_t
1520 nge_param_locked(mac_prop_id_t pr_num)
1521 {
1522         /*
1523          * All adv_* parameters are locked (read-only) while
1524          * the device is in any sort of loopback mode ...
1525          */
1526         switch (pr_num) {
1527                 case MAC_PROP_ADV_1000FDX_CAP:
1528                 case MAC_PROP_EN_1000FDX_CAP:
1529                 case MAC_PROP_ADV_1000HDX_CAP:
1530                 case MAC_PROP_EN_1000HDX_CAP:
1531                 case MAC_PROP_ADV_100FDX_CAP:
1532                 case MAC_PROP_EN_100FDX_CAP:
1533                 case MAC_PROP_ADV_100HDX_CAP:
1534                 case MAC_PROP_EN_100HDX_CAP:
1535                 case MAC_PROP_ADV_10FDX_CAP:
1536                 case MAC_PROP_EN_10FDX_CAP:
1537                 case MAC_PROP_ADV_10HDX_CAP:
1538                 case MAC_PROP_EN_10HDX_CAP:
1539                 case MAC_PROP_AUTONEG:
1540                 case MAC_PROP_FLOWCTRL:
1541                         return (B_TRUE);
1542         }
1543         return (B_FALSE);
1544 }
1545 
1546 /*
1547  * callback functions for set/get of properties
1548  */
1549 static int
1550 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1551     uint_t pr_valsize, const void *pr_val)
1552 {
1553         nge_t *ngep = barg;
1554         int err = 0;
1555         uint32_t cur_mtu, new_mtu;
1556         link_flowctrl_t fl;
1557 
1558         mutex_enter(ngep->genlock);
1559         if (ngep->param_loop_mode != NGE_LOOP_NONE &&
1560             nge_param_locked(pr_num)) {
1561                 /*
1562                  * All adv_* parameters are locked (read-only)
1563                  * while the device is in any sort of loopback mode.
1564                  */
1565                 mutex_exit(ngep->genlock);
1566                 return (EBUSY);
1567         }
1568         switch (pr_num) {
1569                 case MAC_PROP_EN_1000FDX_CAP:
1570                         ngep->param_en_1000fdx = *(uint8_t *)pr_val;
1571                         ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
1572                         goto reprogram;
1573                 case MAC_PROP_EN_100FDX_CAP:
1574                         ngep->param_en_100fdx = *(uint8_t *)pr_val;
1575                         ngep->param_adv_100fdx = *(uint8_t *)pr_val;
1576                         goto reprogram;
1577                 case MAC_PROP_EN_100HDX_CAP:
1578                         ngep->param_en_100hdx = *(uint8_t *)pr_val;
1579                         ngep->param_adv_100hdx = *(uint8_t *)pr_val;
1580                         goto reprogram;
1581                 case MAC_PROP_EN_10FDX_CAP:
1582                         ngep->param_en_10fdx = *(uint8_t *)pr_val;
1583                         ngep->param_adv_10fdx = *(uint8_t *)pr_val;
1584                         goto reprogram;
1585                 case MAC_PROP_EN_10HDX_CAP:
1586                         ngep->param_en_10hdx = *(uint8_t *)pr_val;
1587                         ngep->param_adv_10hdx = *(uint8_t *)pr_val;
1588 reprogram:
1589                 (*ngep->physops->phys_update)(ngep);
1590                 nge_chip_sync(ngep);
1591                 break;
1592 
1593                 case MAC_PROP_ADV_1000FDX_CAP:
1594                 case MAC_PROP_ADV_1000HDX_CAP:
1595                 case MAC_PROP_ADV_100FDX_CAP:
1596                 case MAC_PROP_ADV_100HDX_CAP:
1597                 case MAC_PROP_ADV_10FDX_CAP:
1598                 case MAC_PROP_ADV_10HDX_CAP:
1599                 case MAC_PROP_STATUS:
1600                 case MAC_PROP_SPEED:
1601                 case MAC_PROP_DUPLEX:
1602                 case MAC_PROP_EN_1000HDX_CAP:
1603                         err = ENOTSUP; /* read-only prop. Can't set this */
1604                         break;
1605                 case MAC_PROP_AUTONEG:
1606                         ngep->param_adv_autoneg = *(uint8_t *)pr_val;
1607                         (*ngep->physops->phys_update)(ngep);
1608                         nge_chip_sync(ngep);
1609                         break;
1610                 case MAC_PROP_MTU:
1611                         cur_mtu = ngep->default_mtu;
1612                         bcopy(pr_val, &new_mtu, sizeof (new_mtu));
1613                         if (new_mtu == cur_mtu) {
1614                                 err = 0;
1615                                 break;
1616                         }
1617                         if (new_mtu < ETHERMTU ||
1618                             new_mtu > NGE_MAX_MTU) {
1619                                 err = EINVAL;
1620                                 break;
1621                         }
1622                         if ((new_mtu > ETHERMTU) &&
1623                             (!ngep->dev_spec_param.jumbo)) {
1624                                 err = EINVAL;
1625                                 break;
1626                         }
1627                         if (ngep->nge_mac_state == NGE_MAC_STARTED) {
1628                                 err = EBUSY;
1629                                 break;
1630                         }
1631 
1632                         ngep->default_mtu = new_mtu;
1633                         if (ngep->default_mtu > ETHERMTU &&
1634                             ngep->default_mtu <= NGE_MTU_2500) {
1635                                 ngep->buf_size = NGE_JB2500_BUFSZ;
1636                                 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
1637                                 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
1638                                 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
1639                                 ngep->nge_split = NGE_SPLIT_256;
1640                         } else if (ngep->default_mtu > NGE_MTU_2500 &&
1641                             ngep->default_mtu <= NGE_MTU_4500) {
1642                                 ngep->buf_size = NGE_JB4500_BUFSZ;
1643                                 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
1644                                 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
1645                                 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
1646                                 ngep->nge_split = NGE_SPLIT_256;
1647                         } else if (ngep->default_mtu > NGE_MTU_4500 &&
1648                             ngep->default_mtu <= NGE_MAX_MTU) {
1649                                 ngep->buf_size = NGE_JB9000_BUFSZ;
1650                                 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1651                                 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1652                                 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1653                                 ngep->nge_split = NGE_SPLIT_256;
1654                         } else if (ngep->default_mtu > NGE_MAX_MTU) {
1655                                 ngep->default_mtu = NGE_MAX_MTU;
1656                                 ngep->buf_size = NGE_JB9000_BUFSZ;
1657                                 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
1658                                 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
1659                                 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
1660                                 ngep->nge_split = NGE_SPLIT_256;
1661                         } else if (ngep->lowmem_mode != 0) {
1662                                 ngep->default_mtu = ETHERMTU;
1663                                 ngep->buf_size = NGE_STD_BUFSZ;
1664                                 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
1665                                 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
1666                                 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
1667                                 ngep->nge_split = NGE_SPLIT_32;
1668                         } else {
1669                                 ngep->default_mtu = ETHERMTU;
1670                                 ngep->buf_size = NGE_STD_BUFSZ;
1671                                 ngep->tx_desc =
1672                                     ngep->dev_spec_param.tx_desc_num;
1673                                 ngep->rx_desc =
1674                                     ngep->dev_spec_param.rx_desc_num;
1675                                 ngep->rx_buf =
1676                                     ngep->dev_spec_param.rx_desc_num * 2;
1677                                 ngep->nge_split =
1678                                     ngep->dev_spec_param.nge_split;
1679                         }
1680 
1681                         err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
1682 
1683                         break;
1684                 case MAC_PROP_FLOWCTRL:
1685                         bcopy(pr_val, &fl, sizeof (fl));
1686                         switch (fl) {
1687                         default:
1688                                 err = ENOTSUP;
1689                                 break;
1690                         case LINK_FLOWCTRL_NONE:
1691                                 ngep->param_adv_pause = 0;
1692                                 ngep->param_adv_asym_pause = 0;
1693 
1694                                 ngep->param_link_rx_pause = B_FALSE;
1695                                 ngep->param_link_tx_pause = B_FALSE;
1696                                 break;
1697                         case LINK_FLOWCTRL_RX:
1698                                 if (!((ngep->param_lp_pause == 0) &&
1699                                     (ngep->param_lp_asym_pause == 1))) {
1700                                         err = EINVAL;
1701                                         break;
1702                                 }
1703                                 ngep->param_adv_pause = 1;
1704                                 ngep->param_adv_asym_pause = 1;
1705 
1706                                 ngep->param_link_rx_pause = B_TRUE;
1707                                 ngep->param_link_tx_pause = B_FALSE;
1708                                 break;
1709                         case LINK_FLOWCTRL_TX:
1710                                 if (!((ngep->param_lp_pause == 1) &&
1711                                     (ngep->param_lp_asym_pause == 1))) {
1712                                         err = EINVAL;
1713                                         break;
1714                                 }
1715                                 ngep->param_adv_pause = 0;
1716                                 ngep->param_adv_asym_pause = 1;
1717 
1718                                 ngep->param_link_rx_pause = B_FALSE;
1719                                 ngep->param_link_tx_pause = B_TRUE;
1720                                 break;
1721                         case LINK_FLOWCTRL_BI:
1722                                 if (ngep->param_lp_pause != 1) {
1723                                         err = EINVAL;
1724                                         break;
1725                                 }
1726                                 ngep->param_adv_pause = 1;
1727 
1728                                 ngep->param_link_rx_pause = B_TRUE;
1729                                 ngep->param_link_tx_pause = B_TRUE;
1730                                 break;
1731                         }
1732 
1733                         if (err == 0) {
1734                                 (*ngep->physops->phys_update)(ngep);
1735                                 nge_chip_sync(ngep);
1736                         }
1737 
1738                         break;
1739                 case MAC_PROP_PRIVATE:
1740                         err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
1741                             pr_val);
1742                         if (err == 0) {
1743                                 (*ngep->physops->phys_update)(ngep);
1744                                 nge_chip_sync(ngep);
1745                         }
1746                         break;
1747                 default:
1748                         err = ENOTSUP;
1749         }
1750         mutex_exit(ngep->genlock);
1751         return (err);
1752 }
1753 
1754 static int
1755 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1756     uint_t pr_valsize, void *pr_val)
1757 {
1758         nge_t *ngep = barg;
1759         int err = 0;
1760         link_flowctrl_t fl;
1761         uint64_t speed;
1762 
1763         switch (pr_num) {
1764                 case MAC_PROP_DUPLEX:
1765                         ASSERT(pr_valsize >= sizeof (link_duplex_t));
1766                         bcopy(&ngep->param_link_duplex, pr_val,
1767                             sizeof (link_duplex_t));
1768                         break;
1769                 case MAC_PROP_SPEED:
1770                         ASSERT(pr_valsize >= sizeof (uint64_t));
1771                         speed = ngep->param_link_speed * 1000000ull;
1772                         bcopy(&speed, pr_val, sizeof (speed));
1773                         break;
1774                 case MAC_PROP_AUTONEG:
1775                         *(uint8_t *)pr_val = ngep->param_adv_autoneg;
1776                         break;
1777                 case MAC_PROP_FLOWCTRL:
1778                         ASSERT(pr_valsize >= sizeof (link_flowctrl_t));
1779                         if (ngep->param_link_rx_pause &&
1780                             !ngep->param_link_tx_pause)
1781                                 fl = LINK_FLOWCTRL_RX;
1782 
1783                         if (!ngep->param_link_rx_pause &&
1784                             !ngep->param_link_tx_pause)
1785                                 fl = LINK_FLOWCTRL_NONE;
1786 
1787                         if (!ngep->param_link_rx_pause &&
1788                             ngep->param_link_tx_pause)
1789                                 fl = LINK_FLOWCTRL_TX;
1790 
1791                         if (ngep->param_link_rx_pause &&
1792                             ngep->param_link_tx_pause)
1793                                 fl = LINK_FLOWCTRL_BI;
1794                         bcopy(&fl, pr_val, sizeof (fl));
1795                         break;
1796                 case MAC_PROP_ADV_1000FDX_CAP:
1797                         *(uint8_t *)pr_val = ngep->param_adv_1000fdx;
1798                         break;
1799                 case MAC_PROP_EN_1000FDX_CAP:
1800                         *(uint8_t *)pr_val = ngep->param_en_1000fdx;
1801                         break;
1802                 case MAC_PROP_ADV_1000HDX_CAP:
1803                         *(uint8_t *)pr_val = ngep->param_adv_1000hdx;
1804                         break;
1805                 case MAC_PROP_EN_1000HDX_CAP:
1806                         *(uint8_t *)pr_val = ngep->param_en_1000hdx;
1807                         break;
1808                 case MAC_PROP_ADV_100FDX_CAP:
1809                         *(uint8_t *)pr_val = ngep->param_adv_100fdx;
1810                         break;
1811                 case MAC_PROP_EN_100FDX_CAP:
1812                         *(uint8_t *)pr_val = ngep->param_en_100fdx;
1813                         break;
1814                 case MAC_PROP_ADV_100HDX_CAP:
1815                         *(uint8_t *)pr_val = ngep->param_adv_100hdx;
1816                         break;
1817                 case MAC_PROP_EN_100HDX_CAP:
1818                         *(uint8_t *)pr_val = ngep->param_en_100hdx;
1819                         break;
1820                 case MAC_PROP_ADV_10FDX_CAP:
1821                         *(uint8_t *)pr_val = ngep->param_adv_10fdx;
1822                         break;
1823                 case MAC_PROP_EN_10FDX_CAP:
1824                         *(uint8_t *)pr_val = ngep->param_en_10fdx;
1825                         break;
1826                 case MAC_PROP_ADV_10HDX_CAP:
1827                         *(uint8_t *)pr_val = ngep->param_adv_10hdx;
1828                         break;
1829                 case MAC_PROP_EN_10HDX_CAP:
1830                         *(uint8_t *)pr_val = ngep->param_en_10hdx;
1831                         break;
1832                 case MAC_PROP_ADV_100T4_CAP:
1833                 case MAC_PROP_EN_100T4_CAP:
1834                         *(uint8_t *)pr_val = 0;
1835                         break;
1836                 case MAC_PROP_PRIVATE:
1837                         err = nge_get_priv_prop(ngep, pr_name,
1838                             pr_valsize, pr_val);
1839                         break;
1840                 default:
1841                         err = ENOTSUP;
1842         }
1843         return (err);
1844 }
1845 
1846 static void
1847 nge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1848     mac_prop_info_handle_t prh)
1849 {
1850         nge_t *ngep = barg;
1851 
1852         switch (pr_num) {
1853         case MAC_PROP_DUPLEX:
1854         case MAC_PROP_SPEED:
1855         case MAC_PROP_ADV_1000FDX_CAP:
1856         case MAC_PROP_ADV_1000HDX_CAP:
1857         case MAC_PROP_ADV_100FDX_CAP:
1858         case MAC_PROP_EN_1000HDX_CAP:
1859         case MAC_PROP_ADV_100HDX_CAP:
1860         case MAC_PROP_ADV_10FDX_CAP:
1861         case MAC_PROP_ADV_10HDX_CAP:
1862         case MAC_PROP_ADV_100T4_CAP:
1863         case MAC_PROP_EN_100T4_CAP:
1864                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1865                 break;
1866 
1867         case MAC_PROP_EN_1000FDX_CAP:
1868         case MAC_PROP_EN_100FDX_CAP:
1869         case MAC_PROP_EN_100HDX_CAP:
1870         case MAC_PROP_EN_10FDX_CAP:
1871         case MAC_PROP_EN_10HDX_CAP:
1872                 mac_prop_info_set_default_uint8(prh, 1);
1873                 break;
1874 
1875         case MAC_PROP_AUTONEG:
1876                 mac_prop_info_set_default_uint8(prh, 1);
1877                 break;
1878 
1879         case MAC_PROP_FLOWCTRL:
1880                 mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
1881                 break;
1882 
1883         case MAC_PROP_MTU:
1884                 mac_prop_info_set_range_uint32(prh, ETHERMTU,
1885                     ngep->dev_spec_param.jumbo ? NGE_MAX_MTU : ETHERMTU);
1886                 break;
1887 
1888         case MAC_PROP_PRIVATE: {
1889                 char valstr[64];
1890                 int value;
1891 
1892                 bzero(valstr, sizeof (valstr));
1893                 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
1894                         value = NGE_TX_COPY_SIZE;
1895                 } else  if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
1896                         value = NGE_RX_COPY_SIZE;
1897                 } else  if (strcmp(pr_name, "_recv_max_packet") == 0) {
1898                         value = 128;
1899                 } else  if (strcmp(pr_name, "_poll_quiet_time") == 0) {
1900                         value = NGE_POLL_QUIET_TIME;
1901                 } else  if (strcmp(pr_name, "_poll_busy_time") == 0) {
1902                         value = NGE_POLL_BUSY_TIME;
1903                 } else  if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
1904                         value = 1;
1905                 } else  if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
1906                         value = 8;
1907                 } else {
1908                         return;
1909                 }
1910 
1911                 (void) snprintf(valstr, sizeof (valstr), "%d", value);
1912         }
1913         }
1914 
1915 }
1916 
1917 /* ARGSUSED */
1918 static int
1919 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
1920     const void *pr_val)
1921 {
1922         int err = 0;
1923         long result;
1924 
1925         if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
1926                 if (pr_val == NULL) {
1927                         err = EINVAL;
1928                         return (err);
1929                 }
1930                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1931                 if (result < 0 || result > NGE_MAX_SDU) {
1932                         err = EINVAL;
1933                 } else {
1934                         ngep->param_txbcopy_threshold = (uint32_t)result;
1935                         goto reprogram;
1936                 }
1937                 return (err);
1938         }
1939         if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
1940                 if (pr_val == NULL) {
1941                         err = EINVAL;
1942                         return (err);
1943                 }
1944                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1945                 if (result < 0 || result > NGE_MAX_SDU) {
1946                         err = EINVAL;
1947                 } else {
1948                         ngep->param_rxbcopy_threshold = (uint32_t)result;
1949                         goto reprogram;
1950                 }
1951                 return (err);
1952         }
1953         if (strcmp(pr_name, "_recv_max_packet") == 0) {
1954                 if (pr_val == NULL) {
1955                         err = EINVAL;
1956                         return (err);
1957                 }
1958                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1959                 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
1960                         err = EINVAL;
1961                 } else {
1962                         ngep->param_recv_max_packet = (uint32_t)result;
1963                         goto reprogram;
1964                 }
1965                 return (err);
1966         }
1967         if (strcmp(pr_name, "_poll_quiet_time") == 0) {
1968                 if (pr_val == NULL) {
1969                         err = EINVAL;
1970                         return (err);
1971                 }
1972                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1973                 if (result < 0 || result > 10000) {
1974                         err = EINVAL;
1975                 } else {
1976                         ngep->param_poll_quiet_time = (uint32_t)result;
1977                         goto reprogram;
1978                 }
1979                 return (err);
1980         }
1981         if (strcmp(pr_name, "_poll_busy_time") == 0) {
1982                 if (pr_val == NULL) {
1983                         err = EINVAL;
1984                         return (err);
1985                 }
1986                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1987                 if (result < 0 || result > 10000) {
1988                         err = EINVAL;
1989                 } else {
1990                         ngep->param_poll_busy_time = (uint32_t)result;
1991                         goto reprogram;
1992                 }
1993                 return (err);
1994         }
1995         if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
1996                 if (pr_val == NULL) {
1997                         err = EINVAL;
1998                         return (err);
1999                 }
2000                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
2001                 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
2002                         err = EINVAL;
2003                 } else {
2004                         ngep->param_rx_intr_hwater = (uint32_t)result;
2005                         goto reprogram;
2006                 }
2007                 return (err);
2008         }
2009         if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2010                 if (pr_val == NULL) {
2011                         err = EINVAL;
2012                         return (err);
2013                 }
2014                 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
2015                 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
2016                         err = EINVAL;
2017                 } else {
2018                         ngep->param_rx_intr_lwater = (uint32_t)result;
2019                         goto reprogram;
2020                 }
2021                 return (err);
2022         }
2023         err = ENOTSUP;
2024         return (err);
2025 
2026 reprogram:
2027         if (err == 0) {
2028                 (*ngep->physops->phys_update)(ngep);
2029                 nge_chip_sync(ngep);
2030         }
2031 
2032         return (err);
2033 }
2034 
2035 static int
2036 nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
2037     void *pr_val)
2038 {
2039         int err = ENOTSUP;
2040         int value;
2041 
2042         if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
2043                 value = ngep->param_txbcopy_threshold;
2044                 err = 0;
2045                 goto done;
2046         }
2047         if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
2048                 value = ngep->param_rxbcopy_threshold;
2049                 err = 0;
2050                 goto done;
2051         }
2052         if (strcmp(pr_name, "_recv_max_packet") == 0) {
2053                 value = ngep->param_recv_max_packet;
2054                 err = 0;
2055                 goto done;
2056         }
2057         if (strcmp(pr_name, "_poll_quiet_time") == 0) {
2058                 value = ngep->param_poll_quiet_time;
2059                 err = 0;
2060                 goto done;
2061         }
2062         if (strcmp(pr_name, "_poll_busy_time") == 0) {
2063                 value = ngep->param_poll_busy_time;
2064                 err = 0;
2065                 goto done;
2066         }
2067         if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
2068                 value = ngep->param_rx_intr_hwater;
2069                 err = 0;
2070                 goto done;
2071         }
2072         if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2073                 value = ngep->param_rx_intr_lwater;
2074                 err = 0;
2075                 goto done;
2076         }
2077 
2078 done:
2079         if (err == 0) {
2080                 (void) snprintf(pr_val, pr_valsize, "%d", value);
2081         }
2082         return (err);
2083 }
2084 
2085 /* ARGSUSED */
2086 static boolean_t
2087 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
2088 {
2089         nge_t   *ngep = arg;
2090         nge_dev_spec_param_t *dev_param_p;
2091 
2092         dev_param_p = &ngep->dev_spec_param;
2093 
2094         switch (cap) {
2095         case MAC_CAPAB_HCKSUM: {
2096                 uint32_t *hcksum_txflags = cap_data;
2097 
2098                 if (dev_param_p->tx_hw_checksum) {
2099                         *hcksum_txflags = dev_param_p->tx_hw_checksum;
2100                 } else
2101                         return (B_FALSE);
2102                 break;
2103         }
2104         default:
2105                 return (B_FALSE);
2106         }
2107         return (B_TRUE);
2108 }
2109 
2110 #undef  NGE_DBG
2111 #define NGE_DBG NGE_DBG_INIT    /* debug flag for this code     */
2112 int
2113 nge_restart(nge_t *ngep)
2114 {
2115         int err = 0;
2116         err = nge_reset_dev(ngep);
2117         /* write back the promisc setting */
2118         ngep->promisc = ngep->record_promisc;
2119         nge_chip_sync(ngep);
2120         if (!err)
2121                 err = nge_chip_start(ngep);
2122 
2123         if (err) {
2124                 ngep->nge_mac_state = NGE_MAC_STOPPED;
2125                 return (DDI_FAILURE);
2126         } else {
2127                 ngep->nge_mac_state = NGE_MAC_STARTED;
2128                 return (DDI_SUCCESS);
2129         }
2130 }
2131 
2132 void
2133 nge_wake_factotum(nge_t *ngep)
2134 {
2135         mutex_enter(ngep->softlock);
2136         if (ngep->factotum_flag == 0) {
2137                 ngep->factotum_flag = 1;
2138                 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
2139         }
2140         mutex_exit(ngep->softlock);
2141 }
2142 
2143 void
2144 nge_interrupt_optimize(nge_t *ngep)
2145 {
2146         uint32_t tx_pkts;
2147         tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
2148         ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
2149         if ((tx_pkts > NGE_POLL_TUNE) &&
2150             (tx_pkts <= NGE_POLL_MAX))
2151                 ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
2152         else
2153                 ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2154 }
2155 
2156 /*
2157  * High-level cyclic handler
2158  *
2159  * This routine schedules a (low-level) softint callback to the
2160  * factotum.
2161  */
2162 
2163 static void
2164 nge_chip_cyclic(void *arg)
2165 {
2166         nge_t *ngep;
2167 
2168         ngep = (nge_t *)arg;
2169 
2170         switch (ngep->nge_chip_state) {
2171         default:
2172                 return;
2173 
2174         case NGE_CHIP_RUNNING:
2175                 nge_interrupt_optimize(ngep);
2176                 break;
2177 
2178         case NGE_CHIP_FAULT:
2179         case NGE_CHIP_ERROR:
2180                 break;
2181         }
2182 
2183         nge_wake_factotum(ngep);
2184 }
2185 
2186 /*
2187  * Get/Release semaphore of SMU
2188  * For SMU enabled chipset
2189  * When nge driver is attached, driver should acquire
2190  * semaphore before PHY init and accessing MAC registers.
2191  * When nge driver is unattached, driver should release
2192  * semaphore.
2193  */
2194 
2195 static int
2196 nge_smu_sema(nge_t *ngep, boolean_t acquire)
2197 {
2198         nge_tx_en tx_en;
2199         uint32_t tries;
2200 
2201         if (acquire) {
2202                 for (tries = 0; tries < 5; tries++) {
2203                         tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2204                         if (tx_en.bits.smu2mac == NGE_SMU_FREE)
2205                                 break;
2206                         delay(drv_usectohz(1000000));
2207                 }
2208                 if (tx_en.bits.smu2mac != NGE_SMU_FREE)
2209                         return (DDI_FAILURE);
2210                 for (tries = 0; tries < 5; tries++) {
2211                         tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2212                         tx_en.bits.mac2smu = NGE_SMU_GET;
2213                         nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
2214                         tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2215 
2216                         if (tx_en.bits.mac2smu == NGE_SMU_GET &&
2217                             tx_en.bits.smu2mac == NGE_SMU_FREE)
2218                                 return (DDI_SUCCESS);
2219                         drv_usecwait(10);
2220                 }
2221                 return (DDI_FAILURE);
2222         } else
2223                 nge_reg_put32(ngep, NGE_TX_EN, 0x0);
2224 
2225         return (DDI_SUCCESS);
2226 
2227 }
2228 static void
2229 nge_unattach(nge_t *ngep)
2230 {
2231         send_ring_t *srp;
2232         buff_ring_t *brp;
2233 
2234         srp = ngep->send;
2235         brp = ngep->buff;
2236         NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
2237 
2238         /*
2239          * Flag that no more activity may be initiated
2240          */
2241         ngep->progress &= ~PROGRESS_READY;
2242         ngep->nge_mac_state = NGE_MAC_UNATTACH;
2243 
2244         /*
2245          * Quiesce the PHY and MAC (leave it reset but still powered).
2246          * Clean up and free all NGE data structures
2247          */
2248         if (ngep->periodic_id != NULL) {
2249                 ddi_periodic_delete(ngep->periodic_id);
2250                 ngep->periodic_id = NULL;
2251         }
2252 
2253         if (ngep->progress & PROGRESS_KSTATS)
2254                 nge_fini_kstats(ngep);
2255 
2256         if (ngep->progress & PROGRESS_HWINT) {
2257                 mutex_enter(ngep->genlock);
2258                 nge_restore_mac_addr(ngep);
2259                 (void) nge_chip_stop(ngep, B_FALSE);
2260                 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2261                     ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2262                         (void) nge_smu_sema(ngep, B_FALSE);
2263                 }
2264                 mutex_exit(ngep->genlock);
2265         }
2266 
2267         if (ngep->progress & PROGRESS_SWINT)
2268                 nge_rem_intrs(ngep);
2269 
2270         if (ngep->progress & PROGRESS_FACTOTUM)
2271                 (void) ddi_intr_remove_softint(ngep->factotum_hdl);
2272 
2273         if (ngep->progress & PROGRESS_RESCHED)
2274                 (void) ddi_intr_remove_softint(ngep->resched_hdl);
2275 
2276         if (ngep->progress & PROGRESS_INTR) {
2277                 mutex_destroy(srp->tx_lock);
2278                 mutex_destroy(srp->tc_lock);
2279                 mutex_destroy(&srp->dmah_lock);
2280                 mutex_destroy(brp->recycle_lock);
2281 
2282                 mutex_destroy(ngep->genlock);
2283                 mutex_destroy(ngep->softlock);
2284                 rw_destroy(ngep->rwlock);
2285         }
2286 
2287         if (ngep->progress & PROGRESS_REGS)
2288                 ddi_regs_map_free(&ngep->io_handle);
2289 
2290         if (ngep->progress & PROGRESS_CFG)
2291                 pci_config_teardown(&ngep->cfg_handle);
2292 
2293         ddi_remove_minor_node(ngep->devinfo, NULL);
2294 
2295         kmem_free(ngep, sizeof (*ngep));
2296 }
2297 
2298 static int
2299 nge_resume(dev_info_t *devinfo)
2300 {
2301         nge_t           *ngep;
2302         chip_info_t     *infop;
2303         int             err;
2304 
2305         ASSERT(devinfo != NULL);
2306 
2307         ngep = ddi_get_driver_private(devinfo);
2308         err = 0;
2309 
2310         /*
2311          * If there are state inconsistancies, this is bad.  Returning
2312          * DDI_FAILURE here will eventually cause the machine to panic,
2313          * so it is best done here so that there is a possibility of
2314          * debugging the problem.
2315          */
2316         if (ngep == NULL)
2317                 cmn_err(CE_PANIC,
2318                     "nge: ngep returned from ddi_get_driver_private was NULL");
2319         infop = (chip_info_t *)&ngep->chipinfo;
2320 
2321         if (ngep->devinfo != devinfo)
2322                 cmn_err(CE_PANIC,
2323                     "nge: passed devinfo not the same as saved devinfo");
2324 
2325         mutex_enter(ngep->genlock);
2326         rw_enter(ngep->rwlock, RW_WRITER);
2327 
2328         /*
2329          * Fetch the config space.  Even though we have most of it cached,
2330          * some values *might* change across a suspend/resume.
2331          */
2332         nge_chip_cfg_init(ngep, infop, B_FALSE);
2333 
2334         /*
2335          * Only in one case, this conditional branch can be executed: the port
2336          * hasn't been plumbed.
2337          */
2338         if (ngep->suspended == B_FALSE) {
2339                 rw_exit(ngep->rwlock);
2340                 mutex_exit(ngep->genlock);
2341                 return (DDI_SUCCESS);
2342         }
2343 
2344         nge_tx_recycle_all(ngep);
2345         err = nge_reinit_ring(ngep);
2346         if (!err) {
2347                 err = nge_chip_reset(ngep);
2348                 if (!err)
2349                         err = nge_chip_start(ngep);
2350         }
2351 
2352         if (err) {
2353                 /*
2354                  * We note the failure, but return success, as the
2355                  * system is still usable without this controller.
2356                  */
2357                 cmn_err(CE_WARN, "nge: resume: failed to restart controller");
2358         } else {
2359                 ngep->nge_mac_state = NGE_MAC_STARTED;
2360         }
2361         ngep->suspended = B_FALSE;
2362 
2363         rw_exit(ngep->rwlock);
2364         mutex_exit(ngep->genlock);
2365 
2366         return (DDI_SUCCESS);
2367 }
2368 
2369 /*
2370  * attach(9E) -- Attach a device to the system
2371  *
2372  * Called once for each board successfully probed.
2373  */
2374 static int
2375 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
2376 {
2377         int             err;
2378         int             i;
2379         int             instance;
2380         caddr_t         regs;
2381         nge_t           *ngep;
2382         chip_info_t     *infop;
2383         mac_register_t  *macp;
2384 
2385         switch (cmd) {
2386         default:
2387                 return (DDI_FAILURE);
2388 
2389         case DDI_RESUME:
2390                 return (nge_resume(devinfo));
2391 
2392         case DDI_ATTACH:
2393                 break;
2394         }
2395 
2396         ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
2397         instance = ddi_get_instance(devinfo);
2398         ddi_set_driver_private(devinfo, ngep);
2399         ngep->devinfo = devinfo;
2400 
2401         (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
2402             NGE_DRIVER_NAME, instance);
2403         err = pci_config_setup(devinfo, &ngep->cfg_handle);
2404         if (err != DDI_SUCCESS) {
2405                 nge_problem(ngep, "nge_attach: pci_config_setup() failed");
2406                 goto attach_fail;
2407         }
2408         /*
2409          * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
2410          * thresholds. Bounds: min 0, max NGE_MAX_SDU
2411          */
2412         ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
2413         ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
2414 
2415         /*
2416          * param_recv_max_packet is max packet received per interupt.
2417          * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
2418          */
2419         ngep->param_recv_max_packet = 128;
2420 
2421         /*
2422          * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
2423          * switch from per packet interrupt to polling interrupt.
2424          * Bounds: min 0, max 10000
2425          */
2426         ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
2427         ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
2428         ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2429         ngep->poll = B_FALSE;
2430         ngep->ch_intr_mode = B_FALSE;
2431 
2432         /*
2433          * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
2434          * to trigger the poll_quiet_time/poll_busy_time counter.
2435          * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
2436          */
2437         ngep->param_rx_intr_hwater = 1;
2438         ngep->param_rx_intr_lwater = 8;
2439 
2440 
2441         infop = (chip_info_t *)&ngep->chipinfo;
2442         nge_chip_cfg_init(ngep, infop, B_FALSE);
2443         nge_init_dev_spec_param(ngep);
2444         nge_get_props(ngep);
2445         ngep->progress |= PROGRESS_CFG;
2446 
2447         err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
2448             &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
2449         if (err != DDI_SUCCESS) {
2450                 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
2451                 goto attach_fail;
2452         }
2453         ngep->io_regs = regs;
2454         ngep->progress |= PROGRESS_REGS;
2455 
2456         err = nge_register_intrs_and_init_locks(ngep);
2457         if (err != DDI_SUCCESS) {
2458                 nge_problem(ngep, "nge_attach:"
2459                     " register intrs and init locks failed");
2460                 goto attach_fail;
2461         }
2462         nge_init_ring_param_lock(ngep);
2463         ngep->progress |= PROGRESS_INTR;
2464 
2465         mutex_enter(ngep->genlock);
2466 
2467         if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2468             ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2469                 err = nge_smu_sema(ngep, B_TRUE);
2470                 if (err != DDI_SUCCESS) {
2471                         nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
2472                         goto attach_fail;
2473                 }
2474         }
2475         /*
2476          * Initialise link state variables
2477          * Stop, reset & reinitialise the chip.
2478          * Initialise the (internal) PHY.
2479          */
2480         nge_phys_init(ngep);
2481         ngep->nge_chip_state = NGE_CHIP_INITIAL;
2482         err = nge_chip_reset(ngep);
2483         if (err != DDI_SUCCESS) {
2484                 nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
2485                 mutex_exit(ngep->genlock);
2486                 goto attach_fail;
2487         }
2488         nge_chip_sync(ngep);
2489 
2490         /*
2491          * Now that mutex locks are initialized, enable interrupts.
2492          */
2493         if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
2494                 /* Call ddi_intr_block_enable() for MSI interrupts */
2495                 (void) ddi_intr_block_enable(ngep->htable,
2496                     ngep->intr_actual_cnt);
2497         } else {
2498                 /* Call ddi_intr_enable for MSI or FIXED interrupts */
2499                 for (i = 0; i < ngep->intr_actual_cnt; i++) {
2500                         (void) ddi_intr_enable(ngep->htable[i]);
2501                 }
2502         }
2503 
2504         ngep->link_state = LINK_STATE_UNKNOWN;
2505         ngep->progress |= PROGRESS_HWINT;
2506 
2507         /*
2508          * Register NDD-tweakable parameters
2509          */
2510         if (nge_nd_init(ngep)) {
2511                 nge_problem(ngep, "nge_attach: nge_nd_init() failed");
2512                 mutex_exit(ngep->genlock);
2513                 goto attach_fail;
2514         }
2515         ngep->progress |= PROGRESS_NDD;
2516 
2517         /*
2518          * Create & initialise named kstats
2519          */
2520         nge_init_kstats(ngep, instance);
2521         ngep->progress |= PROGRESS_KSTATS;
2522 
2523         mutex_exit(ngep->genlock);
2524 
2525         if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2526                 goto attach_fail;
2527         macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2528         macp->m_driver = ngep;
2529         macp->m_dip = devinfo;
2530         macp->m_src_addr = infop->vendor_addr.addr;
2531         macp->m_callbacks = &nge_m_callbacks;
2532         macp->m_min_sdu = 0;
2533         macp->m_max_sdu = ngep->default_mtu;
2534         macp->m_margin = VTAG_SIZE;
2535         macp->m_priv_props = nge_priv_props;
2536         /*
2537          * Finally, we're ready to register ourselves with the mac
2538          * interface; if this succeeds, we're all ready to start()
2539          */
2540         err = mac_register(macp, &ngep->mh);
2541         mac_free(macp);
2542         if (err != 0)
2543                 goto attach_fail;
2544 
2545         /*
2546          * Register a periodical handler.
2547          * nge_chip_cyclic() is invoked in kernel context.
2548          */
2549         ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
2550             NGE_CYCLIC_PERIOD, DDI_IPL_0);
2551 
2552         ngep->progress |= PROGRESS_READY;
2553         return (DDI_SUCCESS);
2554 
2555 attach_fail:
2556         nge_unattach(ngep);
2557         return (DDI_FAILURE);
2558 }
2559 
2560 static int
2561 nge_suspend(nge_t *ngep)
2562 {
2563         mutex_enter(ngep->genlock);
2564         rw_enter(ngep->rwlock, RW_WRITER);
2565 
2566         /* if the port hasn't been plumbed, just return */
2567         if (ngep->nge_mac_state != NGE_MAC_STARTED) {
2568                 rw_exit(ngep->rwlock);
2569                 mutex_exit(ngep->genlock);
2570                 return (DDI_SUCCESS);
2571         }
2572         ngep->suspended = B_TRUE;
2573         (void) nge_chip_stop(ngep, B_FALSE);
2574         ngep->nge_mac_state = NGE_MAC_STOPPED;
2575 
2576         rw_exit(ngep->rwlock);
2577         mutex_exit(ngep->genlock);
2578         return (DDI_SUCCESS);
2579 }
2580 
2581 /*
2582  * detach(9E) -- Detach a device from the system
2583  */
2584 static int
2585 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
2586 {
2587         int i;
2588         nge_t *ngep;
2589         mul_item *p, *nextp;
2590         buff_ring_t *brp;
2591 
2592         NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
2593 
2594         ngep = ddi_get_driver_private(devinfo);
2595         brp = ngep->buff;
2596 
2597         switch (cmd) {
2598         default:
2599                 return (DDI_FAILURE);
2600 
2601         case DDI_SUSPEND:
2602                 /*
2603                  * Stop the NIC
2604                  * Note: This driver doesn't currently support WOL, but
2605                  *      should it in the future, it is important to
2606                  *      make sure the PHY remains powered so that the
2607                  *      wakeup packet can actually be recieved.
2608                  */
2609                 return (nge_suspend(ngep));
2610 
2611         case DDI_DETACH:
2612                 break;
2613         }
2614 
2615         /* Try to wait all the buffer post to upper layer be released */
2616         for (i = 0; i < 1000; i++) {
2617                 if (brp->rx_hold == 0)
2618                         break;
2619                 drv_usecwait(1000);
2620         }
2621 
2622         /* If there is any posted buffer, reject to detach */
2623         if (brp->rx_hold != 0)
2624                 return (DDI_FAILURE);
2625 
2626         /*
2627          * Unregister from the GLD subsystem.  This can fail, in
2628          * particular if there are DLPI style-2 streams still open -
2629          * in which case we just return failure without shutting
2630          * down chip operations.
2631          */
2632         if (mac_unregister(ngep->mh) != DDI_SUCCESS)
2633                 return (DDI_FAILURE);
2634 
2635         /*
2636          * Recycle the multicast table. mac_unregister() should be called
2637          * before it to ensure the multicast table can be used even if
2638          * mac_unregister() fails.
2639          */
2640         for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
2641                 nextp = p->next;
2642                 kmem_free(p, sizeof (mul_item));
2643         }
2644         ngep->pcur_mulist = NULL;
2645 
2646         /*
2647          * All activity stopped, so we can clean up & exit
2648          */
2649         nge_unattach(ngep);
2650         return (DDI_SUCCESS);
2651 }
2652 
2653 /*
2654  * quiesce(9E) entry point.
2655  *
2656  * This function is called when the system is single-threaded at high
2657  * PIL with preemption disabled. Therefore, this function must not be
2658  * blocked.
2659  *
2660  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
2661  * DDI_FAILURE indicates an error condition and should almost never happen.
2662  */
2663 static int
2664 nge_quiesce(dev_info_t *devinfo)
2665 {
2666         nge_t *ngep;
2667 
2668         ngep = ddi_get_driver_private(devinfo);
2669 
2670         if (ngep == NULL)
2671                 return (DDI_FAILURE);
2672 
2673         /*
2674          * Turn off debug tracing
2675          */
2676         nge_debug = 0;
2677         ngep->debug = 0;
2678 
2679         nge_restore_mac_addr(ngep);
2680         (void) nge_chip_stop(ngep, B_FALSE);
2681 
2682         return (DDI_SUCCESS);
2683 }
2684 
2685 
2686 
2687 /*
2688  * ========== Module Loading Data & Entry Points ==========
2689  */
2690 
2691 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
2692     NULL, NULL, D_MP, NULL, nge_quiesce);
2693 
2694 
2695 static struct modldrv nge_modldrv = {
2696         &mod_driverops,             /* Type of module.  This one is a driver */
2697         nge_ident,              /* short description */
2698         &nge_dev_ops                /* driver specific ops */
2699 };
2700 
2701 static struct modlinkage modlinkage = {
2702         MODREV_1, { (void *)&nge_modldrv, NULL }
2703 };
2704 
2705 
2706 int
2707 _info(struct modinfo *modinfop)
2708 {
2709         return (mod_info(&modlinkage, modinfop));
2710 }
2711 
2712 int
2713 _init(void)
2714 {
2715         int status;
2716 
2717         mac_init_ops(&nge_dev_ops, "nge");
2718         status = mod_install(&modlinkage);
2719         if (status != DDI_SUCCESS)
2720                 mac_fini_ops(&nge_dev_ops);
2721         else
2722                 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
2723 
2724         return (status);
2725 }
2726 
2727 int
2728 _fini(void)
2729 {
2730         int status;
2731 
2732         status = mod_remove(&modlinkage);
2733         if (status == DDI_SUCCESS) {
2734                 mac_fini_ops(&nge_dev_ops);
2735                 mutex_destroy(nge_log_mutex);
2736         }
2737 
2738         return (status);
2739 }
2740 
2741 /*
2742  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
2743  */
2744 
2745 /*
2746  * Register interrupts and initialize each mutex and condition variables
2747  */
2748 
2749 static int
2750 nge_register_intrs_and_init_locks(nge_t *ngep)
2751 {
2752         int             err;
2753         int             intr_types;
2754         uint_t          soft_prip;
2755         nge_msi_mask    msi_mask;
2756         nge_msi_map0_vec map0_vec;
2757         nge_msi_map1_vec map1_vec;
2758 
2759         /*
2760          * Add the softint handlers:
2761          *
2762          * Both of these handlers are used to avoid restrictions on the
2763          * context and/or mutexes required for some operations.  In
2764          * particular, the hardware interrupt handler and its subfunctions
2765          * can detect a number of conditions that we don't want to handle
2766          * in that context or with that set of mutexes held.  So, these
2767          * softints are triggered instead:
2768          *
2769          * the <resched> softint is triggered if if we have previously
2770          * had to refuse to send a packet because of resource shortage
2771          * (we've run out of transmit buffers), but the send completion
2772          * interrupt handler has now detected that more buffers have
2773          * become available.  Its only purpose is to call gld_sched()
2774          * to retry the pending transmits (we're not allowed to hold
2775          * driver-defined mutexes across gld_sched()).
2776          *
2777          * the <factotum> is triggered if the h/w interrupt handler
2778          * sees the <link state changed> or <error> bits in the status
2779          * block.  It's also triggered periodically to poll the link
2780          * state, just in case we aren't getting link status change
2781          * interrupts ...
2782          */
2783         err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
2784             DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
2785         if (err != DDI_SUCCESS) {
2786                 nge_problem(ngep,
2787                     "nge_attach: add nge_reschedule softintr failed");
2788 
2789                 return (DDI_FAILURE);
2790         }
2791         ngep->progress |= PROGRESS_RESCHED;
2792         err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
2793             DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
2794         if (err != DDI_SUCCESS) {
2795                 nge_problem(ngep,
2796                     "nge_attach: add nge_chip_factotum softintr failed!");
2797 
2798                 return (DDI_FAILURE);
2799         }
2800         if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
2801             != DDI_SUCCESS) {
2802                 nge_problem(ngep, "nge_attach: get softintr priority failed\n");
2803 
2804                 return (DDI_FAILURE);
2805         }
2806         ngep->soft_pri = soft_prip;
2807 
2808         ngep->progress |= PROGRESS_FACTOTUM;
2809         /* Get supported interrupt types */
2810         if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
2811             != DDI_SUCCESS) {
2812                 nge_error(ngep, "ddi_intr_get_supported_types failed\n");
2813 
2814                 return (DDI_FAILURE);
2815         }
2816 
2817         NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
2818             intr_types));
2819 
2820         if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
2821 
2822                 /* MSI Configurations for mcp55 chipset */
2823                 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2824                     ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2825 
2826 
2827                         /* Enable the 8 vectors */
2828                         msi_mask.msi_mask_val =
2829                             nge_reg_get32(ngep, NGE_MSI_MASK);
2830                         msi_mask.msi_msk_bits.vec0 = NGE_SET;
2831                         msi_mask.msi_msk_bits.vec1 = NGE_SET;
2832                         msi_mask.msi_msk_bits.vec2 = NGE_SET;
2833                         msi_mask.msi_msk_bits.vec3 = NGE_SET;
2834                         msi_mask.msi_msk_bits.vec4 = NGE_SET;
2835                         msi_mask.msi_msk_bits.vec5 = NGE_SET;
2836                         msi_mask.msi_msk_bits.vec6 = NGE_SET;
2837                         msi_mask.msi_msk_bits.vec7 = NGE_SET;
2838                         nge_reg_put32(ngep, NGE_MSI_MASK,
2839                             msi_mask.msi_mask_val);
2840 
2841                         /*
2842                          * Remapping the MSI MAP0 and MAP1. MCP55
2843                          * is default mapping all the interrupt to 0 vector.
2844                          * Software needs to remapping this.
2845                          * This mapping is same as CK804.
2846                          */
2847                         map0_vec.msi_map0_val =
2848                             nge_reg_get32(ngep, NGE_MSI_MAP0);
2849                         map1_vec.msi_map1_val =
2850                             nge_reg_get32(ngep, NGE_MSI_MAP1);
2851                         map0_vec.vecs_bits.reint_vec = 0;
2852                         map0_vec.vecs_bits.rcint_vec = 0;
2853                         map0_vec.vecs_bits.miss_vec = 3;
2854                         map0_vec.vecs_bits.teint_vec = 5;
2855                         map0_vec.vecs_bits.tcint_vec = 5;
2856                         map0_vec.vecs_bits.stint_vec = 2;
2857                         map0_vec.vecs_bits.mint_vec = 6;
2858                         map0_vec.vecs_bits.rfint_vec = 0;
2859                         map1_vec.vecs_bits.tfint_vec = 5;
2860                         map1_vec.vecs_bits.feint_vec = 6;
2861                         map1_vec.vecs_bits.resv8_11 = 3;
2862                         map1_vec.vecs_bits.resv12_15 = 1;
2863                         map1_vec.vecs_bits.resv16_19 = 0;
2864                         map1_vec.vecs_bits.resv20_23 = 7;
2865                         map1_vec.vecs_bits.resv24_31 = 0xff;
2866                         nge_reg_put32(ngep, NGE_MSI_MAP0,
2867                             map0_vec.msi_map0_val);
2868                         nge_reg_put32(ngep, NGE_MSI_MAP1,
2869                             map1_vec.msi_map1_val);
2870                 }
2871                 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
2872                         NGE_DEBUG(("MSI registration failed, "
2873                             "trying FIXED interrupt type\n"));
2874                 } else {
2875                         nge_log(ngep, "Using MSI interrupt type\n");
2876 
2877                         ngep->intr_type = DDI_INTR_TYPE_MSI;
2878                         ngep->progress |= PROGRESS_SWINT;
2879                 }
2880         }
2881 
2882         if (!(ngep->progress & PROGRESS_SWINT) &&
2883             (intr_types & DDI_INTR_TYPE_FIXED)) {
2884                 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
2885                         nge_error(ngep, "FIXED interrupt "
2886                             "registration failed\n");
2887 
2888                         return (DDI_FAILURE);
2889                 }
2890 
2891                 nge_log(ngep, "Using FIXED interrupt type\n");
2892 
2893                 ngep->intr_type = DDI_INTR_TYPE_FIXED;
2894                 ngep->progress |= PROGRESS_SWINT;
2895         }
2896 
2897 
2898         if (!(ngep->progress & PROGRESS_SWINT)) {
2899                 nge_error(ngep, "No interrupts registered\n");
2900 
2901                 return (DDI_FAILURE);
2902         }
2903         mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
2904             DDI_INTR_PRI(ngep->intr_pri));
2905         mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
2906             DDI_INTR_PRI(ngep->soft_pri));
2907         rw_init(ngep->rwlock, NULL, RW_DRIVER,
2908             DDI_INTR_PRI(ngep->intr_pri));
2909 
2910         return (DDI_SUCCESS);
2911 }
2912 
2913 /*
2914  * nge_add_intrs:
2915  *
2916  * Register FIXED or MSI interrupts.
2917  */
2918 static int
2919 nge_add_intrs(nge_t *ngep, int  intr_type)
2920 {
2921         dev_info_t      *dip = ngep->devinfo;
2922         int             avail, actual, intr_size, count = 0;
2923         int             i, flag, ret;
2924 
2925         NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
2926 
2927         /* Get number of interrupts */
2928         ret = ddi_intr_get_nintrs(dip, intr_type, &count);
2929         if ((ret != DDI_SUCCESS) || (count == 0)) {
2930                 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
2931                     "count: %d", ret, count);
2932 
2933                 return (DDI_FAILURE);
2934         }
2935 
2936         /* Get number of available interrupts */
2937         ret = ddi_intr_get_navail(dip, intr_type, &avail);
2938         if ((ret != DDI_SUCCESS) || (avail == 0)) {
2939                 nge_error(ngep, "ddi_intr_get_navail() failure, "
2940                     "ret: %d, avail: %d\n", ret, avail);
2941 
2942                 return (DDI_FAILURE);
2943         }
2944 
2945         if (avail < count) {
2946                 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
2947                     count, avail));
2948         }
2949         flag = DDI_INTR_ALLOC_NORMAL;
2950 
2951         /* Allocate an array of interrupt handles */
2952         intr_size = count * sizeof (ddi_intr_handle_t);
2953         ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
2954 
2955         /* Call ddi_intr_alloc() */
2956         ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
2957             count, &actual, flag);
2958 
2959         if ((ret != DDI_SUCCESS) || (actual == 0)) {
2960                 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
2961 
2962                 kmem_free(ngep->htable, intr_size);
2963                 return (DDI_FAILURE);
2964         }
2965 
2966         if (actual < count) {
2967                 NGE_DEBUG(("Requested: %d, Received: %d\n",
2968                     count, actual));
2969         }
2970 
2971         ngep->intr_actual_cnt = actual;
2972         ngep->intr_req_cnt = count;
2973 
2974         /*
2975          * Get priority for first msi, assume remaining are all the same
2976          */
2977         if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
2978             DDI_SUCCESS) {
2979                 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
2980 
2981                 /* Free already allocated intr */
2982                 for (i = 0; i < actual; i++) {
2983                         (void) ddi_intr_free(ngep->htable[i]);
2984                 }
2985 
2986                 kmem_free(ngep->htable, intr_size);
2987 
2988                 return (DDI_FAILURE);
2989         }
2990         /* Test for high level mutex */
2991         if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
2992                 nge_error(ngep, "nge_add_intrs:"
2993                     "Hi level interrupt not supported");
2994 
2995                 for (i = 0; i < actual; i++)
2996                         (void) ddi_intr_free(ngep->htable[i]);
2997 
2998                 kmem_free(ngep->htable, intr_size);
2999 
3000                 return (DDI_FAILURE);
3001         }
3002 
3003 
3004         /* Call ddi_intr_add_handler() */
3005         for (i = 0; i < actual; i++) {
3006                 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
3007                     (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
3008                         nge_error(ngep, "ddi_intr_add_handler() "
3009                             "failed %d\n", ret);
3010 
3011                         /* Free already allocated intr */
3012                         for (i = 0; i < actual; i++) {
3013                                 (void) ddi_intr_free(ngep->htable[i]);
3014                         }
3015 
3016                         kmem_free(ngep->htable, intr_size);
3017 
3018                         return (DDI_FAILURE);
3019                 }
3020         }
3021 
3022         if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
3023             != DDI_SUCCESS) {
3024                 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
3025 
3026                 for (i = 0; i < actual; i++) {
3027                         (void) ddi_intr_remove_handler(ngep->htable[i]);
3028                         (void) ddi_intr_free(ngep->htable[i]);
3029                 }
3030 
3031                 kmem_free(ngep->htable, intr_size);
3032 
3033                 return (DDI_FAILURE);
3034         }
3035 
3036         return (DDI_SUCCESS);
3037 }
3038 
3039 /*
3040  * nge_rem_intrs:
3041  *
3042  * Unregister FIXED or MSI interrupts
3043  */
3044 static void
3045 nge_rem_intrs(nge_t *ngep)
3046 {
3047         int     i;
3048 
3049         NGE_DEBUG(("nge_rem_intrs\n"));
3050 
3051         /* Disable all interrupts */
3052         if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
3053                 /* Call ddi_intr_block_disable() */
3054                 (void) ddi_intr_block_disable(ngep->htable,
3055                     ngep->intr_actual_cnt);
3056         } else {
3057                 for (i = 0; i < ngep->intr_actual_cnt; i++) {
3058                         (void) ddi_intr_disable(ngep->htable[i]);
3059                 }
3060         }
3061 
3062         /* Call ddi_intr_remove_handler() */
3063         for (i = 0; i < ngep->intr_actual_cnt; i++) {
3064                 (void) ddi_intr_remove_handler(ngep->htable[i]);
3065                 (void) ddi_intr_free(ngep->htable[i]);
3066         }
3067 
3068         kmem_free(ngep->htable,
3069             ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
3070 }