1744Sgs150176 /* 2744Sgs150176 * CDDL HEADER START 3744Sgs150176 * 4744Sgs150176 * The contents of this file are subject to the terms of the 52311Sseb * Common Development and Distribution License (the "License"). 62311Sseb * You may not use this file except in compliance with the License. 7744Sgs150176 * 8744Sgs150176 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9744Sgs150176 * or http://www.opensolaris.org/os/licensing. 10744Sgs150176 * See the License for the specific language governing permissions 11744Sgs150176 * and limitations under the License. 12744Sgs150176 * 13744Sgs150176 * When distributing Covered Code, include this CDDL HEADER in each 14744Sgs150176 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15744Sgs150176 * If applicable, add the following below this CDDL HEADER, with the 16744Sgs150176 * fields enclosed by brackets "[]" replaced with your own identifying 17744Sgs150176 * information: Portions Copyright [yyyy] [name of copyright owner] 18744Sgs150176 * 19744Sgs150176 * CDDL HEADER END 20744Sgs150176 */ 21744Sgs150176 /* 222311Sseb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23744Sgs150176 * Use is subject to license terms. 24744Sgs150176 */ 25744Sgs150176 26744Sgs150176 #pragma ident "%Z%%M% %I% %E% SMI" 27744Sgs150176 28744Sgs150176 #include "rge.h" 29744Sgs150176 30744Sgs150176 /* 31744Sgs150176 * This is the string displayed by modinfo, etc. 32744Sgs150176 * Make sure you keep the version ID up to date! 33744Sgs150176 */ 34*2544Sgs150176 static char rge_ident[] = "Realtek 1Gb Ethernet v%I%"; 35744Sgs150176 36744Sgs150176 /* 37744Sgs150176 * Used for buffers allocated by ddi_dma_mem_alloc() 38744Sgs150176 */ 39744Sgs150176 static ddi_dma_attr_t dma_attr_buf = { 40744Sgs150176 DMA_ATTR_V0, /* dma_attr version */ 41744Sgs150176 (uint32_t)0, /* dma_attr_addr_lo */ 42744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 43744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_count_max */ 44744Sgs150176 (uint32_t)16, /* dma_attr_align */ 45744Sgs150176 0xFFFFFFFF, /* dma_attr_burstsizes */ 46744Sgs150176 1, /* dma_attr_minxfer */ 47744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 48744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_seg */ 49744Sgs150176 1, /* dma_attr_sgllen */ 50744Sgs150176 1, /* dma_attr_granular */ 51744Sgs150176 0, /* dma_attr_flags */ 52744Sgs150176 }; 53744Sgs150176 54744Sgs150176 /* 55744Sgs150176 * Used for BDs allocated by ddi_dma_mem_alloc() 56744Sgs150176 */ 57744Sgs150176 static ddi_dma_attr_t dma_attr_desc = { 58744Sgs150176 DMA_ATTR_V0, /* dma_attr version */ 59744Sgs150176 (uint32_t)0, /* dma_attr_addr_lo */ 60744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 61744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_count_max */ 62744Sgs150176 (uint32_t)256, /* dma_attr_align */ 63744Sgs150176 0xFFFFFFFF, /* dma_attr_burstsizes */ 64744Sgs150176 1, /* dma_attr_minxfer */ 65744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 66744Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_seg */ 67744Sgs150176 1, /* dma_attr_sgllen */ 68744Sgs150176 1, /* dma_attr_granular */ 69744Sgs150176 0, /* dma_attr_flags */ 70744Sgs150176 }; 71744Sgs150176 72744Sgs150176 /* 73744Sgs150176 * PIO access attributes for registers 74744Sgs150176 */ 75744Sgs150176 static ddi_device_acc_attr_t rge_reg_accattr = { 76744Sgs150176 DDI_DEVICE_ATTR_V0, 77744Sgs150176 DDI_STRUCTURE_LE_ACC, 78744Sgs150176 DDI_STRICTORDER_ACC, 79744Sgs150176 DDI_DEFAULT_ACC 80744Sgs150176 }; 81744Sgs150176 82744Sgs150176 /* 83744Sgs150176 * DMA access attributes for descriptors 84744Sgs150176 */ 85744Sgs150176 static ddi_device_acc_attr_t rge_desc_accattr = { 86744Sgs150176 DDI_DEVICE_ATTR_V0, 87744Sgs150176 DDI_NEVERSWAP_ACC, 88744Sgs150176 DDI_STRICTORDER_ACC, 89744Sgs150176 DDI_DEFAULT_ACC 90744Sgs150176 }; 91744Sgs150176 92744Sgs150176 /* 93744Sgs150176 * DMA access attributes for data 94744Sgs150176 */ 95744Sgs150176 static ddi_device_acc_attr_t rge_buf_accattr = { 96744Sgs150176 DDI_DEVICE_ATTR_V0, 97744Sgs150176 DDI_NEVERSWAP_ACC, 98744Sgs150176 DDI_STRICTORDER_ACC, 99744Sgs150176 DDI_DEFAULT_ACC 100744Sgs150176 }; 101744Sgs150176 102744Sgs150176 /* 103744Sgs150176 * Property names 104744Sgs150176 */ 105*2544Sgs150176 static char debug_propname[] = "rge_debug_flags"; 106*2544Sgs150176 static char mtu_propname[] = "default_mtu"; 107*2544Sgs150176 static char msi_propname[] = "msi_enable"; 108744Sgs150176 1092311Sseb static int rge_m_start(void *); 1102311Sseb static void rge_m_stop(void *); 1112311Sseb static int rge_m_promisc(void *, boolean_t); 1122311Sseb static int rge_m_multicst(void *, boolean_t, const uint8_t *); 1132311Sseb static int rge_m_unicst(void *, const uint8_t *); 1142311Sseb static void rge_m_resources(void *); 1152311Sseb static void rge_m_ioctl(void *, queue_t *, mblk_t *); 1162311Sseb static boolean_t rge_m_getcapab(void *, mac_capab_t, void *); 1172311Sseb 1182311Sseb #define RGE_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB) 1192311Sseb 1202311Sseb static mac_callbacks_t rge_m_callbacks = { 1212311Sseb RGE_M_CALLBACK_FLAGS, 1222311Sseb rge_m_stat, 1232311Sseb rge_m_start, 1242311Sseb rge_m_stop, 1252311Sseb rge_m_promisc, 1262311Sseb rge_m_multicst, 1272311Sseb rge_m_unicst, 1282311Sseb rge_m_tx, 1292311Sseb rge_m_resources, 1302311Sseb rge_m_ioctl, 1312311Sseb rge_m_getcapab 1322311Sseb }; 133744Sgs150176 134744Sgs150176 /* 135744Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 136744Sgs150176 */ 137744Sgs150176 static int 138744Sgs150176 rge_alloc_dma_mem(rge_t *rgep, size_t memsize, ddi_dma_attr_t *dma_attr_p, 139744Sgs150176 ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, dma_area_t *dma_p) 140744Sgs150176 { 141744Sgs150176 caddr_t vaddr; 142744Sgs150176 int err; 143744Sgs150176 144744Sgs150176 /* 145744Sgs150176 * Allocate handle 146744Sgs150176 */ 147744Sgs150176 err = ddi_dma_alloc_handle(rgep->devinfo, dma_attr_p, 148744Sgs150176 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 149744Sgs150176 if (err != DDI_SUCCESS) { 150744Sgs150176 dma_p->dma_hdl = NULL; 151744Sgs150176 return (DDI_FAILURE); 152744Sgs150176 } 153744Sgs150176 154744Sgs150176 /* 155744Sgs150176 * Allocate memory 156744Sgs150176 */ 157744Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p, 158744Sgs150176 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 159744Sgs150176 DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 160744Sgs150176 if (err != DDI_SUCCESS) { 161744Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 162744Sgs150176 dma_p->dma_hdl = NULL; 163744Sgs150176 dma_p->acc_hdl = NULL; 164744Sgs150176 return (DDI_FAILURE); 165744Sgs150176 } 166744Sgs150176 167744Sgs150176 /* 168744Sgs150176 * Bind the two together 169744Sgs150176 */ 170744Sgs150176 dma_p->mem_va = vaddr; 171744Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 172744Sgs150176 vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 173744Sgs150176 &dma_p->cookie, &dma_p->ncookies); 174744Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) { 175744Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 176744Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 177744Sgs150176 dma_p->acc_hdl = NULL; 178744Sgs150176 dma_p->dma_hdl = NULL; 179744Sgs150176 return (DDI_FAILURE); 180744Sgs150176 } 181744Sgs150176 182744Sgs150176 dma_p->nslots = ~0U; 183744Sgs150176 dma_p->size = ~0U; 184744Sgs150176 dma_p->token = ~0U; 185744Sgs150176 dma_p->offset = 0; 186744Sgs150176 return (DDI_SUCCESS); 187744Sgs150176 } 188744Sgs150176 189744Sgs150176 /* 190744Sgs150176 * Free one allocated area of DMAable memory 191744Sgs150176 */ 192744Sgs150176 static void 193744Sgs150176 rge_free_dma_mem(dma_area_t *dma_p) 194744Sgs150176 { 195744Sgs150176 if (dma_p->dma_hdl != NULL) { 196744Sgs150176 if (dma_p->ncookies) { 197744Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 198744Sgs150176 dma_p->ncookies = 0; 199744Sgs150176 } 200744Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 201744Sgs150176 dma_p->dma_hdl = NULL; 202744Sgs150176 } 203744Sgs150176 204744Sgs150176 if (dma_p->acc_hdl != NULL) { 205744Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 206744Sgs150176 dma_p->acc_hdl = NULL; 207744Sgs150176 } 208744Sgs150176 } 209744Sgs150176 210744Sgs150176 /* 211744Sgs150176 * Utility routine to carve a slice off a chunk of allocated memory, 212744Sgs150176 * updating the chunk descriptor accordingly. The size of the slice 213744Sgs150176 * is given by the product of the <qty> and <size> parameters. 214744Sgs150176 */ 215744Sgs150176 static void 216744Sgs150176 rge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 217744Sgs150176 uint32_t qty, uint32_t size) 218744Sgs150176 { 219744Sgs150176 static uint32_t sequence = 0xbcd5704a; 220744Sgs150176 size_t totsize; 221744Sgs150176 222744Sgs150176 totsize = qty*size; 223744Sgs150176 ASSERT(size >= 0); 224744Sgs150176 ASSERT(totsize <= chunk->alength); 225744Sgs150176 226744Sgs150176 *slice = *chunk; 227744Sgs150176 slice->nslots = qty; 228744Sgs150176 slice->size = size; 229744Sgs150176 slice->alength = totsize; 230744Sgs150176 slice->token = ++sequence; 231744Sgs150176 232744Sgs150176 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 233744Sgs150176 chunk->alength -= totsize; 234744Sgs150176 chunk->offset += totsize; 235744Sgs150176 chunk->cookie.dmac_laddress += totsize; 236744Sgs150176 chunk->cookie.dmac_size -= totsize; 237744Sgs150176 } 238744Sgs150176 239744Sgs150176 static int 240744Sgs150176 rge_alloc_bufs(rge_t *rgep) 241744Sgs150176 { 242744Sgs150176 size_t txdescsize; 243744Sgs150176 size_t rxdescsize; 244744Sgs150176 int err; 245744Sgs150176 246744Sgs150176 /* 247744Sgs150176 * Allocate memory & handle for packet statistics 248744Sgs150176 */ 249744Sgs150176 err = rge_alloc_dma_mem(rgep, 250744Sgs150176 RGE_STATS_DUMP_SIZE, 251744Sgs150176 &dma_attr_desc, 252744Sgs150176 &rge_desc_accattr, 253744Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 254744Sgs150176 &rgep->dma_area_stats); 255744Sgs150176 if (err != DDI_SUCCESS) 256744Sgs150176 return (DDI_FAILURE); 257744Sgs150176 rgep->hw_stats = DMA_VPTR(rgep->dma_area_stats); 258744Sgs150176 259744Sgs150176 /* 260744Sgs150176 * Allocate memory & handle for Tx descriptor ring 261744Sgs150176 */ 262744Sgs150176 txdescsize = RGE_SEND_SLOTS * sizeof (rge_bd_t); 263744Sgs150176 err = rge_alloc_dma_mem(rgep, 264744Sgs150176 txdescsize, 265744Sgs150176 &dma_attr_desc, 266744Sgs150176 &rge_desc_accattr, 267744Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 268744Sgs150176 &rgep->dma_area_txdesc); 269744Sgs150176 if (err != DDI_SUCCESS) 270744Sgs150176 return (DDI_FAILURE); 271744Sgs150176 272744Sgs150176 /* 273744Sgs150176 * Allocate memory & handle for Rx descriptor ring 274744Sgs150176 */ 275744Sgs150176 rxdescsize = RGE_RECV_SLOTS * sizeof (rge_bd_t); 276744Sgs150176 err = rge_alloc_dma_mem(rgep, 277744Sgs150176 rxdescsize, 278744Sgs150176 &dma_attr_desc, 279744Sgs150176 &rge_desc_accattr, 280744Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 281744Sgs150176 &rgep->dma_area_rxdesc); 282744Sgs150176 if (err != DDI_SUCCESS) 283744Sgs150176 return (DDI_FAILURE); 284744Sgs150176 285744Sgs150176 return (DDI_SUCCESS); 286744Sgs150176 } 287744Sgs150176 288744Sgs150176 /* 289744Sgs150176 * rge_free_bufs() -- free descriptors/buffers allocated for this 290744Sgs150176 * device instance. 291744Sgs150176 */ 292744Sgs150176 static void 293744Sgs150176 rge_free_bufs(rge_t *rgep) 294744Sgs150176 { 295744Sgs150176 rge_free_dma_mem(&rgep->dma_area_stats); 296744Sgs150176 rge_free_dma_mem(&rgep->dma_area_txdesc); 297744Sgs150176 rge_free_dma_mem(&rgep->dma_area_rxdesc); 298744Sgs150176 } 299744Sgs150176 300744Sgs150176 /* 301744Sgs150176 * ========== Transmit and receive ring reinitialisation ========== 302744Sgs150176 */ 303744Sgs150176 304744Sgs150176 /* 305744Sgs150176 * These <reinit> routines each reset the rx/tx rings to an initial 306744Sgs150176 * state, assuming that the corresponding <init> routine has already 307744Sgs150176 * been called exactly once. 308744Sgs150176 */ 309744Sgs150176 static void 310744Sgs150176 rge_reinit_send_ring(rge_t *rgep) 311744Sgs150176 { 312744Sgs150176 sw_sbd_t *ssbdp; 313744Sgs150176 rge_bd_t *bdp; 314744Sgs150176 uint32_t slot; 315744Sgs150176 316744Sgs150176 /* 317744Sgs150176 * re-init send ring 318744Sgs150176 */ 319744Sgs150176 DMA_ZERO(rgep->tx_desc); 320744Sgs150176 ssbdp = rgep->sw_sbds; 321744Sgs150176 bdp = rgep->tx_ring; 322744Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; slot++) { 323744Sgs150176 bdp->host_buf_addr = 324744Sgs150176 RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress); 325744Sgs150176 bdp->host_buf_addr_hi = 326744Sgs150176 RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress >> 32); 327744Sgs150176 /* last BD in Tx ring */ 328744Sgs150176 if (slot == (RGE_SEND_SLOTS - 1)) 329744Sgs150176 bdp->flags_len = RGE_BSWAP_32(BD_FLAG_EOR); 330744Sgs150176 ssbdp++; 331744Sgs150176 bdp++; 332744Sgs150176 } 333744Sgs150176 DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV); 334744Sgs150176 rgep->tx_next = 0; 335744Sgs150176 rgep->tc_next = 0; 336744Sgs150176 rgep->tc_tail = 0; 337744Sgs150176 rgep->tx_flow = 0; 338744Sgs150176 rgep->tx_free = RGE_SEND_SLOTS; 339744Sgs150176 } 340744Sgs150176 341744Sgs150176 static void 342744Sgs150176 rge_reinit_recv_ring(rge_t *rgep) 343744Sgs150176 { 344744Sgs150176 rge_bd_t *bdp; 345744Sgs150176 sw_rbd_t *srbdp; 346744Sgs150176 dma_area_t *pbuf; 347744Sgs150176 uint32_t slot; 348744Sgs150176 349744Sgs150176 /* 350744Sgs150176 * re-init receive ring 351744Sgs150176 */ 352744Sgs150176 DMA_ZERO(rgep->rx_desc); 353744Sgs150176 srbdp = rgep->sw_rbds; 354744Sgs150176 bdp = rgep->rx_ring; 355744Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; slot++) { 356744Sgs150176 pbuf = &srbdp->rx_buf->pbuf; 357744Sgs150176 bdp->host_buf_addr = 358*2544Sgs150176 RGE_BSWAP_32(pbuf->cookie.dmac_laddress + rgep->head_room); 359744Sgs150176 bdp->host_buf_addr_hi = 360744Sgs150176 RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32); 361744Sgs150176 bdp->flags_len = RGE_BSWAP_32(BD_FLAG_HW_OWN | 362*2544Sgs150176 (rgep->rxbuf_size - rgep->head_room)); 363744Sgs150176 /* last BD in Tx ring */ 364744Sgs150176 if (slot == (RGE_RECV_SLOTS - 1)) 365744Sgs150176 bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR); 366744Sgs150176 srbdp++; 367744Sgs150176 bdp++; 368744Sgs150176 } 369744Sgs150176 DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV); 370744Sgs150176 rgep->watchdog = 0; 371744Sgs150176 rgep->rx_next = 0; 372744Sgs150176 } 373744Sgs150176 374744Sgs150176 static void 375744Sgs150176 rge_reinit_buf_ring(rge_t *rgep) 376744Sgs150176 { 377*2544Sgs150176 378*2544Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) 379*2544Sgs150176 return; 380*2544Sgs150176 381744Sgs150176 /* 382*2544Sgs150176 * If all the up-sending buffers haven't been returned to driver, 383*2544Sgs150176 * use bcopy() only in rx process. 384744Sgs150176 */ 385744Sgs150176 if (rgep->rx_free != RGE_BUF_SLOTS) 386744Sgs150176 rgep->rx_bcopy = B_TRUE; 387744Sgs150176 } 388744Sgs150176 389744Sgs150176 static void 390744Sgs150176 rge_reinit_rings(rge_t *rgep) 391744Sgs150176 { 392744Sgs150176 rge_reinit_send_ring(rgep); 393744Sgs150176 rge_reinit_recv_ring(rgep); 394744Sgs150176 rge_reinit_buf_ring(rgep); 395744Sgs150176 } 396744Sgs150176 397744Sgs150176 static void 398*2544Sgs150176 rge_fini_send_ring(rge_t *rgep) 399*2544Sgs150176 { 400*2544Sgs150176 sw_sbd_t *ssbdp; 401*2544Sgs150176 uint32_t slot; 402*2544Sgs150176 403*2544Sgs150176 ssbdp = rgep->sw_sbds; 404*2544Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; ++slot) { 405*2544Sgs150176 rge_free_dma_mem(&ssbdp->pbuf); 406*2544Sgs150176 ssbdp++; 407*2544Sgs150176 } 408*2544Sgs150176 409*2544Sgs150176 kmem_free(rgep->sw_sbds, RGE_SEND_SLOTS * sizeof (sw_sbd_t)); 410*2544Sgs150176 rgep->sw_sbds = NULL; 411*2544Sgs150176 } 412*2544Sgs150176 413*2544Sgs150176 static void 414*2544Sgs150176 rge_fini_recv_ring(rge_t *rgep) 415*2544Sgs150176 { 416*2544Sgs150176 sw_rbd_t *srbdp; 417*2544Sgs150176 uint32_t slot; 418*2544Sgs150176 419*2544Sgs150176 srbdp = rgep->sw_rbds; 420*2544Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; ++srbdp, ++slot) { 421*2544Sgs150176 if (srbdp->rx_buf) { 422*2544Sgs150176 if (srbdp->rx_buf->mp != NULL) { 423*2544Sgs150176 freemsg(srbdp->rx_buf->mp); 424*2544Sgs150176 srbdp->rx_buf->mp = NULL; 425*2544Sgs150176 } 426*2544Sgs150176 rge_free_dma_mem(&srbdp->rx_buf->pbuf); 427*2544Sgs150176 kmem_free(srbdp->rx_buf, sizeof (dma_buf_t)); 428*2544Sgs150176 srbdp->rx_buf = NULL; 429*2544Sgs150176 } 430*2544Sgs150176 } 431*2544Sgs150176 432*2544Sgs150176 kmem_free(rgep->sw_rbds, RGE_RECV_SLOTS * sizeof (sw_rbd_t)); 433*2544Sgs150176 rgep->sw_rbds = NULL; 434*2544Sgs150176 } 435*2544Sgs150176 436*2544Sgs150176 static void 437*2544Sgs150176 rge_fini_buf_ring(rge_t *rgep) 438*2544Sgs150176 { 439*2544Sgs150176 sw_rbd_t *srbdp; 440*2544Sgs150176 uint32_t slot; 441*2544Sgs150176 442*2544Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) 443*2544Sgs150176 return; 444*2544Sgs150176 445*2544Sgs150176 ASSERT(rgep->rx_free == RGE_BUF_SLOTS); 446*2544Sgs150176 447*2544Sgs150176 srbdp = rgep->free_srbds; 448*2544Sgs150176 for (slot = 0; slot < RGE_BUF_SLOTS; ++srbdp, ++slot) { 449*2544Sgs150176 if (srbdp->rx_buf != NULL) { 450*2544Sgs150176 if (srbdp->rx_buf->mp != NULL) { 451*2544Sgs150176 freemsg(srbdp->rx_buf->mp); 452*2544Sgs150176 srbdp->rx_buf->mp = NULL; 453*2544Sgs150176 } 454*2544Sgs150176 rge_free_dma_mem(&srbdp->rx_buf->pbuf); 455*2544Sgs150176 kmem_free(srbdp->rx_buf, sizeof (dma_buf_t)); 456*2544Sgs150176 srbdp->rx_buf = NULL; 457*2544Sgs150176 } 458*2544Sgs150176 } 459*2544Sgs150176 460*2544Sgs150176 kmem_free(rgep->free_srbds, RGE_BUF_SLOTS * sizeof (sw_rbd_t)); 461*2544Sgs150176 rgep->free_srbds = NULL; 462*2544Sgs150176 } 463*2544Sgs150176 464*2544Sgs150176 static void 465*2544Sgs150176 rge_fini_rings(rge_t *rgep) 466*2544Sgs150176 { 467*2544Sgs150176 rge_fini_send_ring(rgep); 468*2544Sgs150176 rge_fini_recv_ring(rgep); 469*2544Sgs150176 rge_fini_buf_ring(rgep); 470*2544Sgs150176 } 471*2544Sgs150176 472*2544Sgs150176 static int 473744Sgs150176 rge_init_send_ring(rge_t *rgep) 474744Sgs150176 { 475744Sgs150176 uint32_t slot; 476744Sgs150176 sw_sbd_t *ssbdp; 477744Sgs150176 dma_area_t *pbuf; 478*2544Sgs150176 dma_area_t desc; 479*2544Sgs150176 int err; 480744Sgs150176 481744Sgs150176 /* 482744Sgs150176 * Allocate the array of s/w Tx Buffer Descriptors 483744Sgs150176 */ 484744Sgs150176 ssbdp = kmem_zalloc(RGE_SEND_SLOTS*sizeof (*ssbdp), KM_SLEEP); 485744Sgs150176 rgep->sw_sbds = ssbdp; 486744Sgs150176 487744Sgs150176 /* 488744Sgs150176 * Init send ring 489744Sgs150176 */ 490744Sgs150176 rgep->tx_desc = rgep->dma_area_txdesc; 491744Sgs150176 DMA_ZERO(rgep->tx_desc); 492*2544Sgs150176 rgep->tx_ring = rgep->tx_desc.mem_va; 493*2544Sgs150176 494*2544Sgs150176 desc = rgep->tx_desc; 495*2544Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; slot++) { 496*2544Sgs150176 rge_slice_chunk(&ssbdp->desc, &desc, 1, sizeof (rge_bd_t)); 497*2544Sgs150176 498*2544Sgs150176 /* 499*2544Sgs150176 * Allocate memory & handle for Tx buffers 500*2544Sgs150176 */ 501*2544Sgs150176 pbuf = &ssbdp->pbuf; 502*2544Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->txbuf_size, 503*2544Sgs150176 &dma_attr_buf, &rge_buf_accattr, 504*2544Sgs150176 DDI_DMA_WRITE | DDI_DMA_STREAMING, pbuf); 505*2544Sgs150176 if (err != DDI_SUCCESS) { 506*2544Sgs150176 rge_error(rgep, 507*2544Sgs150176 "rge_init_send_ring: alloc tx buffer failed"); 508*2544Sgs150176 rge_fini_send_ring(rgep); 509*2544Sgs150176 return (DDI_FAILURE); 510744Sgs150176 } 511*2544Sgs150176 ssbdp++; 512744Sgs150176 } 513*2544Sgs150176 ASSERT(desc.alength == 0); 514*2544Sgs150176 515744Sgs150176 DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV); 516*2544Sgs150176 return (DDI_SUCCESS); 517744Sgs150176 } 518744Sgs150176 519744Sgs150176 static int 520744Sgs150176 rge_init_recv_ring(rge_t *rgep) 521744Sgs150176 { 522744Sgs150176 uint32_t slot; 523744Sgs150176 sw_rbd_t *srbdp; 524744Sgs150176 dma_buf_t *rx_buf; 525744Sgs150176 dma_area_t *pbuf; 526*2544Sgs150176 int err; 527744Sgs150176 528744Sgs150176 /* 529744Sgs150176 * Allocate the array of s/w Rx Buffer Descriptors 530744Sgs150176 */ 531744Sgs150176 srbdp = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*srbdp), KM_SLEEP); 532744Sgs150176 rgep->sw_rbds = srbdp; 533744Sgs150176 534744Sgs150176 /* 535744Sgs150176 * Init receive ring 536744Sgs150176 */ 537744Sgs150176 rgep->rx_next = 0; 538744Sgs150176 rgep->rx_desc = rgep->dma_area_rxdesc; 539744Sgs150176 DMA_ZERO(rgep->rx_desc); 540*2544Sgs150176 rgep->rx_ring = rgep->rx_desc.mem_va; 541*2544Sgs150176 542*2544Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; slot++) { 543*2544Sgs150176 srbdp->rx_buf = rx_buf = 544*2544Sgs150176 kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP); 545*2544Sgs150176 546*2544Sgs150176 /* 547*2544Sgs150176 * Allocate memory & handle for Rx buffers 548*2544Sgs150176 */ 549*2544Sgs150176 pbuf = &rx_buf->pbuf; 550*2544Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size, 551*2544Sgs150176 &dma_attr_buf, &rge_buf_accattr, 552*2544Sgs150176 DDI_DMA_READ | DDI_DMA_STREAMING, pbuf); 553*2544Sgs150176 if (err != DDI_SUCCESS) { 554*2544Sgs150176 rge_fini_recv_ring(rgep); 555*2544Sgs150176 rge_error(rgep, 556*2544Sgs150176 "rge_init_recv_ring: alloc rx buffer failed"); 557*2544Sgs150176 return (DDI_FAILURE); 558*2544Sgs150176 } 559*2544Sgs150176 560*2544Sgs150176 pbuf->alength -= rgep->head_room; 561*2544Sgs150176 pbuf->offset += rgep->head_room; 562*2544Sgs150176 if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)) { 563744Sgs150176 rx_buf->rx_recycle.free_func = rge_rx_recycle; 564744Sgs150176 rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf; 565744Sgs150176 rx_buf->private = (caddr_t)rgep; 566744Sgs150176 rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf), 567744Sgs150176 rgep->rxbuf_size, 0, &rx_buf->rx_recycle); 568744Sgs150176 if (rx_buf->mp == NULL) { 569*2544Sgs150176 rge_fini_recv_ring(rgep); 570744Sgs150176 rge_problem(rgep, 571744Sgs150176 "rge_init_recv_ring: desballoc() failed"); 572744Sgs150176 return (DDI_FAILURE); 573744Sgs150176 } 574744Sgs150176 } 575*2544Sgs150176 srbdp++; 576744Sgs150176 } 577744Sgs150176 DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV); 578744Sgs150176 return (DDI_SUCCESS); 579744Sgs150176 } 580744Sgs150176 581744Sgs150176 static int 582744Sgs150176 rge_init_buf_ring(rge_t *rgep) 583744Sgs150176 { 584744Sgs150176 uint32_t slot; 585*2544Sgs150176 sw_rbd_t *free_srbdp; 586744Sgs150176 dma_buf_t *rx_buf; 587744Sgs150176 dma_area_t *pbuf; 588*2544Sgs150176 int err; 589*2544Sgs150176 590*2544Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) { 591*2544Sgs150176 rgep->rx_bcopy = B_TRUE; 592*2544Sgs150176 return (DDI_SUCCESS); 593*2544Sgs150176 } 594744Sgs150176 595744Sgs150176 /* 596744Sgs150176 * Allocate the array of s/w free Buffer Descriptors 597744Sgs150176 */ 598*2544Sgs150176 free_srbdp = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*free_srbdp), KM_SLEEP); 599*2544Sgs150176 rgep->free_srbds = free_srbdp; 600744Sgs150176 601744Sgs150176 /* 602744Sgs150176 * Init free buffer ring 603744Sgs150176 */ 604744Sgs150176 rgep->rc_next = 0; 605744Sgs150176 rgep->rf_next = 0; 606744Sgs150176 rgep->rx_bcopy = B_FALSE; 607744Sgs150176 rgep->rx_free = RGE_BUF_SLOTS; 608*2544Sgs150176 for (slot = 0; slot < RGE_BUF_SLOTS; slot++) { 609*2544Sgs150176 free_srbdp->rx_buf = rx_buf = 610*2544Sgs150176 kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP); 611*2544Sgs150176 612*2544Sgs150176 /* 613*2544Sgs150176 * Allocate memory & handle for free Rx buffers 614*2544Sgs150176 */ 615*2544Sgs150176 pbuf = &rx_buf->pbuf; 616*2544Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size, 617*2544Sgs150176 &dma_attr_buf, &rge_buf_accattr, 618*2544Sgs150176 DDI_DMA_READ | DDI_DMA_STREAMING, pbuf); 619*2544Sgs150176 if (err != DDI_SUCCESS) { 620*2544Sgs150176 rge_fini_buf_ring(rgep); 621*2544Sgs150176 rge_error(rgep, 622*2544Sgs150176 "rge_init_buf_ring: alloc rx free buffer failed"); 623*2544Sgs150176 return (DDI_FAILURE); 624744Sgs150176 } 625*2544Sgs150176 pbuf->alength -= rgep->head_room; 626*2544Sgs150176 pbuf->offset += rgep->head_room; 627*2544Sgs150176 rx_buf->rx_recycle.free_func = rge_rx_recycle; 628*2544Sgs150176 rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf; 629*2544Sgs150176 rx_buf->private = (caddr_t)rgep; 630*2544Sgs150176 rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf), 631*2544Sgs150176 rgep->rxbuf_size, 0, &rx_buf->rx_recycle); 632*2544Sgs150176 if (rx_buf->mp == NULL) { 633*2544Sgs150176 rge_fini_buf_ring(rgep); 634*2544Sgs150176 rge_problem(rgep, 635*2544Sgs150176 "rge_init_buf_ring: desballoc() failed"); 636*2544Sgs150176 return (DDI_FAILURE); 637*2544Sgs150176 } 638*2544Sgs150176 free_srbdp++; 639744Sgs150176 } 640744Sgs150176 return (DDI_SUCCESS); 641744Sgs150176 } 642744Sgs150176 643744Sgs150176 static int 644744Sgs150176 rge_init_rings(rge_t *rgep) 645744Sgs150176 { 646744Sgs150176 int err; 647744Sgs150176 648*2544Sgs150176 err = rge_init_send_ring(rgep); 649*2544Sgs150176 if (err != DDI_SUCCESS) 650*2544Sgs150176 return (DDI_FAILURE); 651744Sgs150176 652*2544Sgs150176 err = rge_init_recv_ring(rgep); 653*2544Sgs150176 if (err != DDI_SUCCESS) { 654*2544Sgs150176 rge_fini_send_ring(rgep); 655*2544Sgs150176 return (DDI_FAILURE); 656*2544Sgs150176 } 657744Sgs150176 658*2544Sgs150176 err = rge_init_buf_ring(rgep); 659*2544Sgs150176 if (err != DDI_SUCCESS) { 660*2544Sgs150176 rge_fini_send_ring(rgep); 661*2544Sgs150176 rge_fini_recv_ring(rgep); 662*2544Sgs150176 return (DDI_FAILURE); 663*2544Sgs150176 } 664744Sgs150176 665*2544Sgs150176 return (DDI_SUCCESS); 666744Sgs150176 } 667744Sgs150176 668744Sgs150176 /* 669744Sgs150176 * ========== Internal state management entry points ========== 670744Sgs150176 */ 671744Sgs150176 672744Sgs150176 #undef RGE_DBG 673744Sgs150176 #define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */ 674744Sgs150176 675744Sgs150176 /* 676744Sgs150176 * These routines provide all the functionality required by the 677744Sgs150176 * corresponding MAC layer entry points, but don't update the 678744Sgs150176 * MAC state so they can be called internally without disturbing 679744Sgs150176 * our record of what NEMO thinks we should be doing ... 680744Sgs150176 */ 681744Sgs150176 682744Sgs150176 /* 683744Sgs150176 * rge_reset() -- reset h/w & rings to initial state 684744Sgs150176 */ 685744Sgs150176 static void 686744Sgs150176 rge_reset(rge_t *rgep) 687744Sgs150176 { 688744Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 689744Sgs150176 690744Sgs150176 /* 691744Sgs150176 * Grab all the other mutexes in the world (this should 692744Sgs150176 * ensure no other threads are manipulating driver state) 693744Sgs150176 */ 694744Sgs150176 mutex_enter(rgep->rx_lock); 695744Sgs150176 mutex_enter(rgep->rc_lock); 696744Sgs150176 rw_enter(rgep->errlock, RW_WRITER); 697744Sgs150176 698744Sgs150176 (void) rge_chip_reset(rgep); 699744Sgs150176 rge_reinit_rings(rgep); 700744Sgs150176 rge_chip_init(rgep); 701744Sgs150176 702744Sgs150176 /* 703744Sgs150176 * Free the world ... 704744Sgs150176 */ 705744Sgs150176 rw_exit(rgep->errlock); 706744Sgs150176 mutex_exit(rgep->rc_lock); 707744Sgs150176 mutex_exit(rgep->rx_lock); 708744Sgs150176 709744Sgs150176 RGE_DEBUG(("rge_reset($%p) done", (void *)rgep)); 710744Sgs150176 } 711744Sgs150176 712744Sgs150176 /* 713744Sgs150176 * rge_stop() -- stop processing, don't reset h/w or rings 714744Sgs150176 */ 715744Sgs150176 static void 716744Sgs150176 rge_stop(rge_t *rgep) 717744Sgs150176 { 718744Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 719744Sgs150176 720744Sgs150176 rge_chip_stop(rgep, B_FALSE); 721744Sgs150176 722744Sgs150176 RGE_DEBUG(("rge_stop($%p) done", (void *)rgep)); 723744Sgs150176 } 724744Sgs150176 725744Sgs150176 /* 726744Sgs150176 * rge_start() -- start transmitting/receiving 727744Sgs150176 */ 728744Sgs150176 static void 729744Sgs150176 rge_start(rge_t *rgep) 730744Sgs150176 { 731744Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 732744Sgs150176 733744Sgs150176 /* 734744Sgs150176 * Start chip processing, including enabling interrupts 735744Sgs150176 */ 736744Sgs150176 rge_chip_start(rgep); 737744Sgs150176 rgep->watchdog = 0; 738744Sgs150176 } 739744Sgs150176 740744Sgs150176 /* 741744Sgs150176 * rge_restart - restart transmitting/receiving after error or suspend 742744Sgs150176 */ 743744Sgs150176 void 744744Sgs150176 rge_restart(rge_t *rgep) 745744Sgs150176 { 746744Sgs150176 uint32_t i; 747744Sgs150176 748744Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 749744Sgs150176 /* 750744Sgs150176 * Wait for posted buffer to be freed... 751744Sgs150176 */ 752744Sgs150176 if (!rgep->rx_bcopy) { 753744Sgs150176 for (i = 0; i < RXBUFF_FREE_LOOP; i++) { 754744Sgs150176 if (rgep->rx_free == RGE_BUF_SLOTS) 755744Sgs150176 break; 756744Sgs150176 drv_usecwait(1000); 757744Sgs150176 RGE_DEBUG(("rge_restart: waiting for rx buf free...")); 758744Sgs150176 } 759744Sgs150176 } 760744Sgs150176 rge_reset(rgep); 761744Sgs150176 rgep->stats.chip_reset++; 762744Sgs150176 if (rgep->rge_mac_state == RGE_MAC_STARTED) { 763744Sgs150176 rge_start(rgep); 764*2544Sgs150176 rgep->resched_needed = B_TRUE; 765*2544Sgs150176 (void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL); 766744Sgs150176 } 767744Sgs150176 } 768744Sgs150176 769744Sgs150176 770744Sgs150176 /* 771744Sgs150176 * ========== Nemo-required management entry points ========== 772744Sgs150176 */ 773744Sgs150176 774744Sgs150176 #undef RGE_DBG 775744Sgs150176 #define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */ 776744Sgs150176 777744Sgs150176 /* 778744Sgs150176 * rge_m_stop() -- stop transmitting/receiving 779744Sgs150176 */ 780744Sgs150176 static void 781744Sgs150176 rge_m_stop(void *arg) 782744Sgs150176 { 783744Sgs150176 rge_t *rgep = arg; /* private device info */ 784744Sgs150176 uint32_t i; 785744Sgs150176 786744Sgs150176 /* 787744Sgs150176 * Just stop processing, then record new MAC state 788744Sgs150176 */ 789744Sgs150176 mutex_enter(rgep->genlock); 790744Sgs150176 rge_stop(rgep); 791744Sgs150176 rgep->link_up_msg = rgep->link_down_msg = " (stopped)"; 792744Sgs150176 /* 793744Sgs150176 * Wait for posted buffer to be freed... 794744Sgs150176 */ 795744Sgs150176 if (!rgep->rx_bcopy) { 796744Sgs150176 for (i = 0; i < RXBUFF_FREE_LOOP; i++) { 797744Sgs150176 if (rgep->rx_free == RGE_BUF_SLOTS) 798744Sgs150176 break; 799744Sgs150176 drv_usecwait(1000); 800744Sgs150176 RGE_DEBUG(("rge_m_stop: waiting for rx buf free...")); 801744Sgs150176 } 802744Sgs150176 } 803744Sgs150176 rgep->rge_mac_state = RGE_MAC_STOPPED; 804744Sgs150176 RGE_DEBUG(("rge_m_stop($%p) done", arg)); 805744Sgs150176 mutex_exit(rgep->genlock); 806744Sgs150176 } 807744Sgs150176 808744Sgs150176 /* 809744Sgs150176 * rge_m_start() -- start transmitting/receiving 810744Sgs150176 */ 811744Sgs150176 static int 812744Sgs150176 rge_m_start(void *arg) 813744Sgs150176 { 814744Sgs150176 rge_t *rgep = arg; /* private device info */ 815744Sgs150176 816744Sgs150176 mutex_enter(rgep->genlock); 817744Sgs150176 818744Sgs150176 /* 819744Sgs150176 * Clear hw/sw statistics 820744Sgs150176 */ 821744Sgs150176 DMA_ZERO(rgep->dma_area_stats); 822744Sgs150176 bzero(&rgep->stats, sizeof (rge_stats_t)); 823744Sgs150176 824744Sgs150176 /* 825744Sgs150176 * Start processing and record new MAC state 826744Sgs150176 */ 827744Sgs150176 rge_reset(rgep); 828744Sgs150176 rgep->link_up_msg = rgep->link_down_msg = " (initialized)"; 829744Sgs150176 rge_start(rgep); 830744Sgs150176 rgep->rge_mac_state = RGE_MAC_STARTED; 831744Sgs150176 RGE_DEBUG(("rge_m_start($%p) done", arg)); 832744Sgs150176 833744Sgs150176 mutex_exit(rgep->genlock); 834744Sgs150176 835744Sgs150176 return (0); 836744Sgs150176 } 837744Sgs150176 838744Sgs150176 /* 839744Sgs150176 * rge_m_unicst_set() -- set the physical network address 840744Sgs150176 */ 841744Sgs150176 static int 842744Sgs150176 rge_m_unicst(void *arg, const uint8_t *macaddr) 843744Sgs150176 { 844744Sgs150176 rge_t *rgep = arg; /* private device info */ 845744Sgs150176 846744Sgs150176 /* 847744Sgs150176 * Remember the new current address in the driver state 848744Sgs150176 * Sync the chip's idea of the address too ... 849744Sgs150176 */ 850744Sgs150176 mutex_enter(rgep->genlock); 851744Sgs150176 bcopy(macaddr, rgep->netaddr, ETHERADDRL); 852744Sgs150176 rge_chip_sync(rgep, RGE_SET_MAC); 853744Sgs150176 mutex_exit(rgep->genlock); 854744Sgs150176 855744Sgs150176 return (0); 856744Sgs150176 } 857744Sgs150176 858744Sgs150176 /* 859744Sgs150176 * Compute the index of the required bit in the multicast hash map. 860744Sgs150176 * This must mirror the way the hardware actually does it! 861744Sgs150176 */ 862744Sgs150176 static uint32_t 863744Sgs150176 rge_hash_index(const uint8_t *mca) 864744Sgs150176 { 865*2544Sgs150176 uint32_t crc = (uint32_t)RGE_HASH_CRC; 866744Sgs150176 uint32_t const POLY = RGE_HASH_POLY; 867744Sgs150176 uint32_t msb; 868744Sgs150176 int bytes; 869744Sgs150176 uchar_t currentbyte; 870744Sgs150176 uint32_t index; 871744Sgs150176 int bit; 872744Sgs150176 873744Sgs150176 for (bytes = 0; bytes < ETHERADDRL; bytes++) { 874744Sgs150176 currentbyte = mca[bytes]; 875744Sgs150176 for (bit = 0; bit < 8; bit++) { 876744Sgs150176 msb = crc >> 31; 877744Sgs150176 crc <<= 1; 878*2544Sgs150176 if (msb ^ (currentbyte & 1)) 879744Sgs150176 crc ^= POLY; 880744Sgs150176 currentbyte >>= 1; 881744Sgs150176 } 882744Sgs150176 } 883744Sgs150176 index = crc >> 26; 884*2544Sgs150176 /* the index value is between 0 and 63(0x3f) */ 885744Sgs150176 886744Sgs150176 return (index); 887744Sgs150176 } 888744Sgs150176 889744Sgs150176 /* 890744Sgs150176 * rge_m_multicst_add() -- enable/disable a multicast address 891744Sgs150176 */ 892744Sgs150176 static int 893744Sgs150176 rge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 894744Sgs150176 { 895744Sgs150176 rge_t *rgep = arg; /* private device info */ 896744Sgs150176 struct ether_addr *addr; 897744Sgs150176 uint32_t index; 898*2544Sgs150176 uint32_t reg; 899*2544Sgs150176 uint8_t *hashp; 900744Sgs150176 901744Sgs150176 mutex_enter(rgep->genlock); 902744Sgs150176 hashp = rgep->mcast_hash; 903744Sgs150176 addr = (struct ether_addr *)mca; 904*2544Sgs150176 /* 905*2544Sgs150176 * Calculate the Multicast address hash index value 906*2544Sgs150176 * Normally, the position of MAR0-MAR7 is 907*2544Sgs150176 * MAR0: offset 0x08, ..., MAR7: offset 0x0F. 908*2544Sgs150176 * 909*2544Sgs150176 * For pcie chipset, the position of MAR0-MAR7 is 910*2544Sgs150176 * different from others: 911*2544Sgs150176 * MAR0: offset 0x0F, ..., MAR7: offset 0x08. 912*2544Sgs150176 */ 913744Sgs150176 index = rge_hash_index(addr->ether_addr_octet); 914*2544Sgs150176 if (rgep->chipid.is_pcie) 915*2544Sgs150176 reg = (~(index / RGE_MCAST_NUM)) & 0x7; 916*2544Sgs150176 else 917*2544Sgs150176 reg = index / RGE_MCAST_NUM; 918744Sgs150176 919744Sgs150176 if (add) { 920744Sgs150176 if (rgep->mcast_refs[index]++) { 921744Sgs150176 mutex_exit(rgep->genlock); 922744Sgs150176 return (0); 923744Sgs150176 } 924*2544Sgs150176 hashp[reg] |= 1 << (index % RGE_MCAST_NUM); 925744Sgs150176 } else { 926744Sgs150176 if (--rgep->mcast_refs[index]) { 927744Sgs150176 mutex_exit(rgep->genlock); 928744Sgs150176 return (0); 929744Sgs150176 } 930*2544Sgs150176 hashp[reg] &= ~ (1 << (index % RGE_MCAST_NUM)); 931744Sgs150176 } 932744Sgs150176 933744Sgs150176 /* 934744Sgs150176 * Set multicast register 935744Sgs150176 */ 936744Sgs150176 rge_chip_sync(rgep, RGE_SET_MUL); 937744Sgs150176 938744Sgs150176 mutex_exit(rgep->genlock); 939744Sgs150176 return (0); 940744Sgs150176 } 941744Sgs150176 942744Sgs150176 /* 943744Sgs150176 * rge_m_promisc() -- set or reset promiscuous mode on the board 944744Sgs150176 * 945744Sgs150176 * Program the hardware to enable/disable promiscuous and/or 946744Sgs150176 * receive-all-multicast modes. 947744Sgs150176 */ 948744Sgs150176 static int 949744Sgs150176 rge_m_promisc(void *arg, boolean_t on) 950744Sgs150176 { 951744Sgs150176 rge_t *rgep = arg; 952744Sgs150176 953744Sgs150176 /* 954744Sgs150176 * Store MAC layer specified mode and pass to chip layer to update h/w 955744Sgs150176 */ 956744Sgs150176 mutex_enter(rgep->genlock); 957744Sgs150176 958744Sgs150176 if (rgep->promisc == on) { 959744Sgs150176 mutex_exit(rgep->genlock); 960744Sgs150176 return (0); 961744Sgs150176 } 962744Sgs150176 rgep->promisc = on; 963744Sgs150176 rge_chip_sync(rgep, RGE_SET_PROMISC); 964744Sgs150176 RGE_DEBUG(("rge_m_promisc_set($%p) done", arg)); 965744Sgs150176 mutex_exit(rgep->genlock); 966744Sgs150176 return (0); 967744Sgs150176 } 968744Sgs150176 969744Sgs150176 /* 970744Sgs150176 * Loopback ioctl code 971744Sgs150176 */ 972744Sgs150176 973744Sgs150176 static lb_property_t loopmodes[] = { 974744Sgs150176 { normal, "normal", RGE_LOOP_NONE }, 975744Sgs150176 { internal, "PHY", RGE_LOOP_INTERNAL_PHY }, 976744Sgs150176 { internal, "MAC", RGE_LOOP_INTERNAL_MAC } 977744Sgs150176 }; 978744Sgs150176 979744Sgs150176 static enum ioc_reply 980744Sgs150176 rge_set_loop_mode(rge_t *rgep, uint32_t mode) 981744Sgs150176 { 982744Sgs150176 const char *msg; 983744Sgs150176 984744Sgs150176 /* 985744Sgs150176 * If the mode isn't being changed, there's nothing to do ... 986744Sgs150176 */ 987744Sgs150176 if (mode == rgep->param_loop_mode) 988744Sgs150176 return (IOC_ACK); 989744Sgs150176 990744Sgs150176 /* 991744Sgs150176 * Validate the requested mode and prepare a suitable message 992744Sgs150176 * to explain the link down/up cycle that the change will 993744Sgs150176 * probably induce ... 994744Sgs150176 */ 995744Sgs150176 switch (mode) { 996744Sgs150176 default: 997744Sgs150176 return (IOC_INVAL); 998744Sgs150176 999744Sgs150176 case RGE_LOOP_NONE: 1000744Sgs150176 msg = " (loopback disabled)"; 1001744Sgs150176 break; 1002744Sgs150176 1003744Sgs150176 case RGE_LOOP_INTERNAL_PHY: 1004744Sgs150176 msg = " (PHY internal loopback selected)"; 1005744Sgs150176 break; 1006744Sgs150176 1007744Sgs150176 case RGE_LOOP_INTERNAL_MAC: 1008744Sgs150176 msg = " (MAC internal loopback selected)"; 1009744Sgs150176 break; 1010744Sgs150176 } 1011744Sgs150176 1012744Sgs150176 /* 1013744Sgs150176 * All OK; tell the caller to reprogram 1014744Sgs150176 * the PHY and/or MAC for the new mode ... 1015744Sgs150176 */ 1016744Sgs150176 rgep->link_down_msg = rgep->link_up_msg = msg; 1017744Sgs150176 rgep->param_loop_mode = mode; 1018744Sgs150176 return (IOC_RESTART_ACK); 1019744Sgs150176 } 1020744Sgs150176 1021744Sgs150176 static enum ioc_reply 1022744Sgs150176 rge_loop_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 1023744Sgs150176 { 1024744Sgs150176 lb_info_sz_t *lbsp; 1025744Sgs150176 lb_property_t *lbpp; 1026744Sgs150176 uint32_t *lbmp; 1027744Sgs150176 int cmd; 1028744Sgs150176 1029744Sgs150176 _NOTE(ARGUNUSED(wq)) 1030744Sgs150176 1031744Sgs150176 /* 1032744Sgs150176 * Validate format of ioctl 1033744Sgs150176 */ 1034744Sgs150176 if (mp->b_cont == NULL) 1035744Sgs150176 return (IOC_INVAL); 1036744Sgs150176 1037744Sgs150176 cmd = iocp->ioc_cmd; 1038744Sgs150176 switch (cmd) { 1039744Sgs150176 default: 1040744Sgs150176 /* NOTREACHED */ 1041744Sgs150176 rge_error(rgep, "rge_loop_ioctl: invalid cmd 0x%x", cmd); 1042744Sgs150176 return (IOC_INVAL); 1043744Sgs150176 1044744Sgs150176 case LB_GET_INFO_SIZE: 1045744Sgs150176 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 1046744Sgs150176 return (IOC_INVAL); 1047744Sgs150176 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 1048744Sgs150176 *lbsp = sizeof (loopmodes); 1049744Sgs150176 return (IOC_REPLY); 1050744Sgs150176 1051744Sgs150176 case LB_GET_INFO: 1052744Sgs150176 if (iocp->ioc_count != sizeof (loopmodes)) 1053744Sgs150176 return (IOC_INVAL); 1054744Sgs150176 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 1055744Sgs150176 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 1056744Sgs150176 return (IOC_REPLY); 1057744Sgs150176 1058744Sgs150176 case LB_GET_MODE: 1059744Sgs150176 if (iocp->ioc_count != sizeof (uint32_t)) 1060744Sgs150176 return (IOC_INVAL); 1061744Sgs150176 lbmp = (uint32_t *)mp->b_cont->b_rptr; 1062744Sgs150176 *lbmp = rgep->param_loop_mode; 1063744Sgs150176 return (IOC_REPLY); 1064744Sgs150176 1065744Sgs150176 case LB_SET_MODE: 1066744Sgs150176 if (iocp->ioc_count != sizeof (uint32_t)) 1067744Sgs150176 return (IOC_INVAL); 1068744Sgs150176 lbmp = (uint32_t *)mp->b_cont->b_rptr; 1069744Sgs150176 return (rge_set_loop_mode(rgep, *lbmp)); 1070744Sgs150176 } 1071744Sgs150176 } 1072744Sgs150176 1073744Sgs150176 /* 1074744Sgs150176 * Specific rge IOCTLs, the MAC layer handles the generic ones. 1075744Sgs150176 */ 1076744Sgs150176 static void 1077744Sgs150176 rge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 1078744Sgs150176 { 1079744Sgs150176 rge_t *rgep = arg; 1080744Sgs150176 struct iocblk *iocp; 1081744Sgs150176 enum ioc_reply status; 1082744Sgs150176 boolean_t need_privilege; 1083744Sgs150176 int err; 1084744Sgs150176 int cmd; 1085744Sgs150176 1086744Sgs150176 /* 1087744Sgs150176 * Validate the command before bothering with the mutex ... 1088744Sgs150176 */ 1089744Sgs150176 iocp = (struct iocblk *)mp->b_rptr; 1090744Sgs150176 iocp->ioc_error = 0; 1091744Sgs150176 need_privilege = B_TRUE; 1092744Sgs150176 cmd = iocp->ioc_cmd; 1093744Sgs150176 switch (cmd) { 1094744Sgs150176 default: 1095744Sgs150176 miocnak(wq, mp, 0, EINVAL); 1096744Sgs150176 return; 1097744Sgs150176 1098744Sgs150176 case RGE_MII_READ: 1099744Sgs150176 case RGE_MII_WRITE: 1100744Sgs150176 case RGE_DIAG: 1101744Sgs150176 case RGE_PEEK: 1102744Sgs150176 case RGE_POKE: 1103744Sgs150176 case RGE_PHY_RESET: 1104744Sgs150176 case RGE_SOFT_RESET: 1105744Sgs150176 case RGE_HARD_RESET: 1106744Sgs150176 break; 1107744Sgs150176 1108744Sgs150176 case LB_GET_INFO_SIZE: 1109744Sgs150176 case LB_GET_INFO: 1110744Sgs150176 case LB_GET_MODE: 1111744Sgs150176 need_privilege = B_FALSE; 1112744Sgs150176 /* FALLTHRU */ 1113744Sgs150176 case LB_SET_MODE: 1114744Sgs150176 break; 1115744Sgs150176 1116744Sgs150176 case ND_GET: 1117744Sgs150176 need_privilege = B_FALSE; 1118744Sgs150176 /* FALLTHRU */ 1119744Sgs150176 case ND_SET: 1120744Sgs150176 break; 1121744Sgs150176 } 1122744Sgs150176 1123744Sgs150176 if (need_privilege) { 1124744Sgs150176 /* 1125*2544Sgs150176 * Check for specific net_config privilege 1126744Sgs150176 */ 1127*2544Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 1128744Sgs150176 if (err != 0) { 1129744Sgs150176 miocnak(wq, mp, 0, err); 1130744Sgs150176 return; 1131744Sgs150176 } 1132744Sgs150176 } 1133744Sgs150176 1134744Sgs150176 mutex_enter(rgep->genlock); 1135744Sgs150176 1136744Sgs150176 switch (cmd) { 1137744Sgs150176 default: 1138744Sgs150176 _NOTE(NOTREACHED) 1139744Sgs150176 status = IOC_INVAL; 1140744Sgs150176 break; 1141744Sgs150176 1142744Sgs150176 case RGE_MII_READ: 1143744Sgs150176 case RGE_MII_WRITE: 1144744Sgs150176 case RGE_DIAG: 1145744Sgs150176 case RGE_PEEK: 1146744Sgs150176 case RGE_POKE: 1147744Sgs150176 case RGE_PHY_RESET: 1148744Sgs150176 case RGE_SOFT_RESET: 1149744Sgs150176 case RGE_HARD_RESET: 1150744Sgs150176 status = rge_chip_ioctl(rgep, wq, mp, iocp); 1151744Sgs150176 break; 1152744Sgs150176 1153744Sgs150176 case LB_GET_INFO_SIZE: 1154744Sgs150176 case LB_GET_INFO: 1155744Sgs150176 case LB_GET_MODE: 1156744Sgs150176 case LB_SET_MODE: 1157744Sgs150176 status = rge_loop_ioctl(rgep, wq, mp, iocp); 1158744Sgs150176 break; 1159744Sgs150176 1160744Sgs150176 case ND_GET: 1161744Sgs150176 case ND_SET: 1162744Sgs150176 status = rge_nd_ioctl(rgep, wq, mp, iocp); 1163744Sgs150176 break; 1164744Sgs150176 } 1165744Sgs150176 1166744Sgs150176 /* 1167744Sgs150176 * Do we need to reprogram the PHY and/or the MAC? 1168744Sgs150176 * Do it now, while we still have the mutex. 1169744Sgs150176 * 1170744Sgs150176 * Note: update the PHY first, 'cos it controls the 1171744Sgs150176 * speed/duplex parameters that the MAC code uses. 1172744Sgs150176 */ 1173744Sgs150176 switch (status) { 1174744Sgs150176 case IOC_RESTART_REPLY: 1175744Sgs150176 case IOC_RESTART_ACK: 1176744Sgs150176 rge_phy_update(rgep); 1177744Sgs150176 break; 1178744Sgs150176 } 1179744Sgs150176 1180744Sgs150176 mutex_exit(rgep->genlock); 1181744Sgs150176 1182744Sgs150176 /* 1183744Sgs150176 * Finally, decide how to reply 1184744Sgs150176 */ 1185744Sgs150176 switch (status) { 1186744Sgs150176 default: 1187744Sgs150176 case IOC_INVAL: 1188744Sgs150176 /* 1189744Sgs150176 * Error, reply with a NAK and EINVAL or the specified error 1190744Sgs150176 */ 1191744Sgs150176 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 1192744Sgs150176 EINVAL : iocp->ioc_error); 1193744Sgs150176 break; 1194744Sgs150176 1195744Sgs150176 case IOC_DONE: 1196744Sgs150176 /* 1197744Sgs150176 * OK, reply already sent 1198744Sgs150176 */ 1199744Sgs150176 break; 1200744Sgs150176 1201744Sgs150176 case IOC_RESTART_ACK: 1202744Sgs150176 case IOC_ACK: 1203744Sgs150176 /* 1204744Sgs150176 * OK, reply with an ACK 1205744Sgs150176 */ 1206744Sgs150176 miocack(wq, mp, 0, 0); 1207744Sgs150176 break; 1208744Sgs150176 1209744Sgs150176 case IOC_RESTART_REPLY: 1210744Sgs150176 case IOC_REPLY: 1211744Sgs150176 /* 1212744Sgs150176 * OK, send prepared reply as ACK or NAK 1213744Sgs150176 */ 1214744Sgs150176 mp->b_datap->db_type = iocp->ioc_error == 0 ? 1215744Sgs150176 M_IOCACK : M_IOCNAK; 1216744Sgs150176 qreply(wq, mp); 1217744Sgs150176 break; 1218744Sgs150176 } 1219744Sgs150176 } 1220744Sgs150176 1221744Sgs150176 static void 1222744Sgs150176 rge_m_resources(void *arg) 1223744Sgs150176 { 1224744Sgs150176 rge_t *rgep = arg; 1225744Sgs150176 mac_rx_fifo_t mrf; 1226744Sgs150176 1227744Sgs150176 mutex_enter(rgep->genlock); 1228744Sgs150176 1229744Sgs150176 /* 1230744Sgs150176 * Register Rx rings as resources and save mac 1231744Sgs150176 * resource id for future reference 1232744Sgs150176 */ 1233744Sgs150176 mrf.mrf_type = MAC_RX_FIFO; 1234744Sgs150176 mrf.mrf_blank = rge_chip_blank; 1235744Sgs150176 mrf.mrf_arg = (void *)rgep; 1236744Sgs150176 mrf.mrf_normal_blank_time = RGE_RX_INT_TIME; 1237744Sgs150176 mrf.mrf_normal_pkt_count = RGE_RX_INT_PKTS; 12382311Sseb rgep->handle = mac_resource_add(rgep->mh, (mac_resource_t *)&mrf); 1239744Sgs150176 1240744Sgs150176 mutex_exit(rgep->genlock); 1241744Sgs150176 } 1242744Sgs150176 12432311Sseb /* ARGSUSED */ 12442311Sseb static boolean_t 12452311Sseb rge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 12462311Sseb { 12472311Sseb switch (cap) { 12482311Sseb case MAC_CAPAB_HCKSUM: { 12492311Sseb uint32_t *hcksum_txflags = cap_data; 12502311Sseb *hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 12512311Sseb break; 12522311Sseb } 12532311Sseb case MAC_CAPAB_POLL: 12542311Sseb /* 12552311Sseb * There's nothing for us to fill in, simply returning 12562311Sseb * B_TRUE stating that we support polling is sufficient. 12572311Sseb */ 12582311Sseb break; 12592311Sseb default: 12602311Sseb return (B_FALSE); 12612311Sseb } 12622311Sseb return (B_TRUE); 12632311Sseb } 12642311Sseb 1265744Sgs150176 /* 1266*2544Sgs150176 * ============ Init MSI/Fixed Interrupt routines ============== 1267*2544Sgs150176 */ 1268*2544Sgs150176 1269*2544Sgs150176 /* 1270*2544Sgs150176 * rge_add_intrs: 1271*2544Sgs150176 * 1272*2544Sgs150176 * Register FIXED or MSI interrupts. 1273*2544Sgs150176 */ 1274*2544Sgs150176 static int 1275*2544Sgs150176 rge_add_intrs(rge_t *rgep, int intr_type) 1276*2544Sgs150176 { 1277*2544Sgs150176 dev_info_t *dip = rgep->devinfo; 1278*2544Sgs150176 int avail; 1279*2544Sgs150176 int actual; 1280*2544Sgs150176 int intr_size; 1281*2544Sgs150176 int count; 1282*2544Sgs150176 int i, j; 1283*2544Sgs150176 int ret; 1284*2544Sgs150176 1285*2544Sgs150176 /* Get number of interrupts */ 1286*2544Sgs150176 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 1287*2544Sgs150176 if ((ret != DDI_SUCCESS) || (count == 0)) { 1288*2544Sgs150176 rge_error(rgep, "ddi_intr_get_nintrs() failure, ret: %d, " 1289*2544Sgs150176 "count: %d", ret, count); 1290*2544Sgs150176 return (DDI_FAILURE); 1291*2544Sgs150176 } 1292*2544Sgs150176 1293*2544Sgs150176 /* Get number of available interrupts */ 1294*2544Sgs150176 ret = ddi_intr_get_navail(dip, intr_type, &avail); 1295*2544Sgs150176 if ((ret != DDI_SUCCESS) || (avail == 0)) { 1296*2544Sgs150176 rge_error(rgep, "ddi_intr_get_navail() failure, " 1297*2544Sgs150176 "ret: %d, avail: %d\n", ret, avail); 1298*2544Sgs150176 return (DDI_FAILURE); 1299*2544Sgs150176 } 1300*2544Sgs150176 1301*2544Sgs150176 /* Allocate an array of interrupt handles */ 1302*2544Sgs150176 intr_size = count * sizeof (ddi_intr_handle_t); 1303*2544Sgs150176 rgep->htable = kmem_alloc(intr_size, KM_SLEEP); 1304*2544Sgs150176 rgep->intr_rqst = count; 1305*2544Sgs150176 1306*2544Sgs150176 /* Call ddi_intr_alloc() */ 1307*2544Sgs150176 ret = ddi_intr_alloc(dip, rgep->htable, intr_type, 0, 1308*2544Sgs150176 count, &actual, DDI_INTR_ALLOC_NORMAL); 1309*2544Sgs150176 if (ret != DDI_SUCCESS || actual == 0) { 1310*2544Sgs150176 rge_error(rgep, "ddi_intr_alloc() failed %d\n", ret); 1311*2544Sgs150176 kmem_free(rgep->htable, intr_size); 1312*2544Sgs150176 return (DDI_FAILURE); 1313*2544Sgs150176 } 1314*2544Sgs150176 if (actual < count) { 1315*2544Sgs150176 rge_log(rgep, "ddi_intr_alloc() Requested: %d, Received: %d\n", 1316*2544Sgs150176 count, actual); 1317*2544Sgs150176 } 1318*2544Sgs150176 rgep->intr_cnt = actual; 1319*2544Sgs150176 1320*2544Sgs150176 /* 1321*2544Sgs150176 * Get priority for first msi, assume remaining are all the same 1322*2544Sgs150176 */ 1323*2544Sgs150176 if ((ret = ddi_intr_get_pri(rgep->htable[0], &rgep->intr_pri)) != 1324*2544Sgs150176 DDI_SUCCESS) { 1325*2544Sgs150176 rge_error(rgep, "ddi_intr_get_pri() failed %d\n", ret); 1326*2544Sgs150176 /* Free already allocated intr */ 1327*2544Sgs150176 for (i = 0; i < actual; i++) { 1328*2544Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1329*2544Sgs150176 } 1330*2544Sgs150176 kmem_free(rgep->htable, intr_size); 1331*2544Sgs150176 return (DDI_FAILURE); 1332*2544Sgs150176 } 1333*2544Sgs150176 1334*2544Sgs150176 /* Test for high level mutex */ 1335*2544Sgs150176 if (rgep->intr_pri >= ddi_intr_get_hilevel_pri()) { 1336*2544Sgs150176 rge_error(rgep, "rge_add_intrs:" 1337*2544Sgs150176 "Hi level interrupt not supported"); 1338*2544Sgs150176 for (i = 0; i < actual; i++) 1339*2544Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1340*2544Sgs150176 kmem_free(rgep->htable, intr_size); 1341*2544Sgs150176 return (DDI_FAILURE); 1342*2544Sgs150176 } 1343*2544Sgs150176 1344*2544Sgs150176 /* Call ddi_intr_add_handler() */ 1345*2544Sgs150176 for (i = 0; i < actual; i++) { 1346*2544Sgs150176 if ((ret = ddi_intr_add_handler(rgep->htable[i], rge_intr, 1347*2544Sgs150176 (caddr_t)rgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 1348*2544Sgs150176 rge_error(rgep, "ddi_intr_add_handler() " 1349*2544Sgs150176 "failed %d\n", ret); 1350*2544Sgs150176 /* Remove already added intr */ 1351*2544Sgs150176 for (j = 0; j < i; j++) 1352*2544Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[j]); 1353*2544Sgs150176 /* Free already allocated intr */ 1354*2544Sgs150176 for (i = 0; i < actual; i++) { 1355*2544Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1356*2544Sgs150176 } 1357*2544Sgs150176 kmem_free(rgep->htable, intr_size); 1358*2544Sgs150176 return (DDI_FAILURE); 1359*2544Sgs150176 } 1360*2544Sgs150176 } 1361*2544Sgs150176 1362*2544Sgs150176 if ((ret = ddi_intr_get_cap(rgep->htable[0], &rgep->intr_cap)) 1363*2544Sgs150176 != DDI_SUCCESS) { 1364*2544Sgs150176 rge_error(rgep, "ddi_intr_get_cap() failed %d\n", ret); 1365*2544Sgs150176 for (i = 0; i < actual; i++) { 1366*2544Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[i]); 1367*2544Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1368*2544Sgs150176 } 1369*2544Sgs150176 kmem_free(rgep->htable, intr_size); 1370*2544Sgs150176 return (DDI_FAILURE); 1371*2544Sgs150176 } 1372*2544Sgs150176 1373*2544Sgs150176 return (DDI_SUCCESS); 1374*2544Sgs150176 } 1375*2544Sgs150176 1376*2544Sgs150176 /* 1377*2544Sgs150176 * rge_rem_intrs: 1378*2544Sgs150176 * 1379*2544Sgs150176 * Unregister FIXED or MSI interrupts 1380*2544Sgs150176 */ 1381*2544Sgs150176 static void 1382*2544Sgs150176 rge_rem_intrs(rge_t *rgep) 1383*2544Sgs150176 { 1384*2544Sgs150176 int i; 1385*2544Sgs150176 1386*2544Sgs150176 /* Disable all interrupts */ 1387*2544Sgs150176 if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 1388*2544Sgs150176 /* Call ddi_intr_block_disable() */ 1389*2544Sgs150176 (void) ddi_intr_block_disable(rgep->htable, rgep->intr_cnt); 1390*2544Sgs150176 } else { 1391*2544Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1392*2544Sgs150176 (void) ddi_intr_disable(rgep->htable[i]); 1393*2544Sgs150176 } 1394*2544Sgs150176 } 1395*2544Sgs150176 1396*2544Sgs150176 /* Call ddi_intr_remove_handler() */ 1397*2544Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1398*2544Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[i]); 1399*2544Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1400*2544Sgs150176 } 1401*2544Sgs150176 1402*2544Sgs150176 kmem_free(rgep->htable, rgep->intr_rqst * sizeof (ddi_intr_handle_t)); 1403*2544Sgs150176 } 1404*2544Sgs150176 1405*2544Sgs150176 /* 1406744Sgs150176 * ========== Per-instance setup/teardown code ========== 1407744Sgs150176 */ 1408744Sgs150176 1409744Sgs150176 #undef RGE_DBG 1410744Sgs150176 #define RGE_DBG RGE_DBG_INIT /* debug flag for this code */ 1411744Sgs150176 1412744Sgs150176 static void 1413744Sgs150176 rge_unattach(rge_t *rgep) 1414744Sgs150176 { 1415744Sgs150176 /* 1416744Sgs150176 * Flag that no more activity may be initiated 1417744Sgs150176 */ 1418744Sgs150176 rgep->progress &= ~PROGRESS_READY; 1419744Sgs150176 rgep->rge_mac_state = RGE_MAC_UNATTACH; 1420744Sgs150176 1421744Sgs150176 /* 1422744Sgs150176 * Quiesce the PHY and MAC (leave it reset but still powered). 1423744Sgs150176 * Clean up and free all RGE data structures 1424744Sgs150176 */ 1425744Sgs150176 if (rgep->cyclic_id) { 1426744Sgs150176 mutex_enter(&cpu_lock); 1427744Sgs150176 cyclic_remove(rgep->cyclic_id); 1428744Sgs150176 mutex_exit(&cpu_lock); 1429744Sgs150176 } 1430744Sgs150176 1431744Sgs150176 if (rgep->progress & PROGRESS_KSTATS) 1432744Sgs150176 rge_fini_kstats(rgep); 1433744Sgs150176 1434744Sgs150176 if (rgep->progress & PROGRESS_PHY) 1435744Sgs150176 (void) rge_phy_reset(rgep); 1436744Sgs150176 1437*2544Sgs150176 if (rgep->progress & PROGRESS_INIT) { 1438744Sgs150176 mutex_enter(rgep->genlock); 1439744Sgs150176 (void) rge_chip_reset(rgep); 1440744Sgs150176 mutex_exit(rgep->genlock); 1441744Sgs150176 rge_fini_rings(rgep); 1442*2544Sgs150176 } 1443*2544Sgs150176 1444*2544Sgs150176 if (rgep->progress & PROGRESS_INTR) { 1445*2544Sgs150176 rge_rem_intrs(rgep); 1446744Sgs150176 mutex_destroy(rgep->rc_lock); 1447744Sgs150176 mutex_destroy(rgep->rx_lock); 1448744Sgs150176 mutex_destroy(rgep->tc_lock); 1449744Sgs150176 mutex_destroy(rgep->tx_lock); 1450744Sgs150176 rw_destroy(rgep->errlock); 1451744Sgs150176 mutex_destroy(rgep->genlock); 1452744Sgs150176 } 1453744Sgs150176 1454744Sgs150176 if (rgep->progress & PROGRESS_FACTOTUM) 1455*2544Sgs150176 (void) ddi_intr_remove_softint(rgep->factotum_hdl); 1456744Sgs150176 1457744Sgs150176 if (rgep->progress & PROGRESS_RESCHED) 1458*2544Sgs150176 (void) ddi_intr_remove_softint(rgep->resched_hdl); 1459744Sgs150176 1460744Sgs150176 rge_free_bufs(rgep); 1461744Sgs150176 1462744Sgs150176 if (rgep->progress & PROGRESS_NDD) 1463744Sgs150176 rge_nd_cleanup(rgep); 1464744Sgs150176 1465744Sgs150176 if (rgep->progress & PROGRESS_REGS) 1466744Sgs150176 ddi_regs_map_free(&rgep->io_handle); 1467744Sgs150176 1468744Sgs150176 if (rgep->progress & PROGRESS_CFG) 1469744Sgs150176 pci_config_teardown(&rgep->cfg_handle); 1470744Sgs150176 1471744Sgs150176 ddi_remove_minor_node(rgep->devinfo, NULL); 1472744Sgs150176 kmem_free(rgep, sizeof (*rgep)); 1473744Sgs150176 } 1474744Sgs150176 1475744Sgs150176 static int 1476744Sgs150176 rge_resume(dev_info_t *devinfo) 1477744Sgs150176 { 1478744Sgs150176 rge_t *rgep; /* Our private data */ 1479744Sgs150176 chip_id_t *cidp; 1480744Sgs150176 chip_id_t chipid; 1481744Sgs150176 1482744Sgs150176 rgep = ddi_get_driver_private(devinfo); 1483744Sgs150176 if (rgep == NULL) 1484744Sgs150176 return (DDI_FAILURE); 1485744Sgs150176 1486744Sgs150176 /* 1487744Sgs150176 * Refuse to resume if the data structures aren't consistent 1488744Sgs150176 */ 1489744Sgs150176 if (rgep->devinfo != devinfo) 1490744Sgs150176 return (DDI_FAILURE); 1491744Sgs150176 1492744Sgs150176 /* 1493744Sgs150176 * Read chip ID & set up config space command register(s) 1494744Sgs150176 * Refuse to resume if the chip has changed its identity! 1495744Sgs150176 */ 1496744Sgs150176 cidp = &rgep->chipid; 1497744Sgs150176 rge_chip_cfg_init(rgep, &chipid); 1498744Sgs150176 if (chipid.vendor != cidp->vendor) 1499744Sgs150176 return (DDI_FAILURE); 1500744Sgs150176 if (chipid.device != cidp->device) 1501744Sgs150176 return (DDI_FAILURE); 1502744Sgs150176 if (chipid.revision != cidp->revision) 1503744Sgs150176 return (DDI_FAILURE); 1504744Sgs150176 1505744Sgs150176 /* 1506744Sgs150176 * All OK, reinitialise h/w & kick off NEMO scheduling 1507744Sgs150176 */ 1508744Sgs150176 mutex_enter(rgep->genlock); 1509744Sgs150176 rge_restart(rgep); 1510744Sgs150176 mutex_exit(rgep->genlock); 1511744Sgs150176 return (DDI_SUCCESS); 1512744Sgs150176 } 1513744Sgs150176 1514744Sgs150176 1515744Sgs150176 /* 1516744Sgs150176 * attach(9E) -- Attach a device to the system 1517744Sgs150176 * 1518744Sgs150176 * Called once for each board successfully probed. 1519744Sgs150176 */ 1520744Sgs150176 static int 1521744Sgs150176 rge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 1522744Sgs150176 { 1523744Sgs150176 rge_t *rgep; /* Our private data */ 15242311Sseb mac_register_t *macp; 1525744Sgs150176 chip_id_t *cidp; 1526744Sgs150176 cyc_handler_t cychand; 1527744Sgs150176 cyc_time_t cyctime; 1528*2544Sgs150176 int intr_types; 1529744Sgs150176 caddr_t regs; 1530744Sgs150176 int instance; 1531*2544Sgs150176 int i; 1532744Sgs150176 int err; 1533744Sgs150176 1534744Sgs150176 /* 1535744Sgs150176 * we don't support high level interrupts in the driver 1536744Sgs150176 */ 1537744Sgs150176 if (ddi_intr_hilevel(devinfo, 0) != 0) { 1538744Sgs150176 cmn_err(CE_WARN, 1539744Sgs150176 "rge_attach -- unsupported high level interrupt"); 1540744Sgs150176 return (DDI_FAILURE); 1541744Sgs150176 } 1542744Sgs150176 1543744Sgs150176 instance = ddi_get_instance(devinfo); 1544744Sgs150176 RGE_GTRACE(("rge_attach($%p, %d) instance %d", 1545744Sgs150176 (void *)devinfo, cmd, instance)); 1546744Sgs150176 RGE_BRKPT(NULL, "rge_attach"); 1547744Sgs150176 1548744Sgs150176 switch (cmd) { 1549744Sgs150176 default: 1550744Sgs150176 return (DDI_FAILURE); 1551744Sgs150176 1552744Sgs150176 case DDI_RESUME: 1553744Sgs150176 return (rge_resume(devinfo)); 1554744Sgs150176 1555744Sgs150176 case DDI_ATTACH: 1556744Sgs150176 break; 1557744Sgs150176 } 1558744Sgs150176 1559744Sgs150176 rgep = kmem_zalloc(sizeof (*rgep), KM_SLEEP); 1560744Sgs150176 ddi_set_driver_private(devinfo, rgep); 1561744Sgs150176 rgep->devinfo = devinfo; 1562744Sgs150176 1563744Sgs150176 /* 1564744Sgs150176 * Initialize more fields in RGE private data 1565744Sgs150176 */ 1566*2544Sgs150176 rgep->rge_mac_state = RGE_MAC_ATTACH; 1567744Sgs150176 rgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1568744Sgs150176 DDI_PROP_DONTPASS, debug_propname, rge_debug); 1569*2544Sgs150176 rgep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1570*2544Sgs150176 DDI_PROP_DONTPASS, mtu_propname, ETHERMTU); 1571*2544Sgs150176 rgep->msi_enable = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1572*2544Sgs150176 DDI_PROP_DONTPASS, msi_propname, B_TRUE); 1573744Sgs150176 (void) snprintf(rgep->ifname, sizeof (rgep->ifname), "%s%d", 1574744Sgs150176 RGE_DRIVER_NAME, instance); 1575744Sgs150176 1576744Sgs150176 /* 1577744Sgs150176 * Map config space registers 1578744Sgs150176 * Read chip ID & set up config space command register(s) 1579744Sgs150176 * 1580744Sgs150176 * Note: this leaves the chip accessible by Memory Space 1581744Sgs150176 * accesses, but with interrupts and Bus Mastering off. 1582744Sgs150176 * This should ensure that nothing untoward will happen 1583744Sgs150176 * if it has been left active by the (net-)bootloader. 1584744Sgs150176 * We'll re-enable Bus Mastering once we've reset the chip, 1585744Sgs150176 * and allow interrupts only when everything else is set up. 1586744Sgs150176 */ 1587744Sgs150176 err = pci_config_setup(devinfo, &rgep->cfg_handle); 1588744Sgs150176 if (err != DDI_SUCCESS) { 1589744Sgs150176 rge_problem(rgep, "pci_config_setup() failed"); 1590744Sgs150176 goto attach_fail; 1591744Sgs150176 } 1592744Sgs150176 rgep->progress |= PROGRESS_CFG; 1593744Sgs150176 cidp = &rgep->chipid; 1594744Sgs150176 bzero(cidp, sizeof (*cidp)); 1595744Sgs150176 rge_chip_cfg_init(rgep, cidp); 1596744Sgs150176 1597744Sgs150176 /* 1598744Sgs150176 * Map operating registers 1599744Sgs150176 */ 1600744Sgs150176 err = ddi_regs_map_setup(devinfo, 1, ®s, 1601744Sgs150176 0, 0, &rge_reg_accattr, &rgep->io_handle); 1602744Sgs150176 if (err != DDI_SUCCESS) { 1603744Sgs150176 rge_problem(rgep, "ddi_regs_map_setup() failed"); 1604744Sgs150176 goto attach_fail; 1605744Sgs150176 } 1606744Sgs150176 rgep->io_regs = regs; 1607744Sgs150176 rgep->progress |= PROGRESS_REGS; 1608744Sgs150176 1609744Sgs150176 /* 1610744Sgs150176 * Register NDD-tweakable parameters 1611744Sgs150176 */ 1612744Sgs150176 if (rge_nd_init(rgep)) { 1613744Sgs150176 rge_problem(rgep, "rge_nd_init() failed"); 1614744Sgs150176 goto attach_fail; 1615744Sgs150176 } 1616744Sgs150176 rgep->progress |= PROGRESS_NDD; 1617744Sgs150176 1618744Sgs150176 /* 1619744Sgs150176 * Characterise the device, so we know its requirements. 1620744Sgs150176 * Then allocate the appropriate TX and RX descriptors & buffers. 1621744Sgs150176 */ 1622744Sgs150176 rge_chip_ident(rgep); 1623744Sgs150176 err = rge_alloc_bufs(rgep); 1624744Sgs150176 if (err != DDI_SUCCESS) { 1625744Sgs150176 rge_problem(rgep, "DMA buffer allocation failed"); 1626744Sgs150176 goto attach_fail; 1627744Sgs150176 } 1628744Sgs150176 1629744Sgs150176 /* 1630744Sgs150176 * Add the softint handlers: 1631744Sgs150176 * 1632744Sgs150176 * Both of these handlers are used to avoid restrictions on the 1633744Sgs150176 * context and/or mutexes required for some operations. In 1634744Sgs150176 * particular, the hardware interrupt handler and its subfunctions 1635744Sgs150176 * can detect a number of conditions that we don't want to handle 1636744Sgs150176 * in that context or with that set of mutexes held. So, these 1637744Sgs150176 * softints are triggered instead: 1638744Sgs150176 * 1639744Sgs150176 * the <resched> softint is triggered if if we have previously 1640744Sgs150176 * had to refuse to send a packet because of resource shortage 1641744Sgs150176 * (we've run out of transmit buffers), but the send completion 1642744Sgs150176 * interrupt handler has now detected that more buffers have 1643744Sgs150176 * become available. 1644744Sgs150176 * 1645744Sgs150176 * the <factotum> is triggered if the h/w interrupt handler 1646744Sgs150176 * sees the <link state changed> or <error> bits in the status 1647744Sgs150176 * block. It's also triggered periodically to poll the link 1648744Sgs150176 * state, just in case we aren't getting link status change 1649744Sgs150176 * interrupts ... 1650744Sgs150176 */ 1651*2544Sgs150176 err = ddi_intr_add_softint(devinfo, &rgep->resched_hdl, 1652*2544Sgs150176 DDI_INTR_SOFTPRI_MIN, rge_reschedule, (caddr_t)rgep); 1653744Sgs150176 if (err != DDI_SUCCESS) { 1654*2544Sgs150176 rge_problem(rgep, "ddi_intr_add_softint() failed"); 1655744Sgs150176 goto attach_fail; 1656744Sgs150176 } 1657744Sgs150176 rgep->progress |= PROGRESS_RESCHED; 1658*2544Sgs150176 err = ddi_intr_add_softint(devinfo, &rgep->factotum_hdl, 1659*2544Sgs150176 DDI_INTR_SOFTPRI_MIN, rge_chip_factotum, (caddr_t)rgep); 1660744Sgs150176 if (err != DDI_SUCCESS) { 1661*2544Sgs150176 rge_problem(rgep, "ddi_intr_add_softint() failed"); 1662744Sgs150176 goto attach_fail; 1663744Sgs150176 } 1664744Sgs150176 rgep->progress |= PROGRESS_FACTOTUM; 1665744Sgs150176 1666744Sgs150176 /* 1667*2544Sgs150176 * Get supported interrupt types 1668744Sgs150176 */ 1669*2544Sgs150176 if (ddi_intr_get_supported_types(devinfo, &intr_types) 1670*2544Sgs150176 != DDI_SUCCESS) { 1671*2544Sgs150176 rge_error(rgep, "ddi_intr_get_supported_types failed\n"); 1672744Sgs150176 goto attach_fail; 1673744Sgs150176 } 1674*2544Sgs150176 1675*2544Sgs150176 /* 1676*2544Sgs150176 * Add the h/w interrupt handler and initialise mutexes 1677*2544Sgs150176 */ 1678*2544Sgs150176 if ((intr_types & DDI_INTR_TYPE_MSI) && rgep->msi_enable) { 1679*2544Sgs150176 if (rge_add_intrs(rgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 1680*2544Sgs150176 rge_error(rgep, "MSI registration failed, " 1681*2544Sgs150176 "trying FIXED interrupt type\n"); 1682*2544Sgs150176 } else { 1683*2544Sgs150176 rge_log(rgep, "Using MSI interrupt type\n"); 1684*2544Sgs150176 rgep->intr_type = DDI_INTR_TYPE_MSI; 1685*2544Sgs150176 rgep->progress |= PROGRESS_INTR; 1686*2544Sgs150176 } 1687*2544Sgs150176 } 1688*2544Sgs150176 if (!(rgep->progress & PROGRESS_INTR) && 1689*2544Sgs150176 (intr_types & DDI_INTR_TYPE_FIXED)) { 1690*2544Sgs150176 if (rge_add_intrs(rgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 1691*2544Sgs150176 rge_error(rgep, "FIXED interrupt " 1692*2544Sgs150176 "registration failed\n"); 1693*2544Sgs150176 goto attach_fail; 1694*2544Sgs150176 } 1695*2544Sgs150176 rge_log(rgep, "Using FIXED interrupt type\n"); 1696*2544Sgs150176 rgep->intr_type = DDI_INTR_TYPE_FIXED; 1697*2544Sgs150176 rgep->progress |= PROGRESS_INTR; 1698*2544Sgs150176 } 1699*2544Sgs150176 if (!(rgep->progress & PROGRESS_INTR)) { 1700*2544Sgs150176 rge_error(rgep, "No interrupts registered\n"); 1701*2544Sgs150176 goto attach_fail; 1702*2544Sgs150176 } 1703*2544Sgs150176 mutex_init(rgep->genlock, NULL, MUTEX_DRIVER, 1704*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1705*2544Sgs150176 rw_init(rgep->errlock, NULL, RW_DRIVER, 1706*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1707*2544Sgs150176 mutex_init(rgep->tx_lock, NULL, MUTEX_DRIVER, 1708*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1709*2544Sgs150176 mutex_init(rgep->tc_lock, NULL, MUTEX_DRIVER, 1710*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1711*2544Sgs150176 mutex_init(rgep->rx_lock, NULL, MUTEX_DRIVER, 1712*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1713*2544Sgs150176 mutex_init(rgep->rc_lock, NULL, MUTEX_DRIVER, 1714*2544Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1715744Sgs150176 1716744Sgs150176 /* 1717744Sgs150176 * Initialize rings 1718744Sgs150176 */ 1719744Sgs150176 err = rge_init_rings(rgep); 1720744Sgs150176 if (err != DDI_SUCCESS) { 1721744Sgs150176 rge_problem(rgep, "rge_init_rings() failed"); 1722744Sgs150176 goto attach_fail; 1723744Sgs150176 } 1724*2544Sgs150176 rgep->progress |= PROGRESS_INIT; 1725*2544Sgs150176 1726*2544Sgs150176 /* 1727*2544Sgs150176 * Now that mutex locks are initialized, enable interrupts. 1728*2544Sgs150176 */ 1729*2544Sgs150176 if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 1730*2544Sgs150176 /* Call ddi_intr_block_enable() for MSI interrupts */ 1731*2544Sgs150176 (void) ddi_intr_block_enable(rgep->htable, rgep->intr_cnt); 1732*2544Sgs150176 } else { 1733*2544Sgs150176 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 1734*2544Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1735*2544Sgs150176 (void) ddi_intr_enable(rgep->htable[i]); 1736*2544Sgs150176 } 1737*2544Sgs150176 } 1738744Sgs150176 1739744Sgs150176 /* 1740744Sgs150176 * Initialise link state variables 1741744Sgs150176 * Stop, reset & reinitialise the chip. 1742744Sgs150176 * Initialise the (internal) PHY. 1743744Sgs150176 */ 1744744Sgs150176 rgep->param_link_up = LINK_STATE_UNKNOWN; 1745744Sgs150176 rgep->link_up_msg = rgep->link_down_msg = " (initialised)"; 1746744Sgs150176 1747744Sgs150176 /* 1748744Sgs150176 * Reset chip & rings to initial state; also reset address 1749744Sgs150176 * filtering, promiscuity, loopback mode. 1750744Sgs150176 */ 1751744Sgs150176 mutex_enter(rgep->genlock); 1752744Sgs150176 (void) rge_chip_reset(rgep); 1753744Sgs150176 rge_chip_sync(rgep, RGE_GET_MAC); 1754744Sgs150176 bzero(rgep->mcast_hash, sizeof (rgep->mcast_hash)); 1755744Sgs150176 bzero(rgep->mcast_refs, sizeof (rgep->mcast_refs)); 1756744Sgs150176 rgep->promisc = B_FALSE; 1757744Sgs150176 rgep->param_loop_mode = RGE_LOOP_NONE; 1758744Sgs150176 mutex_exit(rgep->genlock); 1759744Sgs150176 rge_phy_init(rgep); 1760744Sgs150176 rgep->progress |= PROGRESS_PHY; 1761744Sgs150176 1762744Sgs150176 /* 1763744Sgs150176 * Create & initialise named kstats 1764744Sgs150176 */ 1765744Sgs150176 rge_init_kstats(rgep, instance); 1766744Sgs150176 rgep->progress |= PROGRESS_KSTATS; 1767744Sgs150176 17682311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 17692311Sseb goto attach_fail; 17702311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 17712311Sseb macp->m_driver = rgep; 1772744Sgs150176 macp->m_dip = devinfo; 17732311Sseb macp->m_src_addr = rgep->netaddr; 17742311Sseb macp->m_callbacks = &rge_m_callbacks; 17752311Sseb macp->m_min_sdu = 0; 1776*2544Sgs150176 macp->m_max_sdu = rgep->default_mtu; 1777744Sgs150176 1778744Sgs150176 /* 1779744Sgs150176 * Finally, we're ready to register ourselves with the MAC layer 1780744Sgs150176 * interface; if this succeeds, we're all ready to start() 1781744Sgs150176 */ 17822311Sseb err = mac_register(macp, &rgep->mh); 17832311Sseb mac_free(macp); 17842311Sseb if (err != 0) 1785744Sgs150176 goto attach_fail; 1786744Sgs150176 1787744Sgs150176 cychand.cyh_func = rge_chip_cyclic; 1788744Sgs150176 cychand.cyh_arg = rgep; 1789744Sgs150176 cychand.cyh_level = CY_LOCK_LEVEL; 1790744Sgs150176 cyctime.cyt_when = 0; 1791744Sgs150176 cyctime.cyt_interval = RGE_CYCLIC_PERIOD; 1792744Sgs150176 mutex_enter(&cpu_lock); 1793744Sgs150176 rgep->cyclic_id = cyclic_add(&cychand, &cyctime); 1794744Sgs150176 mutex_exit(&cpu_lock); 1795744Sgs150176 1796744Sgs150176 rgep->progress |= PROGRESS_READY; 1797744Sgs150176 return (DDI_SUCCESS); 1798744Sgs150176 1799744Sgs150176 attach_fail: 1800744Sgs150176 rge_unattach(rgep); 1801744Sgs150176 return (DDI_FAILURE); 1802744Sgs150176 } 1803744Sgs150176 1804744Sgs150176 /* 1805744Sgs150176 * rge_suspend() -- suspend transmit/receive for powerdown 1806744Sgs150176 */ 1807744Sgs150176 static int 1808744Sgs150176 rge_suspend(rge_t *rgep) 1809744Sgs150176 { 1810744Sgs150176 /* 1811744Sgs150176 * Stop processing and idle (powerdown) the PHY ... 1812744Sgs150176 */ 1813744Sgs150176 mutex_enter(rgep->genlock); 1814744Sgs150176 rge_stop(rgep); 1815744Sgs150176 mutex_exit(rgep->genlock); 1816744Sgs150176 1817744Sgs150176 return (DDI_SUCCESS); 1818744Sgs150176 } 1819744Sgs150176 1820744Sgs150176 /* 1821744Sgs150176 * detach(9E) -- Detach a device from the system 1822744Sgs150176 */ 1823744Sgs150176 static int 1824744Sgs150176 rge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 1825744Sgs150176 { 1826744Sgs150176 rge_t *rgep; 1827744Sgs150176 1828744Sgs150176 RGE_GTRACE(("rge_detach($%p, %d)", (void *)devinfo, cmd)); 1829744Sgs150176 1830744Sgs150176 rgep = ddi_get_driver_private(devinfo); 1831744Sgs150176 1832744Sgs150176 switch (cmd) { 1833744Sgs150176 default: 1834744Sgs150176 return (DDI_FAILURE); 1835744Sgs150176 1836744Sgs150176 case DDI_SUSPEND: 1837744Sgs150176 return (rge_suspend(rgep)); 1838744Sgs150176 1839744Sgs150176 case DDI_DETACH: 1840744Sgs150176 break; 1841744Sgs150176 } 1842744Sgs150176 1843744Sgs150176 /* 1844744Sgs150176 * If there is any posted buffer, the driver should reject to be 1845744Sgs150176 * detached. Need notice upper layer to release them. 1846744Sgs150176 */ 1847*2544Sgs150176 if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) && 1848*2544Sgs150176 rgep->rx_free != RGE_BUF_SLOTS) 1849744Sgs150176 return (DDI_FAILURE); 1850744Sgs150176 1851744Sgs150176 /* 1852744Sgs150176 * Unregister from the MAC layer subsystem. This can fail, in 1853744Sgs150176 * particular if there are DLPI style-2 streams still open - 1854744Sgs150176 * in which case we just return failure without shutting 1855744Sgs150176 * down chip operations. 1856744Sgs150176 */ 18572311Sseb if (mac_unregister(rgep->mh) != 0) 1858744Sgs150176 return (DDI_FAILURE); 1859744Sgs150176 1860744Sgs150176 /* 1861744Sgs150176 * All activity stopped, so we can clean up & exit 1862744Sgs150176 */ 1863744Sgs150176 rge_unattach(rgep); 1864744Sgs150176 return (DDI_SUCCESS); 1865744Sgs150176 } 1866744Sgs150176 1867744Sgs150176 1868744Sgs150176 /* 1869744Sgs150176 * ========== Module Loading Data & Entry Points ========== 1870744Sgs150176 */ 1871744Sgs150176 1872744Sgs150176 #undef RGE_DBG 1873744Sgs150176 #define RGE_DBG RGE_DBG_INIT /* debug flag for this code */ 1874744Sgs150176 DDI_DEFINE_STREAM_OPS(rge_dev_ops, nulldev, nulldev, rge_attach, rge_detach, 1875744Sgs150176 nodev, NULL, D_MP, NULL); 1876744Sgs150176 1877744Sgs150176 static struct modldrv rge_modldrv = { 1878744Sgs150176 &mod_driverops, /* Type of module. This one is a driver */ 1879744Sgs150176 rge_ident, /* short description */ 1880744Sgs150176 &rge_dev_ops /* driver specific ops */ 1881744Sgs150176 }; 1882744Sgs150176 1883744Sgs150176 static struct modlinkage modlinkage = { 1884744Sgs150176 MODREV_1, (void *)&rge_modldrv, NULL 1885744Sgs150176 }; 1886744Sgs150176 1887744Sgs150176 1888744Sgs150176 int 1889744Sgs150176 _info(struct modinfo *modinfop) 1890744Sgs150176 { 1891744Sgs150176 return (mod_info(&modlinkage, modinfop)); 1892744Sgs150176 } 1893744Sgs150176 1894744Sgs150176 int 1895744Sgs150176 _init(void) 1896744Sgs150176 { 1897744Sgs150176 int status; 1898744Sgs150176 1899744Sgs150176 mac_init_ops(&rge_dev_ops, "rge"); 1900744Sgs150176 status = mod_install(&modlinkage); 1901744Sgs150176 if (status == DDI_SUCCESS) 1902744Sgs150176 mutex_init(rge_log_mutex, NULL, MUTEX_DRIVER, NULL); 1903744Sgs150176 else 1904744Sgs150176 mac_fini_ops(&rge_dev_ops); 1905744Sgs150176 1906744Sgs150176 return (status); 1907744Sgs150176 } 1908744Sgs150176 1909744Sgs150176 int 1910744Sgs150176 _fini(void) 1911744Sgs150176 { 1912744Sgs150176 int status; 1913744Sgs150176 1914744Sgs150176 status = mod_remove(&modlinkage); 1915744Sgs150176 if (status == DDI_SUCCESS) { 1916744Sgs150176 mac_fini_ops(&rge_dev_ops); 1917744Sgs150176 mutex_destroy(rge_log_mutex); 1918744Sgs150176 } 1919744Sgs150176 return (status); 1920744Sgs150176 } 1921