1c7fd2ed0Sgs150176 /* 2c7fd2ed0Sgs150176 * CDDL HEADER START 3c7fd2ed0Sgs150176 * 4c7fd2ed0Sgs150176 * The contents of this file are subject to the terms of the 5ba2e4443Sseb * Common Development and Distribution License (the "License"). 6ba2e4443Sseb * You may not use this file except in compliance with the License. 7c7fd2ed0Sgs150176 * 8c7fd2ed0Sgs150176 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c7fd2ed0Sgs150176 * or http://www.opensolaris.org/os/licensing. 10c7fd2ed0Sgs150176 * See the License for the specific language governing permissions 11c7fd2ed0Sgs150176 * and limitations under the License. 12c7fd2ed0Sgs150176 * 13c7fd2ed0Sgs150176 * When distributing Covered Code, include this CDDL HEADER in each 14c7fd2ed0Sgs150176 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c7fd2ed0Sgs150176 * If applicable, add the following below this CDDL HEADER, with the 16c7fd2ed0Sgs150176 * fields enclosed by brackets "[]" replaced with your own identifying 17c7fd2ed0Sgs150176 * information: Portions Copyright [yyyy] [name of copyright owner] 18c7fd2ed0Sgs150176 * 19c7fd2ed0Sgs150176 * CDDL HEADER END 20c7fd2ed0Sgs150176 */ 21c7fd2ed0Sgs150176 /* 225ca61e50SLi-Zhen You * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23c7fd2ed0Sgs150176 * Use is subject to license terms. 24c7fd2ed0Sgs150176 */ 25c7fd2ed0Sgs150176 26c7fd2ed0Sgs150176 #include "rge.h" 27c7fd2ed0Sgs150176 28c7fd2ed0Sgs150176 /* 29c7fd2ed0Sgs150176 * This is the string displayed by modinfo, etc. 30c7fd2ed0Sgs150176 * Make sure you keep the version ID up to date! 31c7fd2ed0Sgs150176 */ 3219397407SSherry Moore static char rge_ident[] = "Realtek 1Gb Ethernet"; 33c7fd2ed0Sgs150176 34c7fd2ed0Sgs150176 /* 35c7fd2ed0Sgs150176 * Used for buffers allocated by ddi_dma_mem_alloc() 36c7fd2ed0Sgs150176 */ 37c7fd2ed0Sgs150176 static ddi_dma_attr_t dma_attr_buf = { 38c7fd2ed0Sgs150176 DMA_ATTR_V0, /* dma_attr version */ 39c7fd2ed0Sgs150176 (uint32_t)0, /* dma_attr_addr_lo */ 40c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 41c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_count_max */ 42c7fd2ed0Sgs150176 (uint32_t)16, /* dma_attr_align */ 43c7fd2ed0Sgs150176 0xFFFFFFFF, /* dma_attr_burstsizes */ 44c7fd2ed0Sgs150176 1, /* dma_attr_minxfer */ 45c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 46c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_seg */ 47c7fd2ed0Sgs150176 1, /* dma_attr_sgllen */ 48c7fd2ed0Sgs150176 1, /* dma_attr_granular */ 49c7fd2ed0Sgs150176 0, /* dma_attr_flags */ 50c7fd2ed0Sgs150176 }; 51c7fd2ed0Sgs150176 52c7fd2ed0Sgs150176 /* 53c7fd2ed0Sgs150176 * Used for BDs allocated by ddi_dma_mem_alloc() 54c7fd2ed0Sgs150176 */ 55c7fd2ed0Sgs150176 static ddi_dma_attr_t dma_attr_desc = { 56c7fd2ed0Sgs150176 DMA_ATTR_V0, /* dma_attr version */ 57c7fd2ed0Sgs150176 (uint32_t)0, /* dma_attr_addr_lo */ 58c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 59c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_count_max */ 60c7fd2ed0Sgs150176 (uint32_t)256, /* dma_attr_align */ 61c7fd2ed0Sgs150176 0xFFFFFFFF, /* dma_attr_burstsizes */ 62c7fd2ed0Sgs150176 1, /* dma_attr_minxfer */ 63c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 64c7fd2ed0Sgs150176 (uint32_t)0xFFFFFFFF, /* dma_attr_seg */ 65c7fd2ed0Sgs150176 1, /* dma_attr_sgllen */ 66c7fd2ed0Sgs150176 1, /* dma_attr_granular */ 67c7fd2ed0Sgs150176 0, /* dma_attr_flags */ 68c7fd2ed0Sgs150176 }; 69c7fd2ed0Sgs150176 70c7fd2ed0Sgs150176 /* 71c7fd2ed0Sgs150176 * PIO access attributes for registers 72c7fd2ed0Sgs150176 */ 73c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_reg_accattr = { 74c7fd2ed0Sgs150176 DDI_DEVICE_ATTR_V0, 75c7fd2ed0Sgs150176 DDI_STRUCTURE_LE_ACC, 76c7fd2ed0Sgs150176 DDI_STRICTORDER_ACC, 77c7fd2ed0Sgs150176 DDI_DEFAULT_ACC 78c7fd2ed0Sgs150176 }; 79c7fd2ed0Sgs150176 80c7fd2ed0Sgs150176 /* 81c7fd2ed0Sgs150176 * DMA access attributes for descriptors 82c7fd2ed0Sgs150176 */ 83c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_desc_accattr = { 84c7fd2ed0Sgs150176 DDI_DEVICE_ATTR_V0, 85c7fd2ed0Sgs150176 DDI_NEVERSWAP_ACC, 86c7fd2ed0Sgs150176 DDI_STRICTORDER_ACC, 87c7fd2ed0Sgs150176 DDI_DEFAULT_ACC 88c7fd2ed0Sgs150176 }; 89c7fd2ed0Sgs150176 90c7fd2ed0Sgs150176 /* 91c7fd2ed0Sgs150176 * DMA access attributes for data 92c7fd2ed0Sgs150176 */ 93c7fd2ed0Sgs150176 static ddi_device_acc_attr_t rge_buf_accattr = { 94c7fd2ed0Sgs150176 DDI_DEVICE_ATTR_V0, 95c7fd2ed0Sgs150176 DDI_NEVERSWAP_ACC, 96c7fd2ed0Sgs150176 DDI_STRICTORDER_ACC, 97c7fd2ed0Sgs150176 DDI_DEFAULT_ACC 98c7fd2ed0Sgs150176 }; 99c7fd2ed0Sgs150176 100c7fd2ed0Sgs150176 /* 101c7fd2ed0Sgs150176 * Property names 102c7fd2ed0Sgs150176 */ 103aa817493Sgs150176 static char debug_propname[] = "rge_debug_flags"; 104aa817493Sgs150176 static char mtu_propname[] = "default_mtu"; 105aa817493Sgs150176 static char msi_propname[] = "msi_enable"; 106c7fd2ed0Sgs150176 107ba2e4443Sseb static int rge_m_start(void *); 108ba2e4443Sseb static void rge_m_stop(void *); 109ba2e4443Sseb static int rge_m_promisc(void *, boolean_t); 110ba2e4443Sseb static int rge_m_multicst(void *, boolean_t, const uint8_t *); 111ba2e4443Sseb static int rge_m_unicst(void *, const uint8_t *); 112ba2e4443Sseb static void rge_m_ioctl(void *, queue_t *, mblk_t *); 113ba2e4443Sseb static boolean_t rge_m_getcapab(void *, mac_capab_t, void *); 114ba2e4443Sseb 115da14cebeSEric Cheng #define RGE_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB) 116ba2e4443Sseb 117ba2e4443Sseb static mac_callbacks_t rge_m_callbacks = { 118ba2e4443Sseb RGE_M_CALLBACK_FLAGS, 119ba2e4443Sseb rge_m_stat, 120ba2e4443Sseb rge_m_start, 121ba2e4443Sseb rge_m_stop, 122ba2e4443Sseb rge_m_promisc, 123ba2e4443Sseb rge_m_multicst, 124ba2e4443Sseb rge_m_unicst, 125ba2e4443Sseb rge_m_tx, 126*0dc2366fSVenugopal Iyer NULL, 127ba2e4443Sseb rge_m_ioctl, 128ba2e4443Sseb rge_m_getcapab 129ba2e4443Sseb }; 130c7fd2ed0Sgs150176 131c7fd2ed0Sgs150176 /* 132c7fd2ed0Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 133c7fd2ed0Sgs150176 */ 134c7fd2ed0Sgs150176 static int 135c7fd2ed0Sgs150176 rge_alloc_dma_mem(rge_t *rgep, size_t memsize, ddi_dma_attr_t *dma_attr_p, 136c7fd2ed0Sgs150176 ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, dma_area_t *dma_p) 137c7fd2ed0Sgs150176 { 138c7fd2ed0Sgs150176 caddr_t vaddr; 139c7fd2ed0Sgs150176 int err; 140c7fd2ed0Sgs150176 141c7fd2ed0Sgs150176 /* 142c7fd2ed0Sgs150176 * Allocate handle 143c7fd2ed0Sgs150176 */ 144c7fd2ed0Sgs150176 err = ddi_dma_alloc_handle(rgep->devinfo, dma_attr_p, 145c7fd2ed0Sgs150176 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 146c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 147c7fd2ed0Sgs150176 dma_p->dma_hdl = NULL; 148c7fd2ed0Sgs150176 return (DDI_FAILURE); 149c7fd2ed0Sgs150176 } 150c7fd2ed0Sgs150176 151c7fd2ed0Sgs150176 /* 152c7fd2ed0Sgs150176 * Allocate memory 153c7fd2ed0Sgs150176 */ 154c7fd2ed0Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p, 155c7fd2ed0Sgs150176 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 156c7fd2ed0Sgs150176 DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 157c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 158c7fd2ed0Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 159c7fd2ed0Sgs150176 dma_p->dma_hdl = NULL; 160c7fd2ed0Sgs150176 dma_p->acc_hdl = NULL; 161c7fd2ed0Sgs150176 return (DDI_FAILURE); 162c7fd2ed0Sgs150176 } 163c7fd2ed0Sgs150176 164c7fd2ed0Sgs150176 /* 165c7fd2ed0Sgs150176 * Bind the two together 166c7fd2ed0Sgs150176 */ 167c7fd2ed0Sgs150176 dma_p->mem_va = vaddr; 168c7fd2ed0Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 169c7fd2ed0Sgs150176 vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 170c7fd2ed0Sgs150176 &dma_p->cookie, &dma_p->ncookies); 171c7fd2ed0Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) { 172c7fd2ed0Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 173c7fd2ed0Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 174c7fd2ed0Sgs150176 dma_p->acc_hdl = NULL; 175c7fd2ed0Sgs150176 dma_p->dma_hdl = NULL; 176c7fd2ed0Sgs150176 return (DDI_FAILURE); 177c7fd2ed0Sgs150176 } 178c7fd2ed0Sgs150176 179c7fd2ed0Sgs150176 dma_p->nslots = ~0U; 180c7fd2ed0Sgs150176 dma_p->size = ~0U; 181c7fd2ed0Sgs150176 dma_p->token = ~0U; 182c7fd2ed0Sgs150176 dma_p->offset = 0; 183c7fd2ed0Sgs150176 return (DDI_SUCCESS); 184c7fd2ed0Sgs150176 } 185c7fd2ed0Sgs150176 186c7fd2ed0Sgs150176 /* 187c7fd2ed0Sgs150176 * Free one allocated area of DMAable memory 188c7fd2ed0Sgs150176 */ 189c7fd2ed0Sgs150176 static void 190c7fd2ed0Sgs150176 rge_free_dma_mem(dma_area_t *dma_p) 191c7fd2ed0Sgs150176 { 192c7fd2ed0Sgs150176 if (dma_p->dma_hdl != NULL) { 193c7fd2ed0Sgs150176 if (dma_p->ncookies) { 194c7fd2ed0Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 195c7fd2ed0Sgs150176 dma_p->ncookies = 0; 196c7fd2ed0Sgs150176 } 197c7fd2ed0Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 198c7fd2ed0Sgs150176 dma_p->dma_hdl = NULL; 199c7fd2ed0Sgs150176 } 200c7fd2ed0Sgs150176 201c7fd2ed0Sgs150176 if (dma_p->acc_hdl != NULL) { 202c7fd2ed0Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 203c7fd2ed0Sgs150176 dma_p->acc_hdl = NULL; 204c7fd2ed0Sgs150176 } 205c7fd2ed0Sgs150176 } 206c7fd2ed0Sgs150176 207c7fd2ed0Sgs150176 /* 208c7fd2ed0Sgs150176 * Utility routine to carve a slice off a chunk of allocated memory, 209c7fd2ed0Sgs150176 * updating the chunk descriptor accordingly. The size of the slice 210c7fd2ed0Sgs150176 * is given by the product of the <qty> and <size> parameters. 211c7fd2ed0Sgs150176 */ 212c7fd2ed0Sgs150176 static void 213c7fd2ed0Sgs150176 rge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 214c7fd2ed0Sgs150176 uint32_t qty, uint32_t size) 215c7fd2ed0Sgs150176 { 216c7fd2ed0Sgs150176 static uint32_t sequence = 0xbcd5704a; 217c7fd2ed0Sgs150176 size_t totsize; 218c7fd2ed0Sgs150176 219c7fd2ed0Sgs150176 totsize = qty*size; 220c7fd2ed0Sgs150176 ASSERT(totsize <= chunk->alength); 221c7fd2ed0Sgs150176 222c7fd2ed0Sgs150176 *slice = *chunk; 223c7fd2ed0Sgs150176 slice->nslots = qty; 224c7fd2ed0Sgs150176 slice->size = size; 225c7fd2ed0Sgs150176 slice->alength = totsize; 226c7fd2ed0Sgs150176 slice->token = ++sequence; 227c7fd2ed0Sgs150176 228c7fd2ed0Sgs150176 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 229c7fd2ed0Sgs150176 chunk->alength -= totsize; 230c7fd2ed0Sgs150176 chunk->offset += totsize; 231c7fd2ed0Sgs150176 chunk->cookie.dmac_laddress += totsize; 232c7fd2ed0Sgs150176 chunk->cookie.dmac_size -= totsize; 233c7fd2ed0Sgs150176 } 234c7fd2ed0Sgs150176 235c7fd2ed0Sgs150176 static int 236c7fd2ed0Sgs150176 rge_alloc_bufs(rge_t *rgep) 237c7fd2ed0Sgs150176 { 238c7fd2ed0Sgs150176 size_t txdescsize; 239c7fd2ed0Sgs150176 size_t rxdescsize; 240c7fd2ed0Sgs150176 int err; 241c7fd2ed0Sgs150176 242c7fd2ed0Sgs150176 /* 243c7fd2ed0Sgs150176 * Allocate memory & handle for packet statistics 244c7fd2ed0Sgs150176 */ 245c7fd2ed0Sgs150176 err = rge_alloc_dma_mem(rgep, 246c7fd2ed0Sgs150176 RGE_STATS_DUMP_SIZE, 247c7fd2ed0Sgs150176 &dma_attr_desc, 248c7fd2ed0Sgs150176 &rge_desc_accattr, 249c7fd2ed0Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 250c7fd2ed0Sgs150176 &rgep->dma_area_stats); 251c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) 252c7fd2ed0Sgs150176 return (DDI_FAILURE); 253c7fd2ed0Sgs150176 rgep->hw_stats = DMA_VPTR(rgep->dma_area_stats); 254c7fd2ed0Sgs150176 255c7fd2ed0Sgs150176 /* 256c7fd2ed0Sgs150176 * Allocate memory & handle for Tx descriptor ring 257c7fd2ed0Sgs150176 */ 258c7fd2ed0Sgs150176 txdescsize = RGE_SEND_SLOTS * sizeof (rge_bd_t); 259c7fd2ed0Sgs150176 err = rge_alloc_dma_mem(rgep, 260c7fd2ed0Sgs150176 txdescsize, 261c7fd2ed0Sgs150176 &dma_attr_desc, 262c7fd2ed0Sgs150176 &rge_desc_accattr, 263c7fd2ed0Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 264c7fd2ed0Sgs150176 &rgep->dma_area_txdesc); 265c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) 266c7fd2ed0Sgs150176 return (DDI_FAILURE); 267c7fd2ed0Sgs150176 268c7fd2ed0Sgs150176 /* 269c7fd2ed0Sgs150176 * Allocate memory & handle for Rx descriptor ring 270c7fd2ed0Sgs150176 */ 271c7fd2ed0Sgs150176 rxdescsize = RGE_RECV_SLOTS * sizeof (rge_bd_t); 272c7fd2ed0Sgs150176 err = rge_alloc_dma_mem(rgep, 273c7fd2ed0Sgs150176 rxdescsize, 274c7fd2ed0Sgs150176 &dma_attr_desc, 275c7fd2ed0Sgs150176 &rge_desc_accattr, 276c7fd2ed0Sgs150176 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 277c7fd2ed0Sgs150176 &rgep->dma_area_rxdesc); 278c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) 279c7fd2ed0Sgs150176 return (DDI_FAILURE); 280c7fd2ed0Sgs150176 281c7fd2ed0Sgs150176 return (DDI_SUCCESS); 282c7fd2ed0Sgs150176 } 283c7fd2ed0Sgs150176 284c7fd2ed0Sgs150176 /* 285c7fd2ed0Sgs150176 * rge_free_bufs() -- free descriptors/buffers allocated for this 286c7fd2ed0Sgs150176 * device instance. 287c7fd2ed0Sgs150176 */ 288c7fd2ed0Sgs150176 static void 289c7fd2ed0Sgs150176 rge_free_bufs(rge_t *rgep) 290c7fd2ed0Sgs150176 { 291c7fd2ed0Sgs150176 rge_free_dma_mem(&rgep->dma_area_stats); 292c7fd2ed0Sgs150176 rge_free_dma_mem(&rgep->dma_area_txdesc); 293c7fd2ed0Sgs150176 rge_free_dma_mem(&rgep->dma_area_rxdesc); 294c7fd2ed0Sgs150176 } 295c7fd2ed0Sgs150176 296c7fd2ed0Sgs150176 /* 297c7fd2ed0Sgs150176 * ========== Transmit and receive ring reinitialisation ========== 298c7fd2ed0Sgs150176 */ 299c7fd2ed0Sgs150176 300c7fd2ed0Sgs150176 /* 301c7fd2ed0Sgs150176 * These <reinit> routines each reset the rx/tx rings to an initial 302c7fd2ed0Sgs150176 * state, assuming that the corresponding <init> routine has already 303c7fd2ed0Sgs150176 * been called exactly once. 304c7fd2ed0Sgs150176 */ 305c7fd2ed0Sgs150176 static void 306c7fd2ed0Sgs150176 rge_reinit_send_ring(rge_t *rgep) 307c7fd2ed0Sgs150176 { 308c7fd2ed0Sgs150176 sw_sbd_t *ssbdp; 309c7fd2ed0Sgs150176 rge_bd_t *bdp; 310c7fd2ed0Sgs150176 uint32_t slot; 311c7fd2ed0Sgs150176 312c7fd2ed0Sgs150176 /* 313c7fd2ed0Sgs150176 * re-init send ring 314c7fd2ed0Sgs150176 */ 315c7fd2ed0Sgs150176 DMA_ZERO(rgep->tx_desc); 316c7fd2ed0Sgs150176 ssbdp = rgep->sw_sbds; 317c7fd2ed0Sgs150176 bdp = rgep->tx_ring; 318c7fd2ed0Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; slot++) { 319c7fd2ed0Sgs150176 bdp->host_buf_addr = 320c7fd2ed0Sgs150176 RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress); 321c7fd2ed0Sgs150176 bdp->host_buf_addr_hi = 322c7fd2ed0Sgs150176 RGE_BSWAP_32(ssbdp->pbuf.cookie.dmac_laddress >> 32); 323c7fd2ed0Sgs150176 /* last BD in Tx ring */ 324c7fd2ed0Sgs150176 if (slot == (RGE_SEND_SLOTS - 1)) 325c7fd2ed0Sgs150176 bdp->flags_len = RGE_BSWAP_32(BD_FLAG_EOR); 326c7fd2ed0Sgs150176 ssbdp++; 327c7fd2ed0Sgs150176 bdp++; 328c7fd2ed0Sgs150176 } 329c7fd2ed0Sgs150176 DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV); 330c7fd2ed0Sgs150176 rgep->tx_next = 0; 331c7fd2ed0Sgs150176 rgep->tc_next = 0; 332c7fd2ed0Sgs150176 rgep->tc_tail = 0; 333c7fd2ed0Sgs150176 rgep->tx_flow = 0; 334c7fd2ed0Sgs150176 rgep->tx_free = RGE_SEND_SLOTS; 335c7fd2ed0Sgs150176 } 336c7fd2ed0Sgs150176 337c7fd2ed0Sgs150176 static void 338c7fd2ed0Sgs150176 rge_reinit_recv_ring(rge_t *rgep) 339c7fd2ed0Sgs150176 { 340c7fd2ed0Sgs150176 rge_bd_t *bdp; 341c7fd2ed0Sgs150176 sw_rbd_t *srbdp; 342c7fd2ed0Sgs150176 dma_area_t *pbuf; 343c7fd2ed0Sgs150176 uint32_t slot; 344c7fd2ed0Sgs150176 345c7fd2ed0Sgs150176 /* 346c7fd2ed0Sgs150176 * re-init receive ring 347c7fd2ed0Sgs150176 */ 348c7fd2ed0Sgs150176 DMA_ZERO(rgep->rx_desc); 349c7fd2ed0Sgs150176 srbdp = rgep->sw_rbds; 350c7fd2ed0Sgs150176 bdp = rgep->rx_ring; 351c7fd2ed0Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; slot++) { 352c7fd2ed0Sgs150176 pbuf = &srbdp->rx_buf->pbuf; 353c7fd2ed0Sgs150176 bdp->host_buf_addr = 354aa817493Sgs150176 RGE_BSWAP_32(pbuf->cookie.dmac_laddress + rgep->head_room); 355c7fd2ed0Sgs150176 bdp->host_buf_addr_hi = 356c7fd2ed0Sgs150176 RGE_BSWAP_32(pbuf->cookie.dmac_laddress >> 32); 357c7fd2ed0Sgs150176 bdp->flags_len = RGE_BSWAP_32(BD_FLAG_HW_OWN | 358aa817493Sgs150176 (rgep->rxbuf_size - rgep->head_room)); 359c7fd2ed0Sgs150176 /* last BD in Tx ring */ 360c7fd2ed0Sgs150176 if (slot == (RGE_RECV_SLOTS - 1)) 361c7fd2ed0Sgs150176 bdp->flags_len |= RGE_BSWAP_32(BD_FLAG_EOR); 362c7fd2ed0Sgs150176 srbdp++; 363c7fd2ed0Sgs150176 bdp++; 364c7fd2ed0Sgs150176 } 365c7fd2ed0Sgs150176 DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV); 366c7fd2ed0Sgs150176 rgep->watchdog = 0; 367c7fd2ed0Sgs150176 rgep->rx_next = 0; 368c7fd2ed0Sgs150176 } 369c7fd2ed0Sgs150176 370c7fd2ed0Sgs150176 static void 371c7fd2ed0Sgs150176 rge_reinit_buf_ring(rge_t *rgep) 372c7fd2ed0Sgs150176 { 373aa817493Sgs150176 374aa817493Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) 375aa817493Sgs150176 return; 376aa817493Sgs150176 377c7fd2ed0Sgs150176 /* 378aa817493Sgs150176 * If all the up-sending buffers haven't been returned to driver, 379aa817493Sgs150176 * use bcopy() only in rx process. 380c7fd2ed0Sgs150176 */ 381c7fd2ed0Sgs150176 if (rgep->rx_free != RGE_BUF_SLOTS) 382c7fd2ed0Sgs150176 rgep->rx_bcopy = B_TRUE; 383c7fd2ed0Sgs150176 } 384c7fd2ed0Sgs150176 385c7fd2ed0Sgs150176 static void 386c7fd2ed0Sgs150176 rge_reinit_rings(rge_t *rgep) 387c7fd2ed0Sgs150176 { 388c7fd2ed0Sgs150176 rge_reinit_send_ring(rgep); 389c7fd2ed0Sgs150176 rge_reinit_recv_ring(rgep); 390c7fd2ed0Sgs150176 rge_reinit_buf_ring(rgep); 391c7fd2ed0Sgs150176 } 392c7fd2ed0Sgs150176 393c7fd2ed0Sgs150176 static void 394aa817493Sgs150176 rge_fini_send_ring(rge_t *rgep) 395aa817493Sgs150176 { 396aa817493Sgs150176 sw_sbd_t *ssbdp; 397aa817493Sgs150176 uint32_t slot; 398aa817493Sgs150176 399aa817493Sgs150176 ssbdp = rgep->sw_sbds; 400aa817493Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; ++slot) { 401aa817493Sgs150176 rge_free_dma_mem(&ssbdp->pbuf); 402aa817493Sgs150176 ssbdp++; 403aa817493Sgs150176 } 404aa817493Sgs150176 405aa817493Sgs150176 kmem_free(rgep->sw_sbds, RGE_SEND_SLOTS * sizeof (sw_sbd_t)); 406aa817493Sgs150176 rgep->sw_sbds = NULL; 407aa817493Sgs150176 } 408aa817493Sgs150176 409aa817493Sgs150176 static void 410aa817493Sgs150176 rge_fini_recv_ring(rge_t *rgep) 411aa817493Sgs150176 { 412aa817493Sgs150176 sw_rbd_t *srbdp; 413aa817493Sgs150176 uint32_t slot; 414aa817493Sgs150176 415aa817493Sgs150176 srbdp = rgep->sw_rbds; 416aa817493Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; ++srbdp, ++slot) { 417aa817493Sgs150176 if (srbdp->rx_buf) { 418aa817493Sgs150176 if (srbdp->rx_buf->mp != NULL) { 419aa817493Sgs150176 freemsg(srbdp->rx_buf->mp); 420aa817493Sgs150176 srbdp->rx_buf->mp = NULL; 421aa817493Sgs150176 } 422aa817493Sgs150176 rge_free_dma_mem(&srbdp->rx_buf->pbuf); 423aa817493Sgs150176 kmem_free(srbdp->rx_buf, sizeof (dma_buf_t)); 424aa817493Sgs150176 srbdp->rx_buf = NULL; 425aa817493Sgs150176 } 426aa817493Sgs150176 } 427aa817493Sgs150176 428aa817493Sgs150176 kmem_free(rgep->sw_rbds, RGE_RECV_SLOTS * sizeof (sw_rbd_t)); 429aa817493Sgs150176 rgep->sw_rbds = NULL; 430aa817493Sgs150176 } 431aa817493Sgs150176 432aa817493Sgs150176 static void 433aa817493Sgs150176 rge_fini_buf_ring(rge_t *rgep) 434aa817493Sgs150176 { 435aa817493Sgs150176 sw_rbd_t *srbdp; 436aa817493Sgs150176 uint32_t slot; 437aa817493Sgs150176 438aa817493Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) 439aa817493Sgs150176 return; 440aa817493Sgs150176 441aa817493Sgs150176 ASSERT(rgep->rx_free == RGE_BUF_SLOTS); 442aa817493Sgs150176 443aa817493Sgs150176 srbdp = rgep->free_srbds; 444aa817493Sgs150176 for (slot = 0; slot < RGE_BUF_SLOTS; ++srbdp, ++slot) { 445aa817493Sgs150176 if (srbdp->rx_buf != NULL) { 446aa817493Sgs150176 if (srbdp->rx_buf->mp != NULL) { 447aa817493Sgs150176 freemsg(srbdp->rx_buf->mp); 448aa817493Sgs150176 srbdp->rx_buf->mp = NULL; 449aa817493Sgs150176 } 450aa817493Sgs150176 rge_free_dma_mem(&srbdp->rx_buf->pbuf); 451aa817493Sgs150176 kmem_free(srbdp->rx_buf, sizeof (dma_buf_t)); 452aa817493Sgs150176 srbdp->rx_buf = NULL; 453aa817493Sgs150176 } 454aa817493Sgs150176 } 455aa817493Sgs150176 456aa817493Sgs150176 kmem_free(rgep->free_srbds, RGE_BUF_SLOTS * sizeof (sw_rbd_t)); 457aa817493Sgs150176 rgep->free_srbds = NULL; 458aa817493Sgs150176 } 459aa817493Sgs150176 460aa817493Sgs150176 static void 461aa817493Sgs150176 rge_fini_rings(rge_t *rgep) 462aa817493Sgs150176 { 463aa817493Sgs150176 rge_fini_send_ring(rgep); 464aa817493Sgs150176 rge_fini_recv_ring(rgep); 465aa817493Sgs150176 rge_fini_buf_ring(rgep); 466aa817493Sgs150176 } 467aa817493Sgs150176 468aa817493Sgs150176 static int 469c7fd2ed0Sgs150176 rge_init_send_ring(rge_t *rgep) 470c7fd2ed0Sgs150176 { 471c7fd2ed0Sgs150176 uint32_t slot; 472c7fd2ed0Sgs150176 sw_sbd_t *ssbdp; 473c7fd2ed0Sgs150176 dma_area_t *pbuf; 474aa817493Sgs150176 dma_area_t desc; 475aa817493Sgs150176 int err; 476c7fd2ed0Sgs150176 477c7fd2ed0Sgs150176 /* 478c7fd2ed0Sgs150176 * Allocate the array of s/w Tx Buffer Descriptors 479c7fd2ed0Sgs150176 */ 480c7fd2ed0Sgs150176 ssbdp = kmem_zalloc(RGE_SEND_SLOTS*sizeof (*ssbdp), KM_SLEEP); 481c7fd2ed0Sgs150176 rgep->sw_sbds = ssbdp; 482c7fd2ed0Sgs150176 483c7fd2ed0Sgs150176 /* 484c7fd2ed0Sgs150176 * Init send ring 485c7fd2ed0Sgs150176 */ 486c7fd2ed0Sgs150176 rgep->tx_desc = rgep->dma_area_txdesc; 487c7fd2ed0Sgs150176 DMA_ZERO(rgep->tx_desc); 488aa817493Sgs150176 rgep->tx_ring = rgep->tx_desc.mem_va; 489aa817493Sgs150176 490aa817493Sgs150176 desc = rgep->tx_desc; 491aa817493Sgs150176 for (slot = 0; slot < RGE_SEND_SLOTS; slot++) { 492aa817493Sgs150176 rge_slice_chunk(&ssbdp->desc, &desc, 1, sizeof (rge_bd_t)); 493aa817493Sgs150176 494aa817493Sgs150176 /* 495aa817493Sgs150176 * Allocate memory & handle for Tx buffers 496aa817493Sgs150176 */ 497c7fd2ed0Sgs150176 pbuf = &ssbdp->pbuf; 498aa817493Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->txbuf_size, 499aa817493Sgs150176 &dma_attr_buf, &rge_buf_accattr, 500aa817493Sgs150176 DDI_DMA_WRITE | DDI_DMA_STREAMING, pbuf); 501aa817493Sgs150176 if (err != DDI_SUCCESS) { 502aa817493Sgs150176 rge_error(rgep, 503aa817493Sgs150176 "rge_init_send_ring: alloc tx buffer failed"); 504aa817493Sgs150176 rge_fini_send_ring(rgep); 505aa817493Sgs150176 return (DDI_FAILURE); 506aa817493Sgs150176 } 507c7fd2ed0Sgs150176 ssbdp++; 508c7fd2ed0Sgs150176 } 509aa817493Sgs150176 ASSERT(desc.alength == 0); 510aa817493Sgs150176 511c7fd2ed0Sgs150176 DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV); 512aa817493Sgs150176 return (DDI_SUCCESS); 513c7fd2ed0Sgs150176 } 514c7fd2ed0Sgs150176 515c7fd2ed0Sgs150176 static int 516c7fd2ed0Sgs150176 rge_init_recv_ring(rge_t *rgep) 517c7fd2ed0Sgs150176 { 518c7fd2ed0Sgs150176 uint32_t slot; 519c7fd2ed0Sgs150176 sw_rbd_t *srbdp; 520c7fd2ed0Sgs150176 dma_buf_t *rx_buf; 521c7fd2ed0Sgs150176 dma_area_t *pbuf; 522aa817493Sgs150176 int err; 523c7fd2ed0Sgs150176 524c7fd2ed0Sgs150176 /* 525c7fd2ed0Sgs150176 * Allocate the array of s/w Rx Buffer Descriptors 526c7fd2ed0Sgs150176 */ 527c7fd2ed0Sgs150176 srbdp = kmem_zalloc(RGE_RECV_SLOTS*sizeof (*srbdp), KM_SLEEP); 528c7fd2ed0Sgs150176 rgep->sw_rbds = srbdp; 529c7fd2ed0Sgs150176 530c7fd2ed0Sgs150176 /* 531c7fd2ed0Sgs150176 * Init receive ring 532c7fd2ed0Sgs150176 */ 533c7fd2ed0Sgs150176 rgep->rx_next = 0; 534c7fd2ed0Sgs150176 rgep->rx_desc = rgep->dma_area_rxdesc; 535c7fd2ed0Sgs150176 DMA_ZERO(rgep->rx_desc); 536aa817493Sgs150176 rgep->rx_ring = rgep->rx_desc.mem_va; 537aa817493Sgs150176 538aa817493Sgs150176 for (slot = 0; slot < RGE_RECV_SLOTS; slot++) { 539aa817493Sgs150176 srbdp->rx_buf = rx_buf = 540aa817493Sgs150176 kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP); 541aa817493Sgs150176 542aa817493Sgs150176 /* 543aa817493Sgs150176 * Allocate memory & handle for Rx buffers 544aa817493Sgs150176 */ 545c7fd2ed0Sgs150176 pbuf = &rx_buf->pbuf; 546aa817493Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size, 547aa817493Sgs150176 &dma_attr_buf, &rge_buf_accattr, 548aa817493Sgs150176 DDI_DMA_READ | DDI_DMA_STREAMING, pbuf); 549aa817493Sgs150176 if (err != DDI_SUCCESS) { 550aa817493Sgs150176 rge_fini_recv_ring(rgep); 551aa817493Sgs150176 rge_error(rgep, 552aa817493Sgs150176 "rge_init_recv_ring: alloc rx buffer failed"); 553aa817493Sgs150176 return (DDI_FAILURE); 554aa817493Sgs150176 } 555aa817493Sgs150176 556aa817493Sgs150176 pbuf->alength -= rgep->head_room; 557aa817493Sgs150176 pbuf->offset += rgep->head_room; 558aa817493Sgs150176 if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)) { 559c7fd2ed0Sgs150176 rx_buf->rx_recycle.free_func = rge_rx_recycle; 560c7fd2ed0Sgs150176 rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf; 561c7fd2ed0Sgs150176 rx_buf->private = (caddr_t)rgep; 562c7fd2ed0Sgs150176 rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf), 563c7fd2ed0Sgs150176 rgep->rxbuf_size, 0, &rx_buf->rx_recycle); 564c7fd2ed0Sgs150176 if (rx_buf->mp == NULL) { 565aa817493Sgs150176 rge_fini_recv_ring(rgep); 566c7fd2ed0Sgs150176 rge_problem(rgep, 567c7fd2ed0Sgs150176 "rge_init_recv_ring: desballoc() failed"); 568c7fd2ed0Sgs150176 return (DDI_FAILURE); 569c7fd2ed0Sgs150176 } 570c7fd2ed0Sgs150176 } 571aa817493Sgs150176 srbdp++; 572c7fd2ed0Sgs150176 } 573c7fd2ed0Sgs150176 DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORDEV); 574c7fd2ed0Sgs150176 return (DDI_SUCCESS); 575c7fd2ed0Sgs150176 } 576c7fd2ed0Sgs150176 577c7fd2ed0Sgs150176 static int 578c7fd2ed0Sgs150176 rge_init_buf_ring(rge_t *rgep) 579c7fd2ed0Sgs150176 { 580c7fd2ed0Sgs150176 uint32_t slot; 581aa817493Sgs150176 sw_rbd_t *free_srbdp; 582c7fd2ed0Sgs150176 dma_buf_t *rx_buf; 583c7fd2ed0Sgs150176 dma_area_t *pbuf; 584aa817493Sgs150176 int err; 585aa817493Sgs150176 586aa817493Sgs150176 if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) { 587aa817493Sgs150176 rgep->rx_bcopy = B_TRUE; 588aa817493Sgs150176 return (DDI_SUCCESS); 589aa817493Sgs150176 } 590c7fd2ed0Sgs150176 591c7fd2ed0Sgs150176 /* 592c7fd2ed0Sgs150176 * Allocate the array of s/w free Buffer Descriptors 593c7fd2ed0Sgs150176 */ 594aa817493Sgs150176 free_srbdp = kmem_zalloc(RGE_BUF_SLOTS*sizeof (*free_srbdp), KM_SLEEP); 595aa817493Sgs150176 rgep->free_srbds = free_srbdp; 596c7fd2ed0Sgs150176 597c7fd2ed0Sgs150176 /* 598c7fd2ed0Sgs150176 * Init free buffer ring 599c7fd2ed0Sgs150176 */ 600c7fd2ed0Sgs150176 rgep->rc_next = 0; 601c7fd2ed0Sgs150176 rgep->rf_next = 0; 602c7fd2ed0Sgs150176 rgep->rx_bcopy = B_FALSE; 603c7fd2ed0Sgs150176 rgep->rx_free = RGE_BUF_SLOTS; 604aa817493Sgs150176 for (slot = 0; slot < RGE_BUF_SLOTS; slot++) { 605aa817493Sgs150176 free_srbdp->rx_buf = rx_buf = 606aa817493Sgs150176 kmem_zalloc(sizeof (dma_buf_t), KM_SLEEP); 607aa817493Sgs150176 608aa817493Sgs150176 /* 609aa817493Sgs150176 * Allocate memory & handle for free Rx buffers 610aa817493Sgs150176 */ 611c7fd2ed0Sgs150176 pbuf = &rx_buf->pbuf; 612aa817493Sgs150176 err = rge_alloc_dma_mem(rgep, rgep->rxbuf_size, 613aa817493Sgs150176 &dma_attr_buf, &rge_buf_accattr, 614aa817493Sgs150176 DDI_DMA_READ | DDI_DMA_STREAMING, pbuf); 615aa817493Sgs150176 if (err != DDI_SUCCESS) { 616aa817493Sgs150176 rge_fini_buf_ring(rgep); 617aa817493Sgs150176 rge_error(rgep, 618aa817493Sgs150176 "rge_init_buf_ring: alloc rx free buffer failed"); 619aa817493Sgs150176 return (DDI_FAILURE); 620aa817493Sgs150176 } 621aa817493Sgs150176 pbuf->alength -= rgep->head_room; 622aa817493Sgs150176 pbuf->offset += rgep->head_room; 623c7fd2ed0Sgs150176 rx_buf->rx_recycle.free_func = rge_rx_recycle; 624c7fd2ed0Sgs150176 rx_buf->rx_recycle.free_arg = (caddr_t)rx_buf; 625c7fd2ed0Sgs150176 rx_buf->private = (caddr_t)rgep; 626c7fd2ed0Sgs150176 rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf), 627c7fd2ed0Sgs150176 rgep->rxbuf_size, 0, &rx_buf->rx_recycle); 628c7fd2ed0Sgs150176 if (rx_buf->mp == NULL) { 629aa817493Sgs150176 rge_fini_buf_ring(rgep); 630c7fd2ed0Sgs150176 rge_problem(rgep, 631c7fd2ed0Sgs150176 "rge_init_buf_ring: desballoc() failed"); 632c7fd2ed0Sgs150176 return (DDI_FAILURE); 633c7fd2ed0Sgs150176 } 634aa817493Sgs150176 free_srbdp++; 635c7fd2ed0Sgs150176 } 636c7fd2ed0Sgs150176 return (DDI_SUCCESS); 637c7fd2ed0Sgs150176 } 638c7fd2ed0Sgs150176 639c7fd2ed0Sgs150176 static int 640c7fd2ed0Sgs150176 rge_init_rings(rge_t *rgep) 641c7fd2ed0Sgs150176 { 642c7fd2ed0Sgs150176 int err; 643c7fd2ed0Sgs150176 644aa817493Sgs150176 err = rge_init_send_ring(rgep); 645aa817493Sgs150176 if (err != DDI_SUCCESS) 646aa817493Sgs150176 return (DDI_FAILURE); 647aa817493Sgs150176 648c7fd2ed0Sgs150176 err = rge_init_recv_ring(rgep); 649aa817493Sgs150176 if (err != DDI_SUCCESS) { 650aa817493Sgs150176 rge_fini_send_ring(rgep); 651aa817493Sgs150176 return (DDI_FAILURE); 652aa817493Sgs150176 } 653aa817493Sgs150176 654c7fd2ed0Sgs150176 err = rge_init_buf_ring(rgep); 655aa817493Sgs150176 if (err != DDI_SUCCESS) { 656c7fd2ed0Sgs150176 rge_fini_send_ring(rgep); 657c7fd2ed0Sgs150176 rge_fini_recv_ring(rgep); 658aa817493Sgs150176 return (DDI_FAILURE); 659aa817493Sgs150176 } 660aa817493Sgs150176 661aa817493Sgs150176 return (DDI_SUCCESS); 662c7fd2ed0Sgs150176 } 663c7fd2ed0Sgs150176 664c7fd2ed0Sgs150176 /* 665c7fd2ed0Sgs150176 * ========== Internal state management entry points ========== 666c7fd2ed0Sgs150176 */ 667c7fd2ed0Sgs150176 668c7fd2ed0Sgs150176 #undef RGE_DBG 669c7fd2ed0Sgs150176 #define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */ 670c7fd2ed0Sgs150176 671c7fd2ed0Sgs150176 /* 672c7fd2ed0Sgs150176 * These routines provide all the functionality required by the 673c7fd2ed0Sgs150176 * corresponding MAC layer entry points, but don't update the 674c7fd2ed0Sgs150176 * MAC state so they can be called internally without disturbing 675c7fd2ed0Sgs150176 * our record of what NEMO thinks we should be doing ... 676c7fd2ed0Sgs150176 */ 677c7fd2ed0Sgs150176 678c7fd2ed0Sgs150176 /* 679c7fd2ed0Sgs150176 * rge_reset() -- reset h/w & rings to initial state 680c7fd2ed0Sgs150176 */ 681c7fd2ed0Sgs150176 static void 682c7fd2ed0Sgs150176 rge_reset(rge_t *rgep) 683c7fd2ed0Sgs150176 { 684c7fd2ed0Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 685c7fd2ed0Sgs150176 686c7fd2ed0Sgs150176 /* 687c7fd2ed0Sgs150176 * Grab all the other mutexes in the world (this should 688c7fd2ed0Sgs150176 * ensure no other threads are manipulating driver state) 689c7fd2ed0Sgs150176 */ 690c7fd2ed0Sgs150176 mutex_enter(rgep->rx_lock); 691c7fd2ed0Sgs150176 mutex_enter(rgep->rc_lock); 692c7fd2ed0Sgs150176 rw_enter(rgep->errlock, RW_WRITER); 693c7fd2ed0Sgs150176 694c7fd2ed0Sgs150176 (void) rge_chip_reset(rgep); 695c7fd2ed0Sgs150176 rge_reinit_rings(rgep); 696c7fd2ed0Sgs150176 rge_chip_init(rgep); 697c7fd2ed0Sgs150176 698c7fd2ed0Sgs150176 /* 699c7fd2ed0Sgs150176 * Free the world ... 700c7fd2ed0Sgs150176 */ 701c7fd2ed0Sgs150176 rw_exit(rgep->errlock); 702c7fd2ed0Sgs150176 mutex_exit(rgep->rc_lock); 703c7fd2ed0Sgs150176 mutex_exit(rgep->rx_lock); 704c7fd2ed0Sgs150176 70522dc2133Smx205022 rgep->stats.rpackets = 0; 70622dc2133Smx205022 rgep->stats.rbytes = 0; 70722dc2133Smx205022 rgep->stats.opackets = 0; 70822dc2133Smx205022 rgep->stats.obytes = 0; 70922dc2133Smx205022 rgep->stats.tx_pre_ismax = B_FALSE; 71022dc2133Smx205022 rgep->stats.tx_cur_ismax = B_FALSE; 71122dc2133Smx205022 712c7fd2ed0Sgs150176 RGE_DEBUG(("rge_reset($%p) done", (void *)rgep)); 713c7fd2ed0Sgs150176 } 714c7fd2ed0Sgs150176 715c7fd2ed0Sgs150176 /* 716c7fd2ed0Sgs150176 * rge_stop() -- stop processing, don't reset h/w or rings 717c7fd2ed0Sgs150176 */ 718c7fd2ed0Sgs150176 static void 719c7fd2ed0Sgs150176 rge_stop(rge_t *rgep) 720c7fd2ed0Sgs150176 { 721c7fd2ed0Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 722c7fd2ed0Sgs150176 723c7fd2ed0Sgs150176 rge_chip_stop(rgep, B_FALSE); 724c7fd2ed0Sgs150176 725c7fd2ed0Sgs150176 RGE_DEBUG(("rge_stop($%p) done", (void *)rgep)); 726c7fd2ed0Sgs150176 } 727c7fd2ed0Sgs150176 728c7fd2ed0Sgs150176 /* 729c7fd2ed0Sgs150176 * rge_start() -- start transmitting/receiving 730c7fd2ed0Sgs150176 */ 731c7fd2ed0Sgs150176 static void 732c7fd2ed0Sgs150176 rge_start(rge_t *rgep) 733c7fd2ed0Sgs150176 { 734c7fd2ed0Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 735c7fd2ed0Sgs150176 736c7fd2ed0Sgs150176 /* 737c7fd2ed0Sgs150176 * Start chip processing, including enabling interrupts 738c7fd2ed0Sgs150176 */ 739c7fd2ed0Sgs150176 rge_chip_start(rgep); 740c7fd2ed0Sgs150176 rgep->watchdog = 0; 741c7fd2ed0Sgs150176 } 742c7fd2ed0Sgs150176 743c7fd2ed0Sgs150176 /* 744c7fd2ed0Sgs150176 * rge_restart - restart transmitting/receiving after error or suspend 745c7fd2ed0Sgs150176 */ 746c7fd2ed0Sgs150176 void 747c7fd2ed0Sgs150176 rge_restart(rge_t *rgep) 748c7fd2ed0Sgs150176 { 749c7fd2ed0Sgs150176 uint32_t i; 750c7fd2ed0Sgs150176 751c7fd2ed0Sgs150176 ASSERT(mutex_owned(rgep->genlock)); 752c7fd2ed0Sgs150176 /* 753c7fd2ed0Sgs150176 * Wait for posted buffer to be freed... 754c7fd2ed0Sgs150176 */ 755c7fd2ed0Sgs150176 if (!rgep->rx_bcopy) { 756c7fd2ed0Sgs150176 for (i = 0; i < RXBUFF_FREE_LOOP; i++) { 757c7fd2ed0Sgs150176 if (rgep->rx_free == RGE_BUF_SLOTS) 758c7fd2ed0Sgs150176 break; 759c7fd2ed0Sgs150176 drv_usecwait(1000); 760c7fd2ed0Sgs150176 RGE_DEBUG(("rge_restart: waiting for rx buf free...")); 761c7fd2ed0Sgs150176 } 762c7fd2ed0Sgs150176 } 763c7fd2ed0Sgs150176 rge_reset(rgep); 764c7fd2ed0Sgs150176 rgep->stats.chip_reset++; 765c7fd2ed0Sgs150176 if (rgep->rge_mac_state == RGE_MAC_STARTED) { 766c7fd2ed0Sgs150176 rge_start(rgep); 767aa817493Sgs150176 rgep->resched_needed = B_TRUE; 768aa817493Sgs150176 (void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL); 769c7fd2ed0Sgs150176 } 770c7fd2ed0Sgs150176 } 771c7fd2ed0Sgs150176 772c7fd2ed0Sgs150176 773c7fd2ed0Sgs150176 /* 774c7fd2ed0Sgs150176 * ========== Nemo-required management entry points ========== 775c7fd2ed0Sgs150176 */ 776c7fd2ed0Sgs150176 777c7fd2ed0Sgs150176 #undef RGE_DBG 778c7fd2ed0Sgs150176 #define RGE_DBG RGE_DBG_NEMO /* debug flag for this code */ 779c7fd2ed0Sgs150176 780c7fd2ed0Sgs150176 /* 781c7fd2ed0Sgs150176 * rge_m_stop() -- stop transmitting/receiving 782c7fd2ed0Sgs150176 */ 783c7fd2ed0Sgs150176 static void 784c7fd2ed0Sgs150176 rge_m_stop(void *arg) 785c7fd2ed0Sgs150176 { 786c7fd2ed0Sgs150176 rge_t *rgep = arg; /* private device info */ 787c7fd2ed0Sgs150176 uint32_t i; 788c7fd2ed0Sgs150176 789c7fd2ed0Sgs150176 /* 790c7fd2ed0Sgs150176 * Just stop processing, then record new MAC state 791c7fd2ed0Sgs150176 */ 792c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 793343c2616Smx205022 if (rgep->suspended) { 794343c2616Smx205022 ASSERT(rgep->rge_mac_state == RGE_MAC_STOPPED); 795343c2616Smx205022 mutex_exit(rgep->genlock); 796343c2616Smx205022 return; 797343c2616Smx205022 } 798c7fd2ed0Sgs150176 rge_stop(rgep); 799c7fd2ed0Sgs150176 /* 800c7fd2ed0Sgs150176 * Wait for posted buffer to be freed... 801c7fd2ed0Sgs150176 */ 802c7fd2ed0Sgs150176 if (!rgep->rx_bcopy) { 803c7fd2ed0Sgs150176 for (i = 0; i < RXBUFF_FREE_LOOP; i++) { 804c7fd2ed0Sgs150176 if (rgep->rx_free == RGE_BUF_SLOTS) 805c7fd2ed0Sgs150176 break; 806c7fd2ed0Sgs150176 drv_usecwait(1000); 807c7fd2ed0Sgs150176 RGE_DEBUG(("rge_m_stop: waiting for rx buf free...")); 808c7fd2ed0Sgs150176 } 809c7fd2ed0Sgs150176 } 810c7fd2ed0Sgs150176 rgep->rge_mac_state = RGE_MAC_STOPPED; 811c7fd2ed0Sgs150176 RGE_DEBUG(("rge_m_stop($%p) done", arg)); 812c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 813c7fd2ed0Sgs150176 } 814c7fd2ed0Sgs150176 815c7fd2ed0Sgs150176 /* 816c7fd2ed0Sgs150176 * rge_m_start() -- start transmitting/receiving 817c7fd2ed0Sgs150176 */ 818c7fd2ed0Sgs150176 static int 819c7fd2ed0Sgs150176 rge_m_start(void *arg) 820c7fd2ed0Sgs150176 { 821c7fd2ed0Sgs150176 rge_t *rgep = arg; /* private device info */ 822c7fd2ed0Sgs150176 823c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 824343c2616Smx205022 if (rgep->suspended) { 825343c2616Smx205022 mutex_exit(rgep->genlock); 826343c2616Smx205022 return (DDI_FAILURE); 827343c2616Smx205022 } 828c7fd2ed0Sgs150176 /* 829c7fd2ed0Sgs150176 * Clear hw/sw statistics 830c7fd2ed0Sgs150176 */ 831c7fd2ed0Sgs150176 DMA_ZERO(rgep->dma_area_stats); 832c7fd2ed0Sgs150176 bzero(&rgep->stats, sizeof (rge_stats_t)); 833c7fd2ed0Sgs150176 834c7fd2ed0Sgs150176 /* 835c7fd2ed0Sgs150176 * Start processing and record new MAC state 836c7fd2ed0Sgs150176 */ 837c7fd2ed0Sgs150176 rge_reset(rgep); 838c7fd2ed0Sgs150176 rge_start(rgep); 839c7fd2ed0Sgs150176 rgep->rge_mac_state = RGE_MAC_STARTED; 840c7fd2ed0Sgs150176 RGE_DEBUG(("rge_m_start($%p) done", arg)); 841c7fd2ed0Sgs150176 842c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 843c7fd2ed0Sgs150176 844c7fd2ed0Sgs150176 return (0); 845c7fd2ed0Sgs150176 } 846c7fd2ed0Sgs150176 847c7fd2ed0Sgs150176 /* 848c7fd2ed0Sgs150176 * rge_m_unicst_set() -- set the physical network address 849c7fd2ed0Sgs150176 */ 850c7fd2ed0Sgs150176 static int 851c7fd2ed0Sgs150176 rge_m_unicst(void *arg, const uint8_t *macaddr) 852c7fd2ed0Sgs150176 { 853c7fd2ed0Sgs150176 rge_t *rgep = arg; /* private device info */ 854c7fd2ed0Sgs150176 855c7fd2ed0Sgs150176 /* 856c7fd2ed0Sgs150176 * Remember the new current address in the driver state 857c7fd2ed0Sgs150176 * Sync the chip's idea of the address too ... 858c7fd2ed0Sgs150176 */ 859c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 860c7fd2ed0Sgs150176 bcopy(macaddr, rgep->netaddr, ETHERADDRL); 861343c2616Smx205022 862343c2616Smx205022 if (rgep->suspended) { 863343c2616Smx205022 mutex_exit(rgep->genlock); 864343c2616Smx205022 return (DDI_SUCCESS); 865343c2616Smx205022 } 866343c2616Smx205022 867c7fd2ed0Sgs150176 rge_chip_sync(rgep, RGE_SET_MAC); 868c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 869c7fd2ed0Sgs150176 870c7fd2ed0Sgs150176 return (0); 871c7fd2ed0Sgs150176 } 872c7fd2ed0Sgs150176 873c7fd2ed0Sgs150176 /* 874c7fd2ed0Sgs150176 * Compute the index of the required bit in the multicast hash map. 875c7fd2ed0Sgs150176 * This must mirror the way the hardware actually does it! 876c7fd2ed0Sgs150176 */ 877c7fd2ed0Sgs150176 static uint32_t 878c7fd2ed0Sgs150176 rge_hash_index(const uint8_t *mca) 879c7fd2ed0Sgs150176 { 880aa817493Sgs150176 uint32_t crc = (uint32_t)RGE_HASH_CRC; 881c7fd2ed0Sgs150176 uint32_t const POLY = RGE_HASH_POLY; 882c7fd2ed0Sgs150176 uint32_t msb; 883c7fd2ed0Sgs150176 int bytes; 884c7fd2ed0Sgs150176 uchar_t currentbyte; 885c7fd2ed0Sgs150176 uint32_t index; 886c7fd2ed0Sgs150176 int bit; 887c7fd2ed0Sgs150176 888c7fd2ed0Sgs150176 for (bytes = 0; bytes < ETHERADDRL; bytes++) { 889c7fd2ed0Sgs150176 currentbyte = mca[bytes]; 890c7fd2ed0Sgs150176 for (bit = 0; bit < 8; bit++) { 891c7fd2ed0Sgs150176 msb = crc >> 31; 892c7fd2ed0Sgs150176 crc <<= 1; 893aa817493Sgs150176 if (msb ^ (currentbyte & 1)) 894c7fd2ed0Sgs150176 crc ^= POLY; 895c7fd2ed0Sgs150176 currentbyte >>= 1; 896c7fd2ed0Sgs150176 } 897c7fd2ed0Sgs150176 } 898c7fd2ed0Sgs150176 index = crc >> 26; 899aa817493Sgs150176 /* the index value is between 0 and 63(0x3f) */ 900c7fd2ed0Sgs150176 901c7fd2ed0Sgs150176 return (index); 902c7fd2ed0Sgs150176 } 903c7fd2ed0Sgs150176 904c7fd2ed0Sgs150176 /* 905c7fd2ed0Sgs150176 * rge_m_multicst_add() -- enable/disable a multicast address 906c7fd2ed0Sgs150176 */ 907c7fd2ed0Sgs150176 static int 908c7fd2ed0Sgs150176 rge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 909c7fd2ed0Sgs150176 { 910c7fd2ed0Sgs150176 rge_t *rgep = arg; /* private device info */ 911c7fd2ed0Sgs150176 struct ether_addr *addr; 912c7fd2ed0Sgs150176 uint32_t index; 913aa817493Sgs150176 uint32_t reg; 914aa817493Sgs150176 uint8_t *hashp; 915c7fd2ed0Sgs150176 916c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 917c7fd2ed0Sgs150176 hashp = rgep->mcast_hash; 918c7fd2ed0Sgs150176 addr = (struct ether_addr *)mca; 919aa817493Sgs150176 /* 920aa817493Sgs150176 * Calculate the Multicast address hash index value 921aa817493Sgs150176 * Normally, the position of MAR0-MAR7 is 922aa817493Sgs150176 * MAR0: offset 0x08, ..., MAR7: offset 0x0F. 923aa817493Sgs150176 * 924aa817493Sgs150176 * For pcie chipset, the position of MAR0-MAR7 is 925aa817493Sgs150176 * different from others: 926aa817493Sgs150176 * MAR0: offset 0x0F, ..., MAR7: offset 0x08. 927aa817493Sgs150176 */ 928c7fd2ed0Sgs150176 index = rge_hash_index(addr->ether_addr_octet); 929aa817493Sgs150176 if (rgep->chipid.is_pcie) 930aa817493Sgs150176 reg = (~(index / RGE_MCAST_NUM)) & 0x7; 931aa817493Sgs150176 else 932aa817493Sgs150176 reg = index / RGE_MCAST_NUM; 933c7fd2ed0Sgs150176 934c7fd2ed0Sgs150176 if (add) { 935c7fd2ed0Sgs150176 if (rgep->mcast_refs[index]++) { 936c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 937c7fd2ed0Sgs150176 return (0); 938c7fd2ed0Sgs150176 } 939aa817493Sgs150176 hashp[reg] |= 1 << (index % RGE_MCAST_NUM); 940c7fd2ed0Sgs150176 } else { 941c7fd2ed0Sgs150176 if (--rgep->mcast_refs[index]) { 942c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 943c7fd2ed0Sgs150176 return (0); 944c7fd2ed0Sgs150176 } 945aa817493Sgs150176 hashp[reg] &= ~ (1 << (index % RGE_MCAST_NUM)); 946c7fd2ed0Sgs150176 } 947c7fd2ed0Sgs150176 948343c2616Smx205022 if (rgep->suspended) { 949343c2616Smx205022 mutex_exit(rgep->genlock); 950343c2616Smx205022 return (DDI_SUCCESS); 951343c2616Smx205022 } 952343c2616Smx205022 953c7fd2ed0Sgs150176 /* 954c7fd2ed0Sgs150176 * Set multicast register 955c7fd2ed0Sgs150176 */ 956c7fd2ed0Sgs150176 rge_chip_sync(rgep, RGE_SET_MUL); 957c7fd2ed0Sgs150176 958c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 959c7fd2ed0Sgs150176 return (0); 960c7fd2ed0Sgs150176 } 961c7fd2ed0Sgs150176 962c7fd2ed0Sgs150176 /* 963c7fd2ed0Sgs150176 * rge_m_promisc() -- set or reset promiscuous mode on the board 964c7fd2ed0Sgs150176 * 965c7fd2ed0Sgs150176 * Program the hardware to enable/disable promiscuous and/or 966c7fd2ed0Sgs150176 * receive-all-multicast modes. 967c7fd2ed0Sgs150176 */ 968c7fd2ed0Sgs150176 static int 969c7fd2ed0Sgs150176 rge_m_promisc(void *arg, boolean_t on) 970c7fd2ed0Sgs150176 { 971c7fd2ed0Sgs150176 rge_t *rgep = arg; 972c7fd2ed0Sgs150176 973c7fd2ed0Sgs150176 /* 974c7fd2ed0Sgs150176 * Store MAC layer specified mode and pass to chip layer to update h/w 975c7fd2ed0Sgs150176 */ 976c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 977c7fd2ed0Sgs150176 978c7fd2ed0Sgs150176 if (rgep->promisc == on) { 979c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 980c7fd2ed0Sgs150176 return (0); 981c7fd2ed0Sgs150176 } 982c7fd2ed0Sgs150176 rgep->promisc = on; 983343c2616Smx205022 984343c2616Smx205022 if (rgep->suspended) { 985343c2616Smx205022 mutex_exit(rgep->genlock); 986343c2616Smx205022 return (DDI_SUCCESS); 987343c2616Smx205022 } 988343c2616Smx205022 989c7fd2ed0Sgs150176 rge_chip_sync(rgep, RGE_SET_PROMISC); 990c7fd2ed0Sgs150176 RGE_DEBUG(("rge_m_promisc_set($%p) done", arg)); 991c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 992c7fd2ed0Sgs150176 return (0); 993c7fd2ed0Sgs150176 } 994c7fd2ed0Sgs150176 995c7fd2ed0Sgs150176 /* 996c7fd2ed0Sgs150176 * Loopback ioctl code 997c7fd2ed0Sgs150176 */ 998c7fd2ed0Sgs150176 999c7fd2ed0Sgs150176 static lb_property_t loopmodes[] = { 1000c7fd2ed0Sgs150176 { normal, "normal", RGE_LOOP_NONE }, 1001c7fd2ed0Sgs150176 { internal, "PHY", RGE_LOOP_INTERNAL_PHY }, 1002c7fd2ed0Sgs150176 { internal, "MAC", RGE_LOOP_INTERNAL_MAC } 1003c7fd2ed0Sgs150176 }; 1004c7fd2ed0Sgs150176 1005c7fd2ed0Sgs150176 static enum ioc_reply 1006c7fd2ed0Sgs150176 rge_set_loop_mode(rge_t *rgep, uint32_t mode) 1007c7fd2ed0Sgs150176 { 1008c7fd2ed0Sgs150176 /* 1009c7fd2ed0Sgs150176 * If the mode isn't being changed, there's nothing to do ... 1010c7fd2ed0Sgs150176 */ 1011c7fd2ed0Sgs150176 if (mode == rgep->param_loop_mode) 1012c7fd2ed0Sgs150176 return (IOC_ACK); 1013c7fd2ed0Sgs150176 1014c7fd2ed0Sgs150176 /* 1015c7fd2ed0Sgs150176 * Validate the requested mode and prepare a suitable message 1016c7fd2ed0Sgs150176 * to explain the link down/up cycle that the change will 1017c7fd2ed0Sgs150176 * probably induce ... 1018c7fd2ed0Sgs150176 */ 1019c7fd2ed0Sgs150176 switch (mode) { 1020c7fd2ed0Sgs150176 default: 1021c7fd2ed0Sgs150176 return (IOC_INVAL); 1022c7fd2ed0Sgs150176 1023c7fd2ed0Sgs150176 case RGE_LOOP_NONE: 1024c7fd2ed0Sgs150176 case RGE_LOOP_INTERNAL_PHY: 1025c7fd2ed0Sgs150176 case RGE_LOOP_INTERNAL_MAC: 1026c7fd2ed0Sgs150176 break; 1027c7fd2ed0Sgs150176 } 1028c7fd2ed0Sgs150176 1029c7fd2ed0Sgs150176 /* 1030c7fd2ed0Sgs150176 * All OK; tell the caller to reprogram 1031c7fd2ed0Sgs150176 * the PHY and/or MAC for the new mode ... 1032c7fd2ed0Sgs150176 */ 1033c7fd2ed0Sgs150176 rgep->param_loop_mode = mode; 1034c7fd2ed0Sgs150176 return (IOC_RESTART_ACK); 1035c7fd2ed0Sgs150176 } 1036c7fd2ed0Sgs150176 1037c7fd2ed0Sgs150176 static enum ioc_reply 1038c7fd2ed0Sgs150176 rge_loop_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 1039c7fd2ed0Sgs150176 { 1040c7fd2ed0Sgs150176 lb_info_sz_t *lbsp; 1041c7fd2ed0Sgs150176 lb_property_t *lbpp; 1042c7fd2ed0Sgs150176 uint32_t *lbmp; 1043c7fd2ed0Sgs150176 int cmd; 1044c7fd2ed0Sgs150176 1045c7fd2ed0Sgs150176 _NOTE(ARGUNUSED(wq)) 1046c7fd2ed0Sgs150176 1047c7fd2ed0Sgs150176 /* 1048c7fd2ed0Sgs150176 * Validate format of ioctl 1049c7fd2ed0Sgs150176 */ 1050c7fd2ed0Sgs150176 if (mp->b_cont == NULL) 1051c7fd2ed0Sgs150176 return (IOC_INVAL); 1052c7fd2ed0Sgs150176 1053c7fd2ed0Sgs150176 cmd = iocp->ioc_cmd; 1054c7fd2ed0Sgs150176 switch (cmd) { 1055c7fd2ed0Sgs150176 default: 1056c7fd2ed0Sgs150176 /* NOTREACHED */ 1057c7fd2ed0Sgs150176 rge_error(rgep, "rge_loop_ioctl: invalid cmd 0x%x", cmd); 1058c7fd2ed0Sgs150176 return (IOC_INVAL); 1059c7fd2ed0Sgs150176 1060c7fd2ed0Sgs150176 case LB_GET_INFO_SIZE: 1061c7fd2ed0Sgs150176 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 1062c7fd2ed0Sgs150176 return (IOC_INVAL); 1063c7fd2ed0Sgs150176 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 1064c7fd2ed0Sgs150176 *lbsp = sizeof (loopmodes); 1065c7fd2ed0Sgs150176 return (IOC_REPLY); 1066c7fd2ed0Sgs150176 1067c7fd2ed0Sgs150176 case LB_GET_INFO: 1068c7fd2ed0Sgs150176 if (iocp->ioc_count != sizeof (loopmodes)) 1069c7fd2ed0Sgs150176 return (IOC_INVAL); 1070c7fd2ed0Sgs150176 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 1071c7fd2ed0Sgs150176 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 1072c7fd2ed0Sgs150176 return (IOC_REPLY); 1073c7fd2ed0Sgs150176 1074c7fd2ed0Sgs150176 case LB_GET_MODE: 1075c7fd2ed0Sgs150176 if (iocp->ioc_count != sizeof (uint32_t)) 1076c7fd2ed0Sgs150176 return (IOC_INVAL); 1077c7fd2ed0Sgs150176 lbmp = (uint32_t *)mp->b_cont->b_rptr; 1078c7fd2ed0Sgs150176 *lbmp = rgep->param_loop_mode; 1079c7fd2ed0Sgs150176 return (IOC_REPLY); 1080c7fd2ed0Sgs150176 1081c7fd2ed0Sgs150176 case LB_SET_MODE: 1082c7fd2ed0Sgs150176 if (iocp->ioc_count != sizeof (uint32_t)) 1083c7fd2ed0Sgs150176 return (IOC_INVAL); 1084c7fd2ed0Sgs150176 lbmp = (uint32_t *)mp->b_cont->b_rptr; 1085c7fd2ed0Sgs150176 return (rge_set_loop_mode(rgep, *lbmp)); 1086c7fd2ed0Sgs150176 } 1087c7fd2ed0Sgs150176 } 1088c7fd2ed0Sgs150176 1089c7fd2ed0Sgs150176 /* 1090c7fd2ed0Sgs150176 * Specific rge IOCTLs, the MAC layer handles the generic ones. 1091c7fd2ed0Sgs150176 */ 1092c7fd2ed0Sgs150176 static void 1093c7fd2ed0Sgs150176 rge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 1094c7fd2ed0Sgs150176 { 1095c7fd2ed0Sgs150176 rge_t *rgep = arg; 1096c7fd2ed0Sgs150176 struct iocblk *iocp; 1097c7fd2ed0Sgs150176 enum ioc_reply status; 1098c7fd2ed0Sgs150176 boolean_t need_privilege; 1099c7fd2ed0Sgs150176 int err; 1100c7fd2ed0Sgs150176 int cmd; 1101c7fd2ed0Sgs150176 1102c7fd2ed0Sgs150176 /* 1103343c2616Smx205022 * If suspended, we might actually be able to do some of 1104343c2616Smx205022 * these ioctls, but it is harder to make sure they occur 1105343c2616Smx205022 * without actually putting the hardware in an undesireable 1106343c2616Smx205022 * state. So just NAK it. 1107343c2616Smx205022 */ 1108343c2616Smx205022 mutex_enter(rgep->genlock); 1109343c2616Smx205022 if (rgep->suspended) { 1110343c2616Smx205022 miocnak(wq, mp, 0, EINVAL); 1111343c2616Smx205022 mutex_exit(rgep->genlock); 1112343c2616Smx205022 return; 1113343c2616Smx205022 } 1114343c2616Smx205022 mutex_exit(rgep->genlock); 1115343c2616Smx205022 1116343c2616Smx205022 /* 1117c7fd2ed0Sgs150176 * Validate the command before bothering with the mutex ... 1118c7fd2ed0Sgs150176 */ 1119c7fd2ed0Sgs150176 iocp = (struct iocblk *)mp->b_rptr; 1120c7fd2ed0Sgs150176 iocp->ioc_error = 0; 1121c7fd2ed0Sgs150176 need_privilege = B_TRUE; 1122c7fd2ed0Sgs150176 cmd = iocp->ioc_cmd; 1123c7fd2ed0Sgs150176 switch (cmd) { 1124c7fd2ed0Sgs150176 default: 1125c7fd2ed0Sgs150176 miocnak(wq, mp, 0, EINVAL); 1126c7fd2ed0Sgs150176 return; 1127c7fd2ed0Sgs150176 1128c7fd2ed0Sgs150176 case RGE_MII_READ: 1129c7fd2ed0Sgs150176 case RGE_MII_WRITE: 1130c7fd2ed0Sgs150176 case RGE_DIAG: 1131c7fd2ed0Sgs150176 case RGE_PEEK: 1132c7fd2ed0Sgs150176 case RGE_POKE: 1133c7fd2ed0Sgs150176 case RGE_PHY_RESET: 1134c7fd2ed0Sgs150176 case RGE_SOFT_RESET: 1135c7fd2ed0Sgs150176 case RGE_HARD_RESET: 1136c7fd2ed0Sgs150176 break; 1137c7fd2ed0Sgs150176 1138c7fd2ed0Sgs150176 case LB_GET_INFO_SIZE: 1139c7fd2ed0Sgs150176 case LB_GET_INFO: 1140c7fd2ed0Sgs150176 case LB_GET_MODE: 1141c7fd2ed0Sgs150176 need_privilege = B_FALSE; 1142c7fd2ed0Sgs150176 /* FALLTHRU */ 1143c7fd2ed0Sgs150176 case LB_SET_MODE: 1144c7fd2ed0Sgs150176 break; 1145c7fd2ed0Sgs150176 1146c7fd2ed0Sgs150176 case ND_GET: 1147c7fd2ed0Sgs150176 need_privilege = B_FALSE; 1148c7fd2ed0Sgs150176 /* FALLTHRU */ 1149c7fd2ed0Sgs150176 case ND_SET: 1150c7fd2ed0Sgs150176 break; 1151c7fd2ed0Sgs150176 } 1152c7fd2ed0Sgs150176 1153c7fd2ed0Sgs150176 if (need_privilege) { 1154c7fd2ed0Sgs150176 /* 1155aa817493Sgs150176 * Check for specific net_config privilege 1156c7fd2ed0Sgs150176 */ 1157c7fd2ed0Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 1158c7fd2ed0Sgs150176 if (err != 0) { 1159c7fd2ed0Sgs150176 miocnak(wq, mp, 0, err); 1160c7fd2ed0Sgs150176 return; 1161c7fd2ed0Sgs150176 } 1162c7fd2ed0Sgs150176 } 1163c7fd2ed0Sgs150176 1164c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 1165c7fd2ed0Sgs150176 1166c7fd2ed0Sgs150176 switch (cmd) { 1167c7fd2ed0Sgs150176 default: 1168c7fd2ed0Sgs150176 _NOTE(NOTREACHED) 1169c7fd2ed0Sgs150176 status = IOC_INVAL; 1170c7fd2ed0Sgs150176 break; 1171c7fd2ed0Sgs150176 1172c7fd2ed0Sgs150176 case RGE_MII_READ: 1173c7fd2ed0Sgs150176 case RGE_MII_WRITE: 1174c7fd2ed0Sgs150176 case RGE_DIAG: 1175c7fd2ed0Sgs150176 case RGE_PEEK: 1176c7fd2ed0Sgs150176 case RGE_POKE: 1177c7fd2ed0Sgs150176 case RGE_PHY_RESET: 1178c7fd2ed0Sgs150176 case RGE_SOFT_RESET: 1179c7fd2ed0Sgs150176 case RGE_HARD_RESET: 1180c7fd2ed0Sgs150176 status = rge_chip_ioctl(rgep, wq, mp, iocp); 1181c7fd2ed0Sgs150176 break; 1182c7fd2ed0Sgs150176 1183c7fd2ed0Sgs150176 case LB_GET_INFO_SIZE: 1184c7fd2ed0Sgs150176 case LB_GET_INFO: 1185c7fd2ed0Sgs150176 case LB_GET_MODE: 1186c7fd2ed0Sgs150176 case LB_SET_MODE: 1187c7fd2ed0Sgs150176 status = rge_loop_ioctl(rgep, wq, mp, iocp); 1188c7fd2ed0Sgs150176 break; 1189c7fd2ed0Sgs150176 1190c7fd2ed0Sgs150176 case ND_GET: 1191c7fd2ed0Sgs150176 case ND_SET: 1192c7fd2ed0Sgs150176 status = rge_nd_ioctl(rgep, wq, mp, iocp); 1193c7fd2ed0Sgs150176 break; 1194c7fd2ed0Sgs150176 } 1195c7fd2ed0Sgs150176 1196c7fd2ed0Sgs150176 /* 1197c7fd2ed0Sgs150176 * Do we need to reprogram the PHY and/or the MAC? 1198c7fd2ed0Sgs150176 * Do it now, while we still have the mutex. 1199c7fd2ed0Sgs150176 * 1200c7fd2ed0Sgs150176 * Note: update the PHY first, 'cos it controls the 1201c7fd2ed0Sgs150176 * speed/duplex parameters that the MAC code uses. 1202c7fd2ed0Sgs150176 */ 1203c7fd2ed0Sgs150176 switch (status) { 1204c7fd2ed0Sgs150176 case IOC_RESTART_REPLY: 1205c7fd2ed0Sgs150176 case IOC_RESTART_ACK: 1206c7fd2ed0Sgs150176 rge_phy_update(rgep); 1207c7fd2ed0Sgs150176 break; 1208c7fd2ed0Sgs150176 } 1209c7fd2ed0Sgs150176 1210c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 1211c7fd2ed0Sgs150176 1212c7fd2ed0Sgs150176 /* 1213c7fd2ed0Sgs150176 * Finally, decide how to reply 1214c7fd2ed0Sgs150176 */ 1215c7fd2ed0Sgs150176 switch (status) { 1216c7fd2ed0Sgs150176 default: 1217c7fd2ed0Sgs150176 case IOC_INVAL: 1218c7fd2ed0Sgs150176 /* 1219c7fd2ed0Sgs150176 * Error, reply with a NAK and EINVAL or the specified error 1220c7fd2ed0Sgs150176 */ 1221c7fd2ed0Sgs150176 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 1222c7fd2ed0Sgs150176 EINVAL : iocp->ioc_error); 1223c7fd2ed0Sgs150176 break; 1224c7fd2ed0Sgs150176 1225c7fd2ed0Sgs150176 case IOC_DONE: 1226c7fd2ed0Sgs150176 /* 1227c7fd2ed0Sgs150176 * OK, reply already sent 1228c7fd2ed0Sgs150176 */ 1229c7fd2ed0Sgs150176 break; 1230c7fd2ed0Sgs150176 1231c7fd2ed0Sgs150176 case IOC_RESTART_ACK: 1232c7fd2ed0Sgs150176 case IOC_ACK: 1233c7fd2ed0Sgs150176 /* 1234c7fd2ed0Sgs150176 * OK, reply with an ACK 1235c7fd2ed0Sgs150176 */ 1236c7fd2ed0Sgs150176 miocack(wq, mp, 0, 0); 1237c7fd2ed0Sgs150176 break; 1238c7fd2ed0Sgs150176 1239c7fd2ed0Sgs150176 case IOC_RESTART_REPLY: 1240c7fd2ed0Sgs150176 case IOC_REPLY: 1241c7fd2ed0Sgs150176 /* 1242c7fd2ed0Sgs150176 * OK, send prepared reply as ACK or NAK 1243c7fd2ed0Sgs150176 */ 1244c7fd2ed0Sgs150176 mp->b_datap->db_type = iocp->ioc_error == 0 ? 1245c7fd2ed0Sgs150176 M_IOCACK : M_IOCNAK; 1246c7fd2ed0Sgs150176 qreply(wq, mp); 1247c7fd2ed0Sgs150176 break; 1248c7fd2ed0Sgs150176 } 1249c7fd2ed0Sgs150176 } 1250c7fd2ed0Sgs150176 1251ba2e4443Sseb /* ARGSUSED */ 1252ba2e4443Sseb static boolean_t 1253ba2e4443Sseb rge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 1254ba2e4443Sseb { 1255834a2629Syong tan - Sun Microsystems - Beijing China rge_t *rgep = arg; 1256834a2629Syong tan - Sun Microsystems - Beijing China 1257ba2e4443Sseb switch (cap) { 1258ba2e4443Sseb case MAC_CAPAB_HCKSUM: { 1259ba2e4443Sseb uint32_t *hcksum_txflags = cap_data; 1260834a2629Syong tan - Sun Microsystems - Beijing China switch (rgep->chipid.mac_ver) { 1261834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8169: 1262834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8169S_D: 1263834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8169S_E: 1264834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8169SB: 1265834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8169SC: 1266834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8168: 1267834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8168B_B: 1268834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8168B_C: 1269834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8101E: 1270834a2629Syong tan - Sun Microsystems - Beijing China *hcksum_txflags = HCKSUM_INET_FULL_V4 | 1271834a2629Syong tan - Sun Microsystems - Beijing China HCKSUM_IPHDRCKSUM; 1272834a2629Syong tan - Sun Microsystems - Beijing China break; 12735927ab2bSKHF04453@nifty.ne.jp case MAC_VER_8168C: 1274834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8101E_B: 1275834a2629Syong tan - Sun Microsystems - Beijing China case MAC_VER_8101E_C: 1276834a2629Syong tan - Sun Microsystems - Beijing China default: 1277834a2629Syong tan - Sun Microsystems - Beijing China *hcksum_txflags = 0; 1278834a2629Syong tan - Sun Microsystems - Beijing China break; 1279834a2629Syong tan - Sun Microsystems - Beijing China } 1280ba2e4443Sseb break; 1281ba2e4443Sseb } 1282ba2e4443Sseb default: 1283ba2e4443Sseb return (B_FALSE); 1284ba2e4443Sseb } 1285ba2e4443Sseb return (B_TRUE); 1286ba2e4443Sseb } 1287ba2e4443Sseb 1288c7fd2ed0Sgs150176 /* 1289aa817493Sgs150176 * ============ Init MSI/Fixed Interrupt routines ============== 1290aa817493Sgs150176 */ 1291aa817493Sgs150176 1292aa817493Sgs150176 /* 1293aa817493Sgs150176 * rge_add_intrs: 1294aa817493Sgs150176 * 1295aa817493Sgs150176 * Register FIXED or MSI interrupts. 1296aa817493Sgs150176 */ 1297aa817493Sgs150176 static int 1298aa817493Sgs150176 rge_add_intrs(rge_t *rgep, int intr_type) 1299aa817493Sgs150176 { 1300aa817493Sgs150176 dev_info_t *dip = rgep->devinfo; 1301aa817493Sgs150176 int avail; 1302aa817493Sgs150176 int actual; 1303aa817493Sgs150176 int intr_size; 1304aa817493Sgs150176 int count; 1305aa817493Sgs150176 int i, j; 1306aa817493Sgs150176 int ret; 1307aa817493Sgs150176 1308aa817493Sgs150176 /* Get number of interrupts */ 1309aa817493Sgs150176 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 1310aa817493Sgs150176 if ((ret != DDI_SUCCESS) || (count == 0)) { 1311aa817493Sgs150176 rge_error(rgep, "ddi_intr_get_nintrs() failure, ret: %d, " 1312aa817493Sgs150176 "count: %d", ret, count); 1313aa817493Sgs150176 return (DDI_FAILURE); 1314aa817493Sgs150176 } 1315aa817493Sgs150176 1316aa817493Sgs150176 /* Get number of available interrupts */ 1317aa817493Sgs150176 ret = ddi_intr_get_navail(dip, intr_type, &avail); 1318aa817493Sgs150176 if ((ret != DDI_SUCCESS) || (avail == 0)) { 1319aa817493Sgs150176 rge_error(rgep, "ddi_intr_get_navail() failure, " 1320aa817493Sgs150176 "ret: %d, avail: %d\n", ret, avail); 1321aa817493Sgs150176 return (DDI_FAILURE); 1322aa817493Sgs150176 } 1323aa817493Sgs150176 1324aa817493Sgs150176 /* Allocate an array of interrupt handles */ 1325aa817493Sgs150176 intr_size = count * sizeof (ddi_intr_handle_t); 1326aa817493Sgs150176 rgep->htable = kmem_alloc(intr_size, KM_SLEEP); 1327aa817493Sgs150176 rgep->intr_rqst = count; 1328aa817493Sgs150176 1329aa817493Sgs150176 /* Call ddi_intr_alloc() */ 1330aa817493Sgs150176 ret = ddi_intr_alloc(dip, rgep->htable, intr_type, 0, 1331aa817493Sgs150176 count, &actual, DDI_INTR_ALLOC_NORMAL); 1332aa817493Sgs150176 if (ret != DDI_SUCCESS || actual == 0) { 1333aa817493Sgs150176 rge_error(rgep, "ddi_intr_alloc() failed %d\n", ret); 1334aa817493Sgs150176 kmem_free(rgep->htable, intr_size); 1335aa817493Sgs150176 return (DDI_FAILURE); 1336aa817493Sgs150176 } 1337aa817493Sgs150176 if (actual < count) { 1338aa817493Sgs150176 rge_log(rgep, "ddi_intr_alloc() Requested: %d, Received: %d\n", 1339aa817493Sgs150176 count, actual); 1340aa817493Sgs150176 } 1341aa817493Sgs150176 rgep->intr_cnt = actual; 1342aa817493Sgs150176 1343aa817493Sgs150176 /* 1344aa817493Sgs150176 * Get priority for first msi, assume remaining are all the same 1345aa817493Sgs150176 */ 1346aa817493Sgs150176 if ((ret = ddi_intr_get_pri(rgep->htable[0], &rgep->intr_pri)) != 1347aa817493Sgs150176 DDI_SUCCESS) { 1348aa817493Sgs150176 rge_error(rgep, "ddi_intr_get_pri() failed %d\n", ret); 1349aa817493Sgs150176 /* Free already allocated intr */ 1350aa817493Sgs150176 for (i = 0; i < actual; i++) { 1351aa817493Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1352aa817493Sgs150176 } 1353aa817493Sgs150176 kmem_free(rgep->htable, intr_size); 1354aa817493Sgs150176 return (DDI_FAILURE); 1355aa817493Sgs150176 } 1356aa817493Sgs150176 1357aa817493Sgs150176 /* Test for high level mutex */ 1358aa817493Sgs150176 if (rgep->intr_pri >= ddi_intr_get_hilevel_pri()) { 1359aa817493Sgs150176 rge_error(rgep, "rge_add_intrs:" 1360aa817493Sgs150176 "Hi level interrupt not supported"); 1361aa817493Sgs150176 for (i = 0; i < actual; i++) 1362aa817493Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1363aa817493Sgs150176 kmem_free(rgep->htable, intr_size); 1364aa817493Sgs150176 return (DDI_FAILURE); 1365aa817493Sgs150176 } 1366aa817493Sgs150176 1367aa817493Sgs150176 /* Call ddi_intr_add_handler() */ 1368aa817493Sgs150176 for (i = 0; i < actual; i++) { 1369aa817493Sgs150176 if ((ret = ddi_intr_add_handler(rgep->htable[i], rge_intr, 1370aa817493Sgs150176 (caddr_t)rgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 1371aa817493Sgs150176 rge_error(rgep, "ddi_intr_add_handler() " 1372aa817493Sgs150176 "failed %d\n", ret); 1373aa817493Sgs150176 /* Remove already added intr */ 1374aa817493Sgs150176 for (j = 0; j < i; j++) 1375aa817493Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[j]); 1376aa817493Sgs150176 /* Free already allocated intr */ 1377aa817493Sgs150176 for (i = 0; i < actual; i++) { 1378aa817493Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1379aa817493Sgs150176 } 1380aa817493Sgs150176 kmem_free(rgep->htable, intr_size); 1381aa817493Sgs150176 return (DDI_FAILURE); 1382aa817493Sgs150176 } 1383aa817493Sgs150176 } 1384aa817493Sgs150176 1385aa817493Sgs150176 if ((ret = ddi_intr_get_cap(rgep->htable[0], &rgep->intr_cap)) 1386aa817493Sgs150176 != DDI_SUCCESS) { 1387aa817493Sgs150176 rge_error(rgep, "ddi_intr_get_cap() failed %d\n", ret); 1388aa817493Sgs150176 for (i = 0; i < actual; i++) { 1389aa817493Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[i]); 1390aa817493Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1391aa817493Sgs150176 } 1392aa817493Sgs150176 kmem_free(rgep->htable, intr_size); 1393aa817493Sgs150176 return (DDI_FAILURE); 1394aa817493Sgs150176 } 1395aa817493Sgs150176 1396aa817493Sgs150176 return (DDI_SUCCESS); 1397aa817493Sgs150176 } 1398aa817493Sgs150176 1399aa817493Sgs150176 /* 1400aa817493Sgs150176 * rge_rem_intrs: 1401aa817493Sgs150176 * 1402aa817493Sgs150176 * Unregister FIXED or MSI interrupts 1403aa817493Sgs150176 */ 1404aa817493Sgs150176 static void 1405aa817493Sgs150176 rge_rem_intrs(rge_t *rgep) 1406aa817493Sgs150176 { 1407aa817493Sgs150176 int i; 1408aa817493Sgs150176 1409aa817493Sgs150176 /* Disable all interrupts */ 1410aa817493Sgs150176 if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 1411aa817493Sgs150176 /* Call ddi_intr_block_disable() */ 1412aa817493Sgs150176 (void) ddi_intr_block_disable(rgep->htable, rgep->intr_cnt); 1413aa817493Sgs150176 } else { 1414aa817493Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1415aa817493Sgs150176 (void) ddi_intr_disable(rgep->htable[i]); 1416aa817493Sgs150176 } 1417aa817493Sgs150176 } 1418aa817493Sgs150176 1419aa817493Sgs150176 /* Call ddi_intr_remove_handler() */ 1420aa817493Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1421aa817493Sgs150176 (void) ddi_intr_remove_handler(rgep->htable[i]); 1422aa817493Sgs150176 (void) ddi_intr_free(rgep->htable[i]); 1423aa817493Sgs150176 } 1424aa817493Sgs150176 1425aa817493Sgs150176 kmem_free(rgep->htable, rgep->intr_rqst * sizeof (ddi_intr_handle_t)); 1426aa817493Sgs150176 } 1427aa817493Sgs150176 1428aa817493Sgs150176 /* 1429c7fd2ed0Sgs150176 * ========== Per-instance setup/teardown code ========== 1430c7fd2ed0Sgs150176 */ 1431c7fd2ed0Sgs150176 1432c7fd2ed0Sgs150176 #undef RGE_DBG 1433c7fd2ed0Sgs150176 #define RGE_DBG RGE_DBG_INIT /* debug flag for this code */ 1434c7fd2ed0Sgs150176 1435c7fd2ed0Sgs150176 static void 1436c7fd2ed0Sgs150176 rge_unattach(rge_t *rgep) 1437c7fd2ed0Sgs150176 { 1438c7fd2ed0Sgs150176 /* 1439c7fd2ed0Sgs150176 * Flag that no more activity may be initiated 1440c7fd2ed0Sgs150176 */ 1441c7fd2ed0Sgs150176 rgep->progress &= ~PROGRESS_READY; 1442c7fd2ed0Sgs150176 rgep->rge_mac_state = RGE_MAC_UNATTACH; 1443c7fd2ed0Sgs150176 1444c7fd2ed0Sgs150176 /* 1445c7fd2ed0Sgs150176 * Quiesce the PHY and MAC (leave it reset but still powered). 1446c7fd2ed0Sgs150176 * Clean up and free all RGE data structures 1447c7fd2ed0Sgs150176 */ 1448dd4eeefdSeota if (rgep->periodic_id != NULL) { 1449dd4eeefdSeota ddi_periodic_delete(rgep->periodic_id); 1450dd4eeefdSeota rgep->periodic_id = NULL; 1451c7fd2ed0Sgs150176 } 1452c7fd2ed0Sgs150176 1453c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_KSTATS) 1454c7fd2ed0Sgs150176 rge_fini_kstats(rgep); 1455c7fd2ed0Sgs150176 1456c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_PHY) 1457c7fd2ed0Sgs150176 (void) rge_phy_reset(rgep); 1458c7fd2ed0Sgs150176 1459aa817493Sgs150176 if (rgep->progress & PROGRESS_INIT) { 1460c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 1461c7fd2ed0Sgs150176 (void) rge_chip_reset(rgep); 1462c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 1463c7fd2ed0Sgs150176 rge_fini_rings(rgep); 1464aa817493Sgs150176 } 1465aa817493Sgs150176 1466aa817493Sgs150176 if (rgep->progress & PROGRESS_INTR) { 1467aa817493Sgs150176 rge_rem_intrs(rgep); 1468c7fd2ed0Sgs150176 mutex_destroy(rgep->rc_lock); 1469c7fd2ed0Sgs150176 mutex_destroy(rgep->rx_lock); 1470c7fd2ed0Sgs150176 mutex_destroy(rgep->tc_lock); 1471c7fd2ed0Sgs150176 mutex_destroy(rgep->tx_lock); 1472c7fd2ed0Sgs150176 rw_destroy(rgep->errlock); 1473c7fd2ed0Sgs150176 mutex_destroy(rgep->genlock); 1474c7fd2ed0Sgs150176 } 1475c7fd2ed0Sgs150176 1476c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_FACTOTUM) 1477aa817493Sgs150176 (void) ddi_intr_remove_softint(rgep->factotum_hdl); 1478c7fd2ed0Sgs150176 1479c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_RESCHED) 1480aa817493Sgs150176 (void) ddi_intr_remove_softint(rgep->resched_hdl); 1481c7fd2ed0Sgs150176 1482c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_NDD) 1483c7fd2ed0Sgs150176 rge_nd_cleanup(rgep); 1484c7fd2ed0Sgs150176 1485dfc2d53eSmx205022 rge_free_bufs(rgep); 1486dfc2d53eSmx205022 1487c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_REGS) 1488c7fd2ed0Sgs150176 ddi_regs_map_free(&rgep->io_handle); 1489c7fd2ed0Sgs150176 1490c7fd2ed0Sgs150176 if (rgep->progress & PROGRESS_CFG) 1491c7fd2ed0Sgs150176 pci_config_teardown(&rgep->cfg_handle); 1492c7fd2ed0Sgs150176 1493c7fd2ed0Sgs150176 ddi_remove_minor_node(rgep->devinfo, NULL); 1494c7fd2ed0Sgs150176 kmem_free(rgep, sizeof (*rgep)); 1495c7fd2ed0Sgs150176 } 1496c7fd2ed0Sgs150176 1497c7fd2ed0Sgs150176 static int 1498c7fd2ed0Sgs150176 rge_resume(dev_info_t *devinfo) 1499c7fd2ed0Sgs150176 { 1500c7fd2ed0Sgs150176 rge_t *rgep; /* Our private data */ 1501c7fd2ed0Sgs150176 chip_id_t *cidp; 1502c7fd2ed0Sgs150176 chip_id_t chipid; 1503c7fd2ed0Sgs150176 1504c7fd2ed0Sgs150176 rgep = ddi_get_driver_private(devinfo); 1505343c2616Smx205022 1506343c2616Smx205022 /* 1507343c2616Smx205022 * If there are state inconsistancies, this is bad. Returning 1508343c2616Smx205022 * DDI_FAILURE here will eventually cause the machine to panic, 1509343c2616Smx205022 * so it is best done here so that there is a possibility of 1510343c2616Smx205022 * debugging the problem. 1511343c2616Smx205022 */ 1512c7fd2ed0Sgs150176 if (rgep == NULL) 1513343c2616Smx205022 cmn_err(CE_PANIC, 1514343c2616Smx205022 "rge: ngep returned from ddi_get_driver_private was NULL"); 1515c7fd2ed0Sgs150176 1516c7fd2ed0Sgs150176 /* 1517c7fd2ed0Sgs150176 * Refuse to resume if the data structures aren't consistent 1518c7fd2ed0Sgs150176 */ 1519c7fd2ed0Sgs150176 if (rgep->devinfo != devinfo) 1520343c2616Smx205022 cmn_err(CE_PANIC, 1521343c2616Smx205022 "rge: passed devinfo not the same as saved devinfo"); 1522c7fd2ed0Sgs150176 1523c7fd2ed0Sgs150176 /* 1524c7fd2ed0Sgs150176 * Read chip ID & set up config space command register(s) 1525c7fd2ed0Sgs150176 * Refuse to resume if the chip has changed its identity! 1526c7fd2ed0Sgs150176 */ 1527c7fd2ed0Sgs150176 cidp = &rgep->chipid; 1528c7fd2ed0Sgs150176 rge_chip_cfg_init(rgep, &chipid); 1529c7fd2ed0Sgs150176 if (chipid.vendor != cidp->vendor) 1530c7fd2ed0Sgs150176 return (DDI_FAILURE); 1531c7fd2ed0Sgs150176 if (chipid.device != cidp->device) 1532c7fd2ed0Sgs150176 return (DDI_FAILURE); 1533c7fd2ed0Sgs150176 if (chipid.revision != cidp->revision) 1534c7fd2ed0Sgs150176 return (DDI_FAILURE); 1535c7fd2ed0Sgs150176 1536343c2616Smx205022 mutex_enter(rgep->genlock); 1537343c2616Smx205022 1538343c2616Smx205022 /* 1539343c2616Smx205022 * Only in one case, this conditional branch can be executed: the port 1540343c2616Smx205022 * hasn't been plumbed. 1541343c2616Smx205022 */ 1542343c2616Smx205022 if (rgep->suspended == B_FALSE) { 1543343c2616Smx205022 mutex_exit(rgep->genlock); 1544343c2616Smx205022 return (DDI_SUCCESS); 1545343c2616Smx205022 } 1546343c2616Smx205022 rgep->rge_mac_state = RGE_MAC_STARTED; 1547c7fd2ed0Sgs150176 /* 1548c7fd2ed0Sgs150176 * All OK, reinitialise h/w & kick off NEMO scheduling 1549c7fd2ed0Sgs150176 */ 1550c7fd2ed0Sgs150176 rge_restart(rgep); 1551343c2616Smx205022 rgep->suspended = B_FALSE; 1552343c2616Smx205022 1553c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 1554343c2616Smx205022 1555c7fd2ed0Sgs150176 return (DDI_SUCCESS); 1556c7fd2ed0Sgs150176 } 1557c7fd2ed0Sgs150176 1558c7fd2ed0Sgs150176 1559c7fd2ed0Sgs150176 /* 1560c7fd2ed0Sgs150176 * attach(9E) -- Attach a device to the system 1561c7fd2ed0Sgs150176 * 1562c7fd2ed0Sgs150176 * Called once for each board successfully probed. 1563c7fd2ed0Sgs150176 */ 1564c7fd2ed0Sgs150176 static int 1565c7fd2ed0Sgs150176 rge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 1566c7fd2ed0Sgs150176 { 1567c7fd2ed0Sgs150176 rge_t *rgep; /* Our private data */ 1568ba2e4443Sseb mac_register_t *macp; 1569c7fd2ed0Sgs150176 chip_id_t *cidp; 1570aa817493Sgs150176 int intr_types; 1571c7fd2ed0Sgs150176 caddr_t regs; 1572c7fd2ed0Sgs150176 int instance; 1573aa817493Sgs150176 int i; 1574c7fd2ed0Sgs150176 int err; 1575c7fd2ed0Sgs150176 1576c7fd2ed0Sgs150176 /* 1577c7fd2ed0Sgs150176 * we don't support high level interrupts in the driver 1578c7fd2ed0Sgs150176 */ 1579c7fd2ed0Sgs150176 if (ddi_intr_hilevel(devinfo, 0) != 0) { 1580c7fd2ed0Sgs150176 cmn_err(CE_WARN, 1581c7fd2ed0Sgs150176 "rge_attach -- unsupported high level interrupt"); 1582c7fd2ed0Sgs150176 return (DDI_FAILURE); 1583c7fd2ed0Sgs150176 } 1584c7fd2ed0Sgs150176 1585c7fd2ed0Sgs150176 instance = ddi_get_instance(devinfo); 1586c7fd2ed0Sgs150176 RGE_GTRACE(("rge_attach($%p, %d) instance %d", 1587c7fd2ed0Sgs150176 (void *)devinfo, cmd, instance)); 1588c7fd2ed0Sgs150176 RGE_BRKPT(NULL, "rge_attach"); 1589c7fd2ed0Sgs150176 1590c7fd2ed0Sgs150176 switch (cmd) { 1591c7fd2ed0Sgs150176 default: 1592c7fd2ed0Sgs150176 return (DDI_FAILURE); 1593c7fd2ed0Sgs150176 1594c7fd2ed0Sgs150176 case DDI_RESUME: 1595c7fd2ed0Sgs150176 return (rge_resume(devinfo)); 1596c7fd2ed0Sgs150176 1597c7fd2ed0Sgs150176 case DDI_ATTACH: 1598c7fd2ed0Sgs150176 break; 1599c7fd2ed0Sgs150176 } 1600c7fd2ed0Sgs150176 1601c7fd2ed0Sgs150176 rgep = kmem_zalloc(sizeof (*rgep), KM_SLEEP); 1602c7fd2ed0Sgs150176 ddi_set_driver_private(devinfo, rgep); 1603c7fd2ed0Sgs150176 rgep->devinfo = devinfo; 1604c7fd2ed0Sgs150176 1605c7fd2ed0Sgs150176 /* 1606c7fd2ed0Sgs150176 * Initialize more fields in RGE private data 1607c7fd2ed0Sgs150176 */ 1608aa817493Sgs150176 rgep->rge_mac_state = RGE_MAC_ATTACH; 1609c7fd2ed0Sgs150176 rgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1610c7fd2ed0Sgs150176 DDI_PROP_DONTPASS, debug_propname, rge_debug); 1611aa817493Sgs150176 rgep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1612aa817493Sgs150176 DDI_PROP_DONTPASS, mtu_propname, ETHERMTU); 1613aa817493Sgs150176 rgep->msi_enable = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1614aa817493Sgs150176 DDI_PROP_DONTPASS, msi_propname, B_TRUE); 1615c7fd2ed0Sgs150176 (void) snprintf(rgep->ifname, sizeof (rgep->ifname), "%s%d", 1616c7fd2ed0Sgs150176 RGE_DRIVER_NAME, instance); 1617c7fd2ed0Sgs150176 1618c7fd2ed0Sgs150176 /* 1619c7fd2ed0Sgs150176 * Map config space registers 1620c7fd2ed0Sgs150176 * Read chip ID & set up config space command register(s) 1621c7fd2ed0Sgs150176 * 1622c7fd2ed0Sgs150176 * Note: this leaves the chip accessible by Memory Space 1623c7fd2ed0Sgs150176 * accesses, but with interrupts and Bus Mastering off. 1624c7fd2ed0Sgs150176 * This should ensure that nothing untoward will happen 1625c7fd2ed0Sgs150176 * if it has been left active by the (net-)bootloader. 1626c7fd2ed0Sgs150176 * We'll re-enable Bus Mastering once we've reset the chip, 1627c7fd2ed0Sgs150176 * and allow interrupts only when everything else is set up. 1628c7fd2ed0Sgs150176 */ 1629c7fd2ed0Sgs150176 err = pci_config_setup(devinfo, &rgep->cfg_handle); 1630c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1631c7fd2ed0Sgs150176 rge_problem(rgep, "pci_config_setup() failed"); 1632c7fd2ed0Sgs150176 goto attach_fail; 1633c7fd2ed0Sgs150176 } 1634c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_CFG; 1635c7fd2ed0Sgs150176 cidp = &rgep->chipid; 1636c7fd2ed0Sgs150176 bzero(cidp, sizeof (*cidp)); 1637c7fd2ed0Sgs150176 rge_chip_cfg_init(rgep, cidp); 1638c7fd2ed0Sgs150176 1639c7fd2ed0Sgs150176 /* 1640c7fd2ed0Sgs150176 * Map operating registers 1641c7fd2ed0Sgs150176 */ 16423a84c50fSWinson Wang - Sun Microsystems - Beijing China err = ddi_regs_map_setup(devinfo, 2, ®s, 1643c7fd2ed0Sgs150176 0, 0, &rge_reg_accattr, &rgep->io_handle); 16445ca61e50SLi-Zhen You 16455ca61e50SLi-Zhen You /* 16465ca61e50SLi-Zhen You * MMIO map will fail if the assigned address is bigger than 4G 16475ca61e50SLi-Zhen You * then choose I/O map 16485ca61e50SLi-Zhen You */ 16495ca61e50SLi-Zhen You if (err != DDI_SUCCESS) { 16505ca61e50SLi-Zhen You err = ddi_regs_map_setup(devinfo, 1, ®s, 16515ca61e50SLi-Zhen You 0, 0, &rge_reg_accattr, &rgep->io_handle); 16525ca61e50SLi-Zhen You } 1653c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1654c7fd2ed0Sgs150176 rge_problem(rgep, "ddi_regs_map_setup() failed"); 1655c7fd2ed0Sgs150176 goto attach_fail; 1656c7fd2ed0Sgs150176 } 1657c7fd2ed0Sgs150176 rgep->io_regs = regs; 1658c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_REGS; 1659c7fd2ed0Sgs150176 1660c7fd2ed0Sgs150176 /* 1661c7fd2ed0Sgs150176 * Characterise the device, so we know its requirements. 1662c7fd2ed0Sgs150176 * Then allocate the appropriate TX and RX descriptors & buffers. 1663c7fd2ed0Sgs150176 */ 1664c7fd2ed0Sgs150176 rge_chip_ident(rgep); 1665c7fd2ed0Sgs150176 err = rge_alloc_bufs(rgep); 1666c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1667c7fd2ed0Sgs150176 rge_problem(rgep, "DMA buffer allocation failed"); 1668c7fd2ed0Sgs150176 goto attach_fail; 1669c7fd2ed0Sgs150176 } 1670c7fd2ed0Sgs150176 1671c7fd2ed0Sgs150176 /* 1672dfc2d53eSmx205022 * Register NDD-tweakable parameters 1673dfc2d53eSmx205022 */ 1674dfc2d53eSmx205022 if (rge_nd_init(rgep)) { 1675dfc2d53eSmx205022 rge_problem(rgep, "rge_nd_init() failed"); 1676dfc2d53eSmx205022 goto attach_fail; 1677dfc2d53eSmx205022 } 1678dfc2d53eSmx205022 rgep->progress |= PROGRESS_NDD; 1679dfc2d53eSmx205022 1680dfc2d53eSmx205022 /* 1681c7fd2ed0Sgs150176 * Add the softint handlers: 1682c7fd2ed0Sgs150176 * 1683c7fd2ed0Sgs150176 * Both of these handlers are used to avoid restrictions on the 1684c7fd2ed0Sgs150176 * context and/or mutexes required for some operations. In 1685c7fd2ed0Sgs150176 * particular, the hardware interrupt handler and its subfunctions 1686c7fd2ed0Sgs150176 * can detect a number of conditions that we don't want to handle 1687c7fd2ed0Sgs150176 * in that context or with that set of mutexes held. So, these 1688c7fd2ed0Sgs150176 * softints are triggered instead: 1689c7fd2ed0Sgs150176 * 1690c7fd2ed0Sgs150176 * the <resched> softint is triggered if if we have previously 1691c7fd2ed0Sgs150176 * had to refuse to send a packet because of resource shortage 1692c7fd2ed0Sgs150176 * (we've run out of transmit buffers), but the send completion 1693c7fd2ed0Sgs150176 * interrupt handler has now detected that more buffers have 1694c7fd2ed0Sgs150176 * become available. 1695c7fd2ed0Sgs150176 * 1696c7fd2ed0Sgs150176 * the <factotum> is triggered if the h/w interrupt handler 1697c7fd2ed0Sgs150176 * sees the <link state changed> or <error> bits in the status 1698c7fd2ed0Sgs150176 * block. It's also triggered periodically to poll the link 1699c7fd2ed0Sgs150176 * state, just in case we aren't getting link status change 1700c7fd2ed0Sgs150176 * interrupts ... 1701c7fd2ed0Sgs150176 */ 1702aa817493Sgs150176 err = ddi_intr_add_softint(devinfo, &rgep->resched_hdl, 1703aa817493Sgs150176 DDI_INTR_SOFTPRI_MIN, rge_reschedule, (caddr_t)rgep); 1704c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1705aa817493Sgs150176 rge_problem(rgep, "ddi_intr_add_softint() failed"); 1706c7fd2ed0Sgs150176 goto attach_fail; 1707c7fd2ed0Sgs150176 } 1708c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_RESCHED; 1709aa817493Sgs150176 err = ddi_intr_add_softint(devinfo, &rgep->factotum_hdl, 1710aa817493Sgs150176 DDI_INTR_SOFTPRI_MIN, rge_chip_factotum, (caddr_t)rgep); 1711c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1712aa817493Sgs150176 rge_problem(rgep, "ddi_intr_add_softint() failed"); 1713c7fd2ed0Sgs150176 goto attach_fail; 1714c7fd2ed0Sgs150176 } 1715c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_FACTOTUM; 1716c7fd2ed0Sgs150176 1717c7fd2ed0Sgs150176 /* 1718aa817493Sgs150176 * Get supported interrupt types 1719c7fd2ed0Sgs150176 */ 1720aa817493Sgs150176 if (ddi_intr_get_supported_types(devinfo, &intr_types) 1721aa817493Sgs150176 != DDI_SUCCESS) { 1722aa817493Sgs150176 rge_error(rgep, "ddi_intr_get_supported_types failed\n"); 1723c7fd2ed0Sgs150176 goto attach_fail; 1724c7fd2ed0Sgs150176 } 1725aa817493Sgs150176 1726aa817493Sgs150176 /* 1727aa817493Sgs150176 * Add the h/w interrupt handler and initialise mutexes 1728343c2616Smx205022 * RTL8101E is observed to have MSI invalidation issue after S/R. 1729343c2616Smx205022 * So the FIXED interrupt is used instead. 1730aa817493Sgs150176 */ 1731343c2616Smx205022 if (rgep->chipid.mac_ver == MAC_VER_8101E) 1732343c2616Smx205022 rgep->msi_enable = B_FALSE; 1733aa817493Sgs150176 if ((intr_types & DDI_INTR_TYPE_MSI) && rgep->msi_enable) { 1734aa817493Sgs150176 if (rge_add_intrs(rgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 1735aa817493Sgs150176 rge_error(rgep, "MSI registration failed, " 1736aa817493Sgs150176 "trying FIXED interrupt type\n"); 1737aa817493Sgs150176 } else { 1738aa817493Sgs150176 rge_log(rgep, "Using MSI interrupt type\n"); 1739aa817493Sgs150176 rgep->intr_type = DDI_INTR_TYPE_MSI; 1740c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_INTR; 1741aa817493Sgs150176 } 1742aa817493Sgs150176 } 1743aa817493Sgs150176 if (!(rgep->progress & PROGRESS_INTR) && 1744aa817493Sgs150176 (intr_types & DDI_INTR_TYPE_FIXED)) { 1745aa817493Sgs150176 if (rge_add_intrs(rgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 1746aa817493Sgs150176 rge_error(rgep, "FIXED interrupt " 1747aa817493Sgs150176 "registration failed\n"); 1748aa817493Sgs150176 goto attach_fail; 1749aa817493Sgs150176 } 1750aa817493Sgs150176 rge_log(rgep, "Using FIXED interrupt type\n"); 1751aa817493Sgs150176 rgep->intr_type = DDI_INTR_TYPE_FIXED; 1752aa817493Sgs150176 rgep->progress |= PROGRESS_INTR; 1753aa817493Sgs150176 } 1754aa817493Sgs150176 if (!(rgep->progress & PROGRESS_INTR)) { 1755aa817493Sgs150176 rge_error(rgep, "No interrupts registered\n"); 1756aa817493Sgs150176 goto attach_fail; 1757aa817493Sgs150176 } 1758aa817493Sgs150176 mutex_init(rgep->genlock, NULL, MUTEX_DRIVER, 1759aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1760aa817493Sgs150176 rw_init(rgep->errlock, NULL, RW_DRIVER, 1761aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1762aa817493Sgs150176 mutex_init(rgep->tx_lock, NULL, MUTEX_DRIVER, 1763aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1764aa817493Sgs150176 mutex_init(rgep->tc_lock, NULL, MUTEX_DRIVER, 1765aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1766aa817493Sgs150176 mutex_init(rgep->rx_lock, NULL, MUTEX_DRIVER, 1767aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1768aa817493Sgs150176 mutex_init(rgep->rc_lock, NULL, MUTEX_DRIVER, 1769aa817493Sgs150176 DDI_INTR_PRI(rgep->intr_pri)); 1770c7fd2ed0Sgs150176 1771c7fd2ed0Sgs150176 /* 1772c7fd2ed0Sgs150176 * Initialize rings 1773c7fd2ed0Sgs150176 */ 1774c7fd2ed0Sgs150176 err = rge_init_rings(rgep); 1775c7fd2ed0Sgs150176 if (err != DDI_SUCCESS) { 1776c7fd2ed0Sgs150176 rge_problem(rgep, "rge_init_rings() failed"); 1777c7fd2ed0Sgs150176 goto attach_fail; 1778c7fd2ed0Sgs150176 } 1779aa817493Sgs150176 rgep->progress |= PROGRESS_INIT; 1780aa817493Sgs150176 1781aa817493Sgs150176 /* 1782aa817493Sgs150176 * Now that mutex locks are initialized, enable interrupts. 1783aa817493Sgs150176 */ 1784aa817493Sgs150176 if (rgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 1785aa817493Sgs150176 /* Call ddi_intr_block_enable() for MSI interrupts */ 1786aa817493Sgs150176 (void) ddi_intr_block_enable(rgep->htable, rgep->intr_cnt); 1787aa817493Sgs150176 } else { 1788aa817493Sgs150176 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 1789aa817493Sgs150176 for (i = 0; i < rgep->intr_cnt; i++) { 1790aa817493Sgs150176 (void) ddi_intr_enable(rgep->htable[i]); 1791aa817493Sgs150176 } 1792aa817493Sgs150176 } 1793c7fd2ed0Sgs150176 1794c7fd2ed0Sgs150176 /* 1795c7fd2ed0Sgs150176 * Initialise link state variables 1796c7fd2ed0Sgs150176 * Stop, reset & reinitialise the chip. 1797c7fd2ed0Sgs150176 * Initialise the (internal) PHY. 1798c7fd2ed0Sgs150176 */ 1799c7fd2ed0Sgs150176 rgep->param_link_up = LINK_STATE_UNKNOWN; 1800c7fd2ed0Sgs150176 1801c7fd2ed0Sgs150176 /* 1802c7fd2ed0Sgs150176 * Reset chip & rings to initial state; also reset address 1803c7fd2ed0Sgs150176 * filtering, promiscuity, loopback mode. 1804c7fd2ed0Sgs150176 */ 1805c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 1806c7fd2ed0Sgs150176 (void) rge_chip_reset(rgep); 1807c7fd2ed0Sgs150176 rge_chip_sync(rgep, RGE_GET_MAC); 1808c7fd2ed0Sgs150176 bzero(rgep->mcast_hash, sizeof (rgep->mcast_hash)); 1809c7fd2ed0Sgs150176 bzero(rgep->mcast_refs, sizeof (rgep->mcast_refs)); 1810c7fd2ed0Sgs150176 rgep->promisc = B_FALSE; 1811c7fd2ed0Sgs150176 rgep->param_loop_mode = RGE_LOOP_NONE; 1812c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 1813c7fd2ed0Sgs150176 rge_phy_init(rgep); 1814c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_PHY; 1815c7fd2ed0Sgs150176 1816c7fd2ed0Sgs150176 /* 1817c7fd2ed0Sgs150176 * Create & initialise named kstats 1818c7fd2ed0Sgs150176 */ 1819c7fd2ed0Sgs150176 rge_init_kstats(rgep, instance); 1820c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_KSTATS; 1821c7fd2ed0Sgs150176 1822ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 1823ba2e4443Sseb goto attach_fail; 1824ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1825ba2e4443Sseb macp->m_driver = rgep; 1826c7fd2ed0Sgs150176 macp->m_dip = devinfo; 1827ba2e4443Sseb macp->m_src_addr = rgep->netaddr; 1828ba2e4443Sseb macp->m_callbacks = &rge_m_callbacks; 1829ba2e4443Sseb macp->m_min_sdu = 0; 1830aa817493Sgs150176 macp->m_max_sdu = rgep->default_mtu; 1831d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ; 1832c7fd2ed0Sgs150176 1833c7fd2ed0Sgs150176 /* 1834c7fd2ed0Sgs150176 * Finally, we're ready to register ourselves with the MAC layer 1835c7fd2ed0Sgs150176 * interface; if this succeeds, we're all ready to start() 1836c7fd2ed0Sgs150176 */ 1837ba2e4443Sseb err = mac_register(macp, &rgep->mh); 1838ba2e4443Sseb mac_free(macp); 1839ba2e4443Sseb if (err != 0) 1840c7fd2ed0Sgs150176 goto attach_fail; 1841c7fd2ed0Sgs150176 1842dd4eeefdSeota /* 1843dd4eeefdSeota * Register a periodical handler. 1844dd4eeefdSeota * reg_chip_cyclic() is invoked in kernel context. 1845dd4eeefdSeota */ 1846dd4eeefdSeota rgep->periodic_id = ddi_periodic_add(rge_chip_cyclic, rgep, 1847dd4eeefdSeota RGE_CYCLIC_PERIOD, DDI_IPL_0); 1848c7fd2ed0Sgs150176 1849c7fd2ed0Sgs150176 rgep->progress |= PROGRESS_READY; 1850c7fd2ed0Sgs150176 return (DDI_SUCCESS); 1851c7fd2ed0Sgs150176 1852c7fd2ed0Sgs150176 attach_fail: 1853c7fd2ed0Sgs150176 rge_unattach(rgep); 1854c7fd2ed0Sgs150176 return (DDI_FAILURE); 1855c7fd2ed0Sgs150176 } 1856c7fd2ed0Sgs150176 1857c7fd2ed0Sgs150176 /* 1858c7fd2ed0Sgs150176 * rge_suspend() -- suspend transmit/receive for powerdown 1859c7fd2ed0Sgs150176 */ 1860c7fd2ed0Sgs150176 static int 1861c7fd2ed0Sgs150176 rge_suspend(rge_t *rgep) 1862c7fd2ed0Sgs150176 { 1863c7fd2ed0Sgs150176 /* 1864c7fd2ed0Sgs150176 * Stop processing and idle (powerdown) the PHY ... 1865c7fd2ed0Sgs150176 */ 1866c7fd2ed0Sgs150176 mutex_enter(rgep->genlock); 1867368a5ef8SMiles Xu, Sun Microsystems rw_enter(rgep->errlock, RW_WRITER); 1868343c2616Smx205022 1869343c2616Smx205022 if (rgep->rge_mac_state != RGE_MAC_STARTED) { 1870368a5ef8SMiles Xu, Sun Microsystems rw_exit(rgep->errlock); 1871343c2616Smx205022 mutex_exit(rgep->genlock); 1872343c2616Smx205022 return (DDI_SUCCESS); 1873343c2616Smx205022 } 1874343c2616Smx205022 1875343c2616Smx205022 rgep->suspended = B_TRUE; 1876c7fd2ed0Sgs150176 rge_stop(rgep); 1877343c2616Smx205022 rgep->rge_mac_state = RGE_MAC_STOPPED; 1878343c2616Smx205022 1879343c2616Smx205022 rw_exit(rgep->errlock); 1880c7fd2ed0Sgs150176 mutex_exit(rgep->genlock); 1881c7fd2ed0Sgs150176 1882c7fd2ed0Sgs150176 return (DDI_SUCCESS); 1883c7fd2ed0Sgs150176 } 1884c7fd2ed0Sgs150176 1885c7fd2ed0Sgs150176 /* 188619397407SSherry Moore * quiesce(9E) entry point. 188719397407SSherry Moore * 188819397407SSherry Moore * This function is called when the system is single-threaded at high 188919397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 189019397407SSherry Moore * blocked. 189119397407SSherry Moore * 189219397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 189319397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 189419397407SSherry Moore */ 189519397407SSherry Moore static int 189619397407SSherry Moore rge_quiesce(dev_info_t *devinfo) 189719397407SSherry Moore { 189819397407SSherry Moore rge_t *rgep = ddi_get_driver_private(devinfo); 189919397407SSherry Moore 190019397407SSherry Moore if (rgep == NULL) 190119397407SSherry Moore return (DDI_FAILURE); 190219397407SSherry Moore 190319397407SSherry Moore /* 190419397407SSherry Moore * Turn off debugging 190519397407SSherry Moore */ 190619397407SSherry Moore rge_debug = 0; 190719397407SSherry Moore rgep->debug = 0; 190819397407SSherry Moore 190919397407SSherry Moore /* Stop the chip */ 191019397407SSherry Moore rge_chip_stop(rgep, B_FALSE); 191119397407SSherry Moore 191219397407SSherry Moore return (DDI_SUCCESS); 191319397407SSherry Moore } 191419397407SSherry Moore 191519397407SSherry Moore /* 1916c7fd2ed0Sgs150176 * detach(9E) -- Detach a device from the system 1917c7fd2ed0Sgs150176 */ 1918c7fd2ed0Sgs150176 static int 1919c7fd2ed0Sgs150176 rge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 1920c7fd2ed0Sgs150176 { 1921c7fd2ed0Sgs150176 rge_t *rgep; 1922c7fd2ed0Sgs150176 1923c7fd2ed0Sgs150176 RGE_GTRACE(("rge_detach($%p, %d)", (void *)devinfo, cmd)); 1924c7fd2ed0Sgs150176 1925c7fd2ed0Sgs150176 rgep = ddi_get_driver_private(devinfo); 1926c7fd2ed0Sgs150176 1927c7fd2ed0Sgs150176 switch (cmd) { 1928c7fd2ed0Sgs150176 default: 1929c7fd2ed0Sgs150176 return (DDI_FAILURE); 1930c7fd2ed0Sgs150176 1931c7fd2ed0Sgs150176 case DDI_SUSPEND: 1932c7fd2ed0Sgs150176 return (rge_suspend(rgep)); 1933c7fd2ed0Sgs150176 1934c7fd2ed0Sgs150176 case DDI_DETACH: 1935c7fd2ed0Sgs150176 break; 1936c7fd2ed0Sgs150176 } 1937c7fd2ed0Sgs150176 1938c7fd2ed0Sgs150176 /* 1939c7fd2ed0Sgs150176 * If there is any posted buffer, the driver should reject to be 1940c7fd2ed0Sgs150176 * detached. Need notice upper layer to release them. 1941c7fd2ed0Sgs150176 */ 1942aa817493Sgs150176 if (!(rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY) && 1943aa817493Sgs150176 rgep->rx_free != RGE_BUF_SLOTS) 1944c7fd2ed0Sgs150176 return (DDI_FAILURE); 1945c7fd2ed0Sgs150176 1946c7fd2ed0Sgs150176 /* 1947c7fd2ed0Sgs150176 * Unregister from the MAC layer subsystem. This can fail, in 1948c7fd2ed0Sgs150176 * particular if there are DLPI style-2 streams still open - 1949c7fd2ed0Sgs150176 * in which case we just return failure without shutting 1950c7fd2ed0Sgs150176 * down chip operations. 1951c7fd2ed0Sgs150176 */ 1952ba2e4443Sseb if (mac_unregister(rgep->mh) != 0) 1953c7fd2ed0Sgs150176 return (DDI_FAILURE); 1954c7fd2ed0Sgs150176 1955c7fd2ed0Sgs150176 /* 1956c7fd2ed0Sgs150176 * All activity stopped, so we can clean up & exit 1957c7fd2ed0Sgs150176 */ 1958c7fd2ed0Sgs150176 rge_unattach(rgep); 1959c7fd2ed0Sgs150176 return (DDI_SUCCESS); 1960c7fd2ed0Sgs150176 } 1961c7fd2ed0Sgs150176 1962c7fd2ed0Sgs150176 1963c7fd2ed0Sgs150176 /* 1964c7fd2ed0Sgs150176 * ========== Module Loading Data & Entry Points ========== 1965c7fd2ed0Sgs150176 */ 1966c7fd2ed0Sgs150176 1967c7fd2ed0Sgs150176 #undef RGE_DBG 1968c7fd2ed0Sgs150176 #define RGE_DBG RGE_DBG_INIT /* debug flag for this code */ 1969c7fd2ed0Sgs150176 DDI_DEFINE_STREAM_OPS(rge_dev_ops, nulldev, nulldev, rge_attach, rge_detach, 197019397407SSherry Moore nodev, NULL, D_MP, NULL, rge_quiesce); 1971c7fd2ed0Sgs150176 1972c7fd2ed0Sgs150176 static struct modldrv rge_modldrv = { 1973c7fd2ed0Sgs150176 &mod_driverops, /* Type of module. This one is a driver */ 1974c7fd2ed0Sgs150176 rge_ident, /* short description */ 1975c7fd2ed0Sgs150176 &rge_dev_ops /* driver specific ops */ 1976c7fd2ed0Sgs150176 }; 1977c7fd2ed0Sgs150176 1978c7fd2ed0Sgs150176 static struct modlinkage modlinkage = { 1979c7fd2ed0Sgs150176 MODREV_1, (void *)&rge_modldrv, NULL 1980c7fd2ed0Sgs150176 }; 1981c7fd2ed0Sgs150176 1982c7fd2ed0Sgs150176 1983c7fd2ed0Sgs150176 int 1984c7fd2ed0Sgs150176 _info(struct modinfo *modinfop) 1985c7fd2ed0Sgs150176 { 1986c7fd2ed0Sgs150176 return (mod_info(&modlinkage, modinfop)); 1987c7fd2ed0Sgs150176 } 1988c7fd2ed0Sgs150176 1989c7fd2ed0Sgs150176 int 1990c7fd2ed0Sgs150176 _init(void) 1991c7fd2ed0Sgs150176 { 1992c7fd2ed0Sgs150176 int status; 1993c7fd2ed0Sgs150176 1994c7fd2ed0Sgs150176 mac_init_ops(&rge_dev_ops, "rge"); 1995c7fd2ed0Sgs150176 status = mod_install(&modlinkage); 1996c7fd2ed0Sgs150176 if (status == DDI_SUCCESS) 1997c7fd2ed0Sgs150176 mutex_init(rge_log_mutex, NULL, MUTEX_DRIVER, NULL); 1998c7fd2ed0Sgs150176 else 1999c7fd2ed0Sgs150176 mac_fini_ops(&rge_dev_ops); 2000c7fd2ed0Sgs150176 2001c7fd2ed0Sgs150176 return (status); 2002c7fd2ed0Sgs150176 } 2003c7fd2ed0Sgs150176 2004c7fd2ed0Sgs150176 int 2005c7fd2ed0Sgs150176 _fini(void) 2006c7fd2ed0Sgs150176 { 2007c7fd2ed0Sgs150176 int status; 2008c7fd2ed0Sgs150176 2009c7fd2ed0Sgs150176 status = mod_remove(&modlinkage); 2010c7fd2ed0Sgs150176 if (status == DDI_SUCCESS) { 2011c7fd2ed0Sgs150176 mac_fini_ops(&rge_dev_ops); 2012c7fd2ed0Sgs150176 mutex_destroy(rge_log_mutex); 2013c7fd2ed0Sgs150176 } 2014c7fd2ed0Sgs150176 return (status); 2015c7fd2ed0Sgs150176 } 2016