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