162387023Sdduvall /* 262387023Sdduvall * CDDL HEADER START 362387023Sdduvall * 462387023Sdduvall * The contents of this file are subject to the terms of the 562387023Sdduvall * Common Development and Distribution License (the "License"). 662387023Sdduvall * You may not use this file except in compliance with the License. 762387023Sdduvall * 862387023Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 962387023Sdduvall * or http://www.opensolaris.org/os/licensing. 1062387023Sdduvall * See the License for the specific language governing permissions 1162387023Sdduvall * and limitations under the License. 1262387023Sdduvall * 1362387023Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 1462387023Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1562387023Sdduvall * If applicable, add the following below this CDDL HEADER, with the 1662387023Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 1762387023Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 1862387023Sdduvall * 1962387023Sdduvall * CDDL HEADER END 2062387023Sdduvall */ 2162387023Sdduvall 2262387023Sdduvall /* 23087a28d1SDavid Gwynne * Copyright (c) 2010-2013, by Broadcom, Inc. 24087a28d1SDavid Gwynne * All Rights Reserved. 25087a28d1SDavid Gwynne */ 26087a28d1SDavid Gwynne 27087a28d1SDavid Gwynne /* 28087a28d1SDavid Gwynne * Copyright (c) 2002, 2010, Oracle and/or its affiliates. 29087a28d1SDavid Gwynne * All rights reserved. 30*76a3936eSHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 3162387023Sdduvall */ 3262387023Sdduvall 33f724721bSzh199473 #include "bge_impl.h" 3462387023Sdduvall #include <sys/sdt.h> 35da14cebeSEric Cheng #include <sys/mac_provider.h> 363fd94f8cSam223141 #include <sys/mac.h> 37da14cebeSEric Cheng #include <sys/mac_flow.h> 3862387023Sdduvall 39087a28d1SDavid Gwynne 40087a28d1SDavid Gwynne #ifndef STRINGIFY 41087a28d1SDavid Gwynne #define XSTRINGIFY(x) #x 42087a28d1SDavid Gwynne #define STRINGIFY(x) XSTRINGIFY(x) 43087a28d1SDavid Gwynne #endif 44087a28d1SDavid Gwynne 4562387023Sdduvall /* 4662387023Sdduvall * This is the string displayed by modinfo, etc. 4727c3238fSyong tan - Sun Microsystems - Beijing China */ 4827c3238fSyong tan - Sun Microsystems - Beijing China static char bge_ident[] = "Broadcom Gb Ethernet"; 4962387023Sdduvall 5062387023Sdduvall /* 5162387023Sdduvall * Property names 5262387023Sdduvall */ 5362387023Sdduvall static char debug_propname[] = "bge-debug-flags"; 5462387023Sdduvall static char clsize_propname[] = "cache-line-size"; 5562387023Sdduvall static char latency_propname[] = "latency-timer"; 5662387023Sdduvall static char localmac_boolname[] = "local-mac-address?"; 5762387023Sdduvall static char localmac_propname[] = "local-mac-address"; 5862387023Sdduvall static char macaddr_propname[] = "mac-address"; 5962387023Sdduvall static char subdev_propname[] = "subsystem-id"; 6062387023Sdduvall static char subven_propname[] = "subsystem-vendor-id"; 6162387023Sdduvall static char rxrings_propname[] = "bge-rx-rings"; 6262387023Sdduvall static char txrings_propname[] = "bge-tx-rings"; 63087a28d1SDavid Gwynne static char eee_propname[] = "bge-eee"; 6400d0963fSdilpreet static char fm_cap[] = "fm-capable"; 651b5c96f3Sly149593 static char default_mtu[] = "default_mtu"; 6662387023Sdduvall 6762387023Sdduvall static int bge_add_intrs(bge_t *, int); 6862387023Sdduvall static void bge_rem_intrs(bge_t *); 69da14cebeSEric Cheng static int bge_unicst_set(void *, const uint8_t *, int); 70087a28d1SDavid Gwynne static int bge_addmac(void *, const uint8_t *); 71087a28d1SDavid Gwynne static int bge_remmac(void *, const uint8_t *); 7262387023Sdduvall 7362387023Sdduvall /* 7462387023Sdduvall * Describes the chip's DMA engine 7562387023Sdduvall */ 7662387023Sdduvall static ddi_dma_attr_t dma_attr = { 77087a28d1SDavid Gwynne DMA_ATTR_V0, /* dma_attr_version */ 7862387023Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */ 7962387023Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 8062387023Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 8162387023Sdduvall 0x0000000000000001ull, /* dma_attr_align */ 8262387023Sdduvall 0x00000FFF, /* dma_attr_burstsizes */ 8362387023Sdduvall 0x00000001, /* dma_attr_minxfer */ 8462387023Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */ 85087a28d1SDavid Gwynne 0x00000000FFFFFFFFull, /* dma_attr_seg */ 8662387023Sdduvall 1, /* dma_attr_sgllen */ 8762387023Sdduvall 0x00000001, /* dma_attr_granular */ 8800d0963fSdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */ 8962387023Sdduvall }; 9062387023Sdduvall 9162387023Sdduvall /* 9262387023Sdduvall * PIO access attributes for registers 9362387023Sdduvall */ 9462387023Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = { 95837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1, 9662387023Sdduvall DDI_NEVERSWAP_ACC, 9700d0963fSdilpreet DDI_STRICTORDER_ACC, 9800d0963fSdilpreet DDI_FLAGERR_ACC 9962387023Sdduvall }; 10062387023Sdduvall 10162387023Sdduvall /* 10262387023Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped. 10362387023Sdduvall */ 10462387023Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = { 10562387023Sdduvall DDI_DEVICE_ATTR_V0, 10662387023Sdduvall DDI_NEVERSWAP_ACC, 107837c1ac4SStephen Hanson DDI_STRICTORDER_ACC 10862387023Sdduvall }; 10962387023Sdduvall 11062387023Sdduvall /* 11162387023Sdduvall * DMA access attributes for data: NOT to be byte swapped. 11262387023Sdduvall */ 11362387023Sdduvall static ddi_device_acc_attr_t bge_data_accattr = { 11462387023Sdduvall DDI_DEVICE_ATTR_V0, 11562387023Sdduvall DDI_NEVERSWAP_ACC, 11662387023Sdduvall DDI_STRICTORDER_ACC 11762387023Sdduvall }; 11862387023Sdduvall 119ba2e4443Sseb static int bge_m_start(void *); 120ba2e4443Sseb static void bge_m_stop(void *); 121ba2e4443Sseb static int bge_m_promisc(void *, boolean_t); 122087a28d1SDavid Gwynne static int bge_m_unicst(void * pArg, const uint8_t *); 123ba2e4443Sseb static int bge_m_multicst(void *, boolean_t, const uint8_t *); 124087a28d1SDavid Gwynne static void bge_m_resources(void * arg); 125ba2e4443Sseb static void bge_m_ioctl(void *, queue_t *, mblk_t *); 126ba2e4443Sseb static boolean_t bge_m_getcapab(void *, mac_capab_t, void *); 127ed8845d8Skrgopi static int bge_unicst_set(void *, const uint8_t *, 128da14cebeSEric Cheng int); 129e7801d59Ssowmini static int bge_m_setprop(void *, const char *, mac_prop_id_t, 130e7801d59Ssowmini uint_t, const void *); 131e7801d59Ssowmini static int bge_m_getprop(void *, const char *, mac_prop_id_t, 1320dc2366fSVenugopal Iyer uint_t, void *); 1330dc2366fSVenugopal Iyer static void bge_m_propinfo(void *, const char *, mac_prop_id_t, 1340dc2366fSVenugopal Iyer mac_prop_info_handle_t); 135e7801d59Ssowmini static int bge_set_priv_prop(bge_t *, const char *, uint_t, 136e7801d59Ssowmini const void *); 137e7801d59Ssowmini static int bge_get_priv_prop(bge_t *, const char *, uint_t, 1380dc2366fSVenugopal Iyer void *); 1390dc2366fSVenugopal Iyer static void bge_priv_propinfo(const char *, 1400dc2366fSVenugopal Iyer mac_prop_info_handle_t); 141ba2e4443Sseb 142ba2e4443Sseb static mac_callbacks_t bge_m_callbacks = { 143087a28d1SDavid Gwynne MC_IOCTL 144087a28d1SDavid Gwynne #ifdef MC_RESOURCES 145087a28d1SDavid Gwynne | MC_RESOURCES 146087a28d1SDavid Gwynne #endif 147087a28d1SDavid Gwynne #ifdef MC_SETPROP 148087a28d1SDavid Gwynne | MC_SETPROP 149087a28d1SDavid Gwynne #endif 150087a28d1SDavid Gwynne #ifdef MC_GETPROP 151087a28d1SDavid Gwynne | MC_GETPROP 152087a28d1SDavid Gwynne #endif 153087a28d1SDavid Gwynne #ifdef MC_PROPINFO 154087a28d1SDavid Gwynne | MC_PROPINFO 155087a28d1SDavid Gwynne #endif 156087a28d1SDavid Gwynne | MC_GETCAPAB, 157ba2e4443Sseb bge_m_stat, 158ba2e4443Sseb bge_m_start, 159ba2e4443Sseb bge_m_stop, 160ba2e4443Sseb bge_m_promisc, 161ba2e4443Sseb bge_m_multicst, 162087a28d1SDavid Gwynne bge_m_unicst, 163ba2e4443Sseb bge_m_tx, 164087a28d1SDavid Gwynne #ifdef MC_RESOURCES 165087a28d1SDavid Gwynne bge_m_resources, 166087a28d1SDavid Gwynne #else 1670dc2366fSVenugopal Iyer NULL, 168087a28d1SDavid Gwynne #endif 169ba2e4443Sseb bge_m_ioctl, 170e7801d59Ssowmini bge_m_getcapab, 171087a28d1SDavid Gwynne #ifdef MC_OPEN 172e7801d59Ssowmini NULL, 173e7801d59Ssowmini NULL, 174087a28d1SDavid Gwynne #endif 175087a28d1SDavid Gwynne #ifdef MC_SETPROP 176e7801d59Ssowmini bge_m_setprop, 177087a28d1SDavid Gwynne #endif 178087a28d1SDavid Gwynne #ifdef MC_GETPROP 1790dc2366fSVenugopal Iyer bge_m_getprop, 180087a28d1SDavid Gwynne #endif 181087a28d1SDavid Gwynne #ifdef MC_PROPINFO 1820dc2366fSVenugopal Iyer bge_m_propinfo 183087a28d1SDavid Gwynne #endif 184ba2e4443Sseb }; 185ba2e4443Sseb 1860dc2366fSVenugopal Iyer char *bge_priv_prop[] = { 1870dc2366fSVenugopal Iyer "_adv_asym_pause_cap", 1880dc2366fSVenugopal Iyer "_adv_pause_cap", 1890dc2366fSVenugopal Iyer "_drain_max", 1900dc2366fSVenugopal Iyer "_msi_cnt", 1910dc2366fSVenugopal Iyer "_rx_intr_coalesce_blank_time", 1920dc2366fSVenugopal Iyer "_tx_intr_coalesce_blank_time", 1930dc2366fSVenugopal Iyer "_rx_intr_coalesce_pkt_cnt", 1940dc2366fSVenugopal Iyer "_tx_intr_coalesce_pkt_cnt", 1950dc2366fSVenugopal Iyer NULL 1964045d941Ssowmini }; 1974045d941Ssowmini 198da14cebeSEric Cheng uint8_t zero_addr[6] = {0, 0, 0, 0, 0, 0}; 19962387023Sdduvall /* 20062387023Sdduvall * ========== Transmit and receive ring reinitialisation ========== 20162387023Sdduvall */ 20262387023Sdduvall 20362387023Sdduvall /* 20462387023Sdduvall * These <reinit> routines each reset the specified ring to an initial 20562387023Sdduvall * state, assuming that the corresponding <init> routine has already 20662387023Sdduvall * been called exactly once. 20762387023Sdduvall */ 20862387023Sdduvall 20962387023Sdduvall static void 21062387023Sdduvall bge_reinit_send_ring(send_ring_t *srp) 21162387023Sdduvall { 212931dca7dSgs150176 bge_queue_t *txbuf_queue; 213931dca7dSgs150176 bge_queue_item_t *txbuf_head; 214931dca7dSgs150176 sw_txbuf_t *txbuf; 215931dca7dSgs150176 sw_sbd_t *ssbdp; 216931dca7dSgs150176 uint32_t slot; 217931dca7dSgs150176 21862387023Sdduvall /* 21962387023Sdduvall * Reinitialise control variables ... 22062387023Sdduvall */ 221931dca7dSgs150176 srp->tx_flow = 0; 22262387023Sdduvall srp->tx_next = 0; 223931dca7dSgs150176 srp->txfill_next = 0; 22462387023Sdduvall srp->tx_free = srp->desc.nslots; 22562387023Sdduvall ASSERT(mutex_owned(srp->tc_lock)); 22662387023Sdduvall srp->tc_next = 0; 227931dca7dSgs150176 srp->txpkt_next = 0; 228931dca7dSgs150176 srp->tx_block = 0; 229931dca7dSgs150176 srp->tx_nobd = 0; 230931dca7dSgs150176 srp->tx_nobuf = 0; 231931dca7dSgs150176 232931dca7dSgs150176 /* 233931dca7dSgs150176 * Initialize the tx buffer push queue 234931dca7dSgs150176 */ 235931dca7dSgs150176 mutex_enter(srp->freetxbuf_lock); 236931dca7dSgs150176 mutex_enter(srp->txbuf_lock); 237931dca7dSgs150176 txbuf_queue = &srp->freetxbuf_queue; 238931dca7dSgs150176 txbuf_queue->head = NULL; 239931dca7dSgs150176 txbuf_queue->count = 0; 240931dca7dSgs150176 txbuf_queue->lock = srp->freetxbuf_lock; 241931dca7dSgs150176 srp->txbuf_push_queue = txbuf_queue; 242931dca7dSgs150176 243931dca7dSgs150176 /* 244931dca7dSgs150176 * Initialize the tx buffer pop queue 245931dca7dSgs150176 */ 246931dca7dSgs150176 txbuf_queue = &srp->txbuf_queue; 247931dca7dSgs150176 txbuf_queue->head = NULL; 248931dca7dSgs150176 txbuf_queue->count = 0; 249931dca7dSgs150176 txbuf_queue->lock = srp->txbuf_lock; 250931dca7dSgs150176 srp->txbuf_pop_queue = txbuf_queue; 251931dca7dSgs150176 txbuf_head = srp->txbuf_head; 252931dca7dSgs150176 txbuf = srp->txbuf; 253931dca7dSgs150176 for (slot = 0; slot < srp->tx_buffers; ++slot) { 254931dca7dSgs150176 txbuf_head->item = txbuf; 255931dca7dSgs150176 txbuf_head->next = txbuf_queue->head; 256931dca7dSgs150176 txbuf_queue->head = txbuf_head; 257931dca7dSgs150176 txbuf_queue->count++; 258931dca7dSgs150176 txbuf++; 259931dca7dSgs150176 txbuf_head++; 260931dca7dSgs150176 } 261931dca7dSgs150176 mutex_exit(srp->txbuf_lock); 262931dca7dSgs150176 mutex_exit(srp->freetxbuf_lock); 26362387023Sdduvall 26462387023Sdduvall /* 26562387023Sdduvall * Zero and sync all the h/w Send Buffer Descriptors 26662387023Sdduvall */ 26762387023Sdduvall DMA_ZERO(srp->desc); 26862387023Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 269931dca7dSgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 270931dca7dSgs150176 ssbdp = srp->sw_sbds; 271931dca7dSgs150176 for (slot = 0; slot < srp->desc.nslots; ++ssbdp, ++slot) 272931dca7dSgs150176 ssbdp->pbuf = NULL; 27362387023Sdduvall } 27462387023Sdduvall 27562387023Sdduvall static void 27662387023Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp) 27762387023Sdduvall { 27862387023Sdduvall /* 27962387023Sdduvall * Reinitialise control variables ... 28062387023Sdduvall */ 28162387023Sdduvall rrp->rx_next = 0; 28262387023Sdduvall } 28362387023Sdduvall 28462387023Sdduvall static void 285931dca7dSgs150176 bge_reinit_buff_ring(buff_ring_t *brp, uint32_t ring) 28662387023Sdduvall { 28762387023Sdduvall bge_rbd_t *hw_rbd_p; 28862387023Sdduvall sw_rbd_t *srbdp; 28962387023Sdduvall uint32_t bufsize; 29062387023Sdduvall uint32_t nslots; 29162387023Sdduvall uint32_t slot; 29262387023Sdduvall 29362387023Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = { 29462387023Sdduvall RBD_FLAG_STD_RING, 29562387023Sdduvall RBD_FLAG_JUMBO_RING, 29662387023Sdduvall RBD_FLAG_MINI_RING 29762387023Sdduvall }; 29862387023Sdduvall 29962387023Sdduvall /* 30062387023Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors 30162387023Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>, 30262387023Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>) 30362387023Sdduvall * should be zeroed, and so don't need to be set up specifically 30462387023Sdduvall * once the whole area has been cleared. 30562387023Sdduvall */ 30662387023Sdduvall DMA_ZERO(brp->desc); 30762387023Sdduvall 30862387023Sdduvall hw_rbd_p = DMA_VPTR(brp->desc); 30962387023Sdduvall nslots = brp->desc.nslots; 31062387023Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 31162387023Sdduvall bufsize = brp->buf[0].size; 31262387023Sdduvall srbdp = brp->sw_rbds; 31362387023Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) { 31462387023Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress; 3154a06b59fSyt223700 hw_rbd_p->index = (uint16_t)slot; 3164a06b59fSyt223700 hw_rbd_p->len = (uint16_t)bufsize; 31762387023Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token; 31862387023Sdduvall hw_rbd_p->flags |= ring_type_flag[ring]; 31962387023Sdduvall } 32062387023Sdduvall 32162387023Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV); 32262387023Sdduvall 32362387023Sdduvall /* 32462387023Sdduvall * Finally, reinitialise the ring control variables ... 32562387023Sdduvall */ 32662387023Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0; 32762387023Sdduvall } 32862387023Sdduvall 32962387023Sdduvall /* 33062387023Sdduvall * Reinitialize all rings 33162387023Sdduvall */ 33262387023Sdduvall static void 33362387023Sdduvall bge_reinit_rings(bge_t *bgep) 33462387023Sdduvall { 335931dca7dSgs150176 uint32_t ring; 33662387023Sdduvall 33762387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 33862387023Sdduvall 33962387023Sdduvall /* 34062387023Sdduvall * Send Rings ... 34162387023Sdduvall */ 34262387023Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) 34362387023Sdduvall bge_reinit_send_ring(&bgep->send[ring]); 34462387023Sdduvall 34562387023Sdduvall /* 34662387023Sdduvall * Receive Return Rings ... 34762387023Sdduvall */ 34862387023Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring) 34962387023Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]); 35062387023Sdduvall 35162387023Sdduvall /* 35262387023Sdduvall * Receive Producer Rings ... 35362387023Sdduvall */ 35462387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 35562387023Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring); 35662387023Sdduvall } 35762387023Sdduvall 35862387023Sdduvall /* 35962387023Sdduvall * ========== Internal state management entry points ========== 36062387023Sdduvall */ 36162387023Sdduvall 36262387023Sdduvall #undef BGE_DBG 36362387023Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 36462387023Sdduvall 36562387023Sdduvall /* 36662387023Sdduvall * These routines provide all the functionality required by the 36762387023Sdduvall * corresponding GLD entry points, but don't update the GLD state 36862387023Sdduvall * so they can be called internally without disturbing our record 36962387023Sdduvall * of what GLD thinks we should be doing ... 37062387023Sdduvall */ 37162387023Sdduvall 37262387023Sdduvall /* 37362387023Sdduvall * bge_reset() -- reset h/w & rings to initial state 37462387023Sdduvall */ 37500d0963fSdilpreet static int 37667f02347Srandyf #ifdef BGE_IPMI_ASF 37767f02347Srandyf bge_reset(bge_t *bgep, uint_t asf_mode) 37867f02347Srandyf #else 37962387023Sdduvall bge_reset(bge_t *bgep) 38067f02347Srandyf #endif 38162387023Sdduvall { 382931dca7dSgs150176 uint32_t ring; 38300d0963fSdilpreet int retval; 38462387023Sdduvall 38562387023Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep)); 38662387023Sdduvall 38762387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 38862387023Sdduvall 38962387023Sdduvall /* 39062387023Sdduvall * Grab all the other mutexes in the world (this should 39162387023Sdduvall * ensure no other threads are manipulating driver state) 39262387023Sdduvall */ 39362387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 39462387023Sdduvall mutex_enter(bgep->recv[ring].rx_lock); 39562387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 39662387023Sdduvall mutex_enter(bgep->buff[ring].rf_lock); 39762387023Sdduvall rw_enter(bgep->errlock, RW_WRITER); 39862387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 399931dca7dSgs150176 mutex_enter(bgep->send[ring].tx_lock); 400931dca7dSgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 40162387023Sdduvall mutex_enter(bgep->send[ring].tc_lock); 40262387023Sdduvall 40367f02347Srandyf #ifdef BGE_IPMI_ASF 40400d0963fSdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode); 40567f02347Srandyf #else 40600d0963fSdilpreet retval = bge_chip_reset(bgep, B_TRUE); 40767f02347Srandyf #endif 40862387023Sdduvall bge_reinit_rings(bgep); 40962387023Sdduvall 41062387023Sdduvall /* 41162387023Sdduvall * Free the world ... 41262387023Sdduvall */ 41362387023Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; ) 41462387023Sdduvall mutex_exit(bgep->send[ring].tc_lock); 415931dca7dSgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 416931dca7dSgs150176 mutex_exit(bgep->send[ring].tx_lock); 41762387023Sdduvall rw_exit(bgep->errlock); 41862387023Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; ) 41962387023Sdduvall mutex_exit(bgep->buff[ring].rf_lock); 42062387023Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; ) 42162387023Sdduvall mutex_exit(bgep->recv[ring].rx_lock); 42262387023Sdduvall 42362387023Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep)); 42400d0963fSdilpreet return (retval); 42562387023Sdduvall } 42662387023Sdduvall 42762387023Sdduvall /* 42862387023Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings 42962387023Sdduvall */ 43062387023Sdduvall static void 43162387023Sdduvall bge_stop(bge_t *bgep) 43262387023Sdduvall { 43362387023Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep)); 43462387023Sdduvall 43562387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 43662387023Sdduvall 43767f02347Srandyf #ifdef BGE_IPMI_ASF 43867f02347Srandyf if (bgep->asf_enabled) { 43967f02347Srandyf bgep->asf_pseudostop = B_TRUE; 44067f02347Srandyf } else { 44167f02347Srandyf #endif 44262387023Sdduvall bge_chip_stop(bgep, B_FALSE); 44367f02347Srandyf #ifdef BGE_IPMI_ASF 44467f02347Srandyf } 44567f02347Srandyf #endif 44662387023Sdduvall 44762387023Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep)); 44862387023Sdduvall } 44962387023Sdduvall 45062387023Sdduvall /* 45162387023Sdduvall * bge_start() -- start transmitting/receiving 45262387023Sdduvall */ 45300d0963fSdilpreet static int 45462387023Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys) 45562387023Sdduvall { 45600d0963fSdilpreet int retval; 45700d0963fSdilpreet 45862387023Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys)); 45962387023Sdduvall 46062387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 46162387023Sdduvall 46262387023Sdduvall /* 46362387023Sdduvall * Start chip processing, including enabling interrupts 46462387023Sdduvall */ 46500d0963fSdilpreet retval = bge_chip_start(bgep, reset_phys); 46662387023Sdduvall 46762387023Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys)); 46800d0963fSdilpreet return (retval); 46962387023Sdduvall } 47062387023Sdduvall 47162387023Sdduvall /* 47262387023Sdduvall * bge_restart - restart transmitting/receiving after error or suspend 47362387023Sdduvall */ 47400d0963fSdilpreet int 47562387023Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys) 47662387023Sdduvall { 47700d0963fSdilpreet int retval = DDI_SUCCESS; 47862387023Sdduvall ASSERT(mutex_owned(bgep->genlock)); 47962387023Sdduvall 48067f02347Srandyf #ifdef BGE_IPMI_ASF 48167f02347Srandyf if (bgep->asf_enabled) { 48200d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS) 48300d0963fSdilpreet retval = DDI_FAILURE; 48467f02347Srandyf } else 48500d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS) 48600d0963fSdilpreet retval = DDI_FAILURE; 48767f02347Srandyf #else 48800d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS) 48900d0963fSdilpreet retval = DDI_FAILURE; 49067f02347Srandyf #endif 491c77e0fa5Szh199473 if (bgep->bge_mac_state == BGE_MAC_STARTED) { 49200d0963fSdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS) 49300d0963fSdilpreet retval = DDI_FAILURE; 49462387023Sdduvall bgep->watchdog = 0; 495931dca7dSgs150176 ddi_trigger_softintr(bgep->drain_id); 49662387023Sdduvall } 49762387023Sdduvall 49862387023Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys)); 49900d0963fSdilpreet return (retval); 50062387023Sdduvall } 50162387023Sdduvall 50262387023Sdduvall 50362387023Sdduvall /* 50462387023Sdduvall * ========== Nemo-required management entry points ========== 50562387023Sdduvall */ 50662387023Sdduvall 50762387023Sdduvall #undef BGE_DBG 50862387023Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 50962387023Sdduvall 51062387023Sdduvall /* 51162387023Sdduvall * bge_m_stop() -- stop transmitting/receiving 51262387023Sdduvall */ 51362387023Sdduvall static void 51462387023Sdduvall bge_m_stop(void *arg) 51562387023Sdduvall { 51662387023Sdduvall bge_t *bgep = arg; /* private device info */ 517931dca7dSgs150176 send_ring_t *srp; 518931dca7dSgs150176 uint32_t ring; 51962387023Sdduvall 52062387023Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg)); 52162387023Sdduvall 52262387023Sdduvall /* 52362387023Sdduvall * Just stop processing, then record new GLD state 52462387023Sdduvall */ 52562387023Sdduvall mutex_enter(bgep->genlock); 52600d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 52700d0963fSdilpreet /* can happen during autorecovery */ 52827c3238fSyong tan - Sun Microsystems - Beijing China bgep->bge_chip_state = BGE_CHIP_STOPPED; 52927c3238fSyong tan - Sun Microsystems - Beijing China } else 53062387023Sdduvall bge_stop(bgep); 531dca582a1Sgh162552 532dca582a1Sgh162552 bgep->link_state = LINK_STATE_UNKNOWN; 533dca582a1Sgh162552 mac_link_update(bgep->mh, bgep->link_state); 534dca582a1Sgh162552 535931dca7dSgs150176 /* 536931dca7dSgs150176 * Free the possible tx buffers allocated in tx process. 537931dca7dSgs150176 */ 538931dca7dSgs150176 #ifdef BGE_IPMI_ASF 539931dca7dSgs150176 if (!bgep->asf_pseudostop) 540931dca7dSgs150176 #endif 541931dca7dSgs150176 { 542931dca7dSgs150176 rw_enter(bgep->errlock, RW_WRITER); 543931dca7dSgs150176 for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) { 544931dca7dSgs150176 srp = &bgep->send[ring]; 545931dca7dSgs150176 mutex_enter(srp->tx_lock); 546931dca7dSgs150176 if (srp->tx_array > 1) 547931dca7dSgs150176 bge_free_txbuf_arrays(srp); 548931dca7dSgs150176 mutex_exit(srp->tx_lock); 549931dca7dSgs150176 } 550931dca7dSgs150176 rw_exit(bgep->errlock); 551931dca7dSgs150176 } 55262387023Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED; 55362387023Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg)); 55400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 55500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 55662387023Sdduvall mutex_exit(bgep->genlock); 55762387023Sdduvall } 55862387023Sdduvall 55962387023Sdduvall /* 56062387023Sdduvall * bge_m_start() -- start transmitting/receiving 56162387023Sdduvall */ 56262387023Sdduvall static int 56362387023Sdduvall bge_m_start(void *arg) 56462387023Sdduvall { 56562387023Sdduvall bge_t *bgep = arg; /* private device info */ 56662387023Sdduvall 56762387023Sdduvall BGE_TRACE(("bge_m_start($%p)", arg)); 56862387023Sdduvall 56962387023Sdduvall /* 57062387023Sdduvall * Start processing and record new GLD state 57162387023Sdduvall */ 57262387023Sdduvall mutex_enter(bgep->genlock); 57300d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 57400d0963fSdilpreet /* can happen during autorecovery */ 57500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 57600d0963fSdilpreet mutex_exit(bgep->genlock); 57700d0963fSdilpreet return (EIO); 57800d0963fSdilpreet } 57967f02347Srandyf #ifdef BGE_IPMI_ASF 58067f02347Srandyf if (bgep->asf_enabled) { 58167f02347Srandyf if ((bgep->asf_status == ASF_STAT_RUN) && 58267f02347Srandyf (bgep->asf_pseudostop)) { 58367f02347Srandyf bgep->bge_mac_state = BGE_MAC_STARTED; 584087a28d1SDavid Gwynne /* forcing a mac link update here */ 585087a28d1SDavid Gwynne bge_phys_check(bgep); 586087a28d1SDavid Gwynne bgep->link_state = (bgep->param_link_up) ? LINK_STATE_UP : 587087a28d1SDavid Gwynne LINK_STATE_DOWN; 588087a28d1SDavid Gwynne mac_link_update(bgep->mh, bgep->link_state); 58967f02347Srandyf mutex_exit(bgep->genlock); 59067f02347Srandyf return (0); 59167f02347Srandyf } 59267f02347Srandyf } 59300d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 59467f02347Srandyf #else 59500d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 59667f02347Srandyf #endif 59700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 59800d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 59900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 60000d0963fSdilpreet mutex_exit(bgep->genlock); 60100d0963fSdilpreet return (EIO); 60200d0963fSdilpreet } 60300d0963fSdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) { 60400d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 60500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 60600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 60700d0963fSdilpreet mutex_exit(bgep->genlock); 60800d0963fSdilpreet return (EIO); 60900d0963fSdilpreet } 6106adbf114Syong tan - Sun Microsystems - Beijing China bgep->watchdog = 0; 61162387023Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 61262387023Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 61367f02347Srandyf 61400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 61500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 61600d0963fSdilpreet mutex_exit(bgep->genlock); 61700d0963fSdilpreet return (EIO); 61800d0963fSdilpreet } 61900d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 62000d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 62100d0963fSdilpreet mutex_exit(bgep->genlock); 62200d0963fSdilpreet return (EIO); 62300d0963fSdilpreet } 62467f02347Srandyf #ifdef BGE_IPMI_ASF 62567f02347Srandyf if (bgep->asf_enabled) { 62667f02347Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 62767f02347Srandyf /* start ASF heart beat */ 62867f02347Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 62967f02347Srandyf (void *)bgep, 63067f02347Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 63167f02347Srandyf bgep->asf_status = ASF_STAT_RUN; 63267f02347Srandyf } 63367f02347Srandyf } 63467f02347Srandyf #endif 63562387023Sdduvall mutex_exit(bgep->genlock); 63662387023Sdduvall 63762387023Sdduvall return (0); 63862387023Sdduvall } 63962387023Sdduvall 64062387023Sdduvall /* 641ed8845d8Skrgopi * bge_unicst_set() -- set the physical network address 642ed8845d8Skrgopi */ 643ed8845d8Skrgopi static int 644da14cebeSEric Cheng bge_unicst_set(void *arg, const uint8_t *macaddr, int slot) 645ed8845d8Skrgopi { 64662387023Sdduvall bge_t *bgep = arg; /* private device info */ 64762387023Sdduvall 648087a28d1SDavid Gwynne BGE_TRACE(("bge_unicst_set($%p, %s)", arg, 64962387023Sdduvall ether_sprintf((void *)macaddr))); 65062387023Sdduvall /* 65162387023Sdduvall * Remember the new current address in the driver state 65262387023Sdduvall * Sync the chip's idea of the address too ... 65362387023Sdduvall */ 65462387023Sdduvall mutex_enter(bgep->genlock); 65500d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 65600d0963fSdilpreet /* can happen during autorecovery */ 65700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 65800d0963fSdilpreet mutex_exit(bgep->genlock); 65900d0963fSdilpreet return (EIO); 66000d0963fSdilpreet } 661ed8845d8Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr); 66267f02347Srandyf #ifdef BGE_IPMI_ASF 66300d0963fSdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 66400d0963fSdilpreet #else 66500d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 66600d0963fSdilpreet #endif 66700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 66800d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 66900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 67000d0963fSdilpreet mutex_exit(bgep->genlock); 67100d0963fSdilpreet return (EIO); 67200d0963fSdilpreet } 67300d0963fSdilpreet #ifdef BGE_IPMI_ASF 67467f02347Srandyf if (bgep->asf_enabled) { 67567f02347Srandyf /* 67667f02347Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 67767f02347Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 67867f02347Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 67967f02347Srandyf */ 68067f02347Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 68167f02347Srandyf /* 68267f02347Srandyf * We must stop ASF heart beat before bge_chip_stop(), 68367f02347Srandyf * otherwise some computers (ex. IBM HS20 blade server) 68467f02347Srandyf * may crash. 68567f02347Srandyf */ 68667f02347Srandyf bge_asf_update_status(bgep); 68767f02347Srandyf bge_asf_stop_timer(bgep); 68867f02347Srandyf bgep->asf_status = ASF_STAT_STOP; 68967f02347Srandyf 69067f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 69167f02347Srandyf } 69200d0963fSdilpreet bge_chip_stop(bgep, B_FALSE); 69367f02347Srandyf 69400d0963fSdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 69500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 69600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 69700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 69800d0963fSdilpreet DDI_SERVICE_DEGRADED); 69900d0963fSdilpreet mutex_exit(bgep->genlock); 70000d0963fSdilpreet return (EIO); 70100d0963fSdilpreet } 70200d0963fSdilpreet 70367f02347Srandyf /* 70467f02347Srandyf * Start our ASF heartbeat counter as soon as possible. 70567f02347Srandyf */ 70667f02347Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 70767f02347Srandyf /* start ASF heart beat */ 70867f02347Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 70967f02347Srandyf (void *)bgep, 71067f02347Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 71167f02347Srandyf bgep->asf_status = ASF_STAT_RUN; 71267f02347Srandyf } 71367f02347Srandyf } 71467f02347Srandyf #endif 715087a28d1SDavid Gwynne BGE_DEBUG(("bge_unicst_set($%p) done", arg)); 71600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 71700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 71800d0963fSdilpreet mutex_exit(bgep->genlock); 71900d0963fSdilpreet return (EIO); 72000d0963fSdilpreet } 72100d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 72200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 72300d0963fSdilpreet mutex_exit(bgep->genlock); 72400d0963fSdilpreet return (EIO); 72500d0963fSdilpreet } 72662387023Sdduvall mutex_exit(bgep->genlock); 72762387023Sdduvall 72862387023Sdduvall return (0); 72962387023Sdduvall } 73062387023Sdduvall 731e7801d59Ssowmini extern void bge_wake_factotum(bge_t *); 732e7801d59Ssowmini 733e7801d59Ssowmini static boolean_t 734e7801d59Ssowmini bge_param_locked(mac_prop_id_t pr_num) 735e7801d59Ssowmini { 736e7801d59Ssowmini /* 737e7801d59Ssowmini * All adv_* parameters are locked (read-only) while 738e7801d59Ssowmini * the device is in any sort of loopback mode ... 739e7801d59Ssowmini */ 740e7801d59Ssowmini switch (pr_num) { 7413fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 7423fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 7433fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 7443fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 7453fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 7463fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 7473fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 7483fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 7493fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 7503fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 7513fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 7523fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 7533fd94f8cSam223141 case MAC_PROP_AUTONEG: 7543fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 755e7801d59Ssowmini return (B_TRUE); 756e7801d59Ssowmini } 757e7801d59Ssowmini return (B_FALSE); 758e7801d59Ssowmini } 759e7801d59Ssowmini /* 760e7801d59Ssowmini * callback functions for set/get of properties 761e7801d59Ssowmini */ 762e7801d59Ssowmini static int 763e7801d59Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 764e7801d59Ssowmini uint_t pr_valsize, const void *pr_val) 765e7801d59Ssowmini { 766e7801d59Ssowmini bge_t *bgep = barg; 767e7801d59Ssowmini int err = 0; 7684045d941Ssowmini uint32_t cur_mtu, new_mtu; 769e7801d59Ssowmini link_flowctrl_t fl; 770e7801d59Ssowmini 771e7801d59Ssowmini mutex_enter(bgep->genlock); 772e7801d59Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE && 773e7801d59Ssowmini bge_param_locked(pr_num)) { 774e7801d59Ssowmini /* 775e7801d59Ssowmini * All adv_* parameters are locked (read-only) 776e7801d59Ssowmini * while the device is in any sort of loopback mode. 777e7801d59Ssowmini */ 778e7801d59Ssowmini mutex_exit(bgep->genlock); 779e7801d59Ssowmini return (EBUSY); 780e7801d59Ssowmini } 7814045d941Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 7823fd94f8cSam223141 ((pr_num == MAC_PROP_EN_100FDX_CAP) || 783afdda45fSVasumathi Sundaram - Sun Microsystems (pr_num == MAC_PROP_EN_100HDX_CAP) || 7843fd94f8cSam223141 (pr_num == MAC_PROP_EN_10FDX_CAP) || 7853fd94f8cSam223141 (pr_num == MAC_PROP_EN_10HDX_CAP))) { 7864045d941Ssowmini /* 7874045d941Ssowmini * these properties are read/write on copper, 7884045d941Ssowmini * read-only and 0 on serdes 7894045d941Ssowmini */ 7904045d941Ssowmini mutex_exit(bgep->genlock); 7914045d941Ssowmini return (ENOTSUP); 7924045d941Ssowmini } 79327c3238fSyong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep) && 79427c3238fSyong tan - Sun Microsystems - Beijing China ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 7955a506a18Syong tan - Sun Microsystems - Beijing China (pr_num == MAC_PROP_EN_1000HDX_CAP))) { 7965a506a18Syong tan - Sun Microsystems - Beijing China mutex_exit(bgep->genlock); 7975a506a18Syong tan - Sun Microsystems - Beijing China return (ENOTSUP); 7985a506a18Syong tan - Sun Microsystems - Beijing China } 7994045d941Ssowmini 800e7801d59Ssowmini switch (pr_num) { 8013fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 802e7801d59Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val; 803e7801d59Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val; 804e7801d59Ssowmini goto reprogram; 8053fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 806e7801d59Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val; 807e7801d59Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val; 808e7801d59Ssowmini goto reprogram; 8093fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 810e7801d59Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val; 811e7801d59Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val; 812e7801d59Ssowmini goto reprogram; 8133fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 814e7801d59Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val; 815e7801d59Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val; 816e7801d59Ssowmini goto reprogram; 8173fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 818e7801d59Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val; 819e7801d59Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val; 820e7801d59Ssowmini goto reprogram; 8213fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 822e7801d59Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val; 823e7801d59Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val; 824e7801d59Ssowmini reprogram: 825e7801d59Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) 826e7801d59Ssowmini err = EINVAL; 827e7801d59Ssowmini break; 8283fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 8293fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 8303fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 8313fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 8323fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 8333fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 8343fd94f8cSam223141 case MAC_PROP_STATUS: 8353fd94f8cSam223141 case MAC_PROP_SPEED: 8363fd94f8cSam223141 case MAC_PROP_DUPLEX: 8374045d941Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */ 838e7801d59Ssowmini break; 8393fd94f8cSam223141 case MAC_PROP_AUTONEG: 840e7801d59Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val; 841e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 842e7801d59Ssowmini err = EINVAL; 843e7801d59Ssowmini break; 8443fd94f8cSam223141 case MAC_PROP_MTU: 845e7801d59Ssowmini cur_mtu = bgep->chipid.default_mtu; 846e7801d59Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 8474045d941Ssowmini 848e7801d59Ssowmini if (new_mtu == cur_mtu) { 849e7801d59Ssowmini err = 0; 850e7801d59Ssowmini break; 851e7801d59Ssowmini } 852e7801d59Ssowmini if (new_mtu < BGE_DEFAULT_MTU || 853e7801d59Ssowmini new_mtu > BGE_MAXIMUM_MTU) { 854e7801d59Ssowmini err = EINVAL; 855e7801d59Ssowmini break; 856e7801d59Ssowmini } 857e7801d59Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) && 858e7801d59Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { 859e7801d59Ssowmini err = EINVAL; 860e7801d59Ssowmini break; 861e7801d59Ssowmini } 862e7801d59Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) { 863e7801d59Ssowmini err = EBUSY; 864e7801d59Ssowmini break; 865e7801d59Ssowmini } 866e7801d59Ssowmini bgep->chipid.default_mtu = new_mtu; 867e7801d59Ssowmini if (bge_chip_id_init(bgep)) { 868e7801d59Ssowmini err = EINVAL; 869e7801d59Ssowmini break; 870e7801d59Ssowmini } 871e7801d59Ssowmini bgep->bge_dma_error = B_TRUE; 872e7801d59Ssowmini bgep->manual_reset = B_TRUE; 873e7801d59Ssowmini bge_chip_stop(bgep, B_TRUE); 874e7801d59Ssowmini bge_wake_factotum(bgep); 875e7801d59Ssowmini err = 0; 876e7801d59Ssowmini break; 8773fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 878e7801d59Ssowmini bcopy(pr_val, &fl, sizeof (fl)); 879e7801d59Ssowmini switch (fl) { 880e7801d59Ssowmini default: 8814045d941Ssowmini err = ENOTSUP; 882e7801d59Ssowmini break; 883e7801d59Ssowmini case LINK_FLOWCTRL_NONE: 884e7801d59Ssowmini bgep->param_adv_pause = 0; 885e7801d59Ssowmini bgep->param_adv_asym_pause = 0; 886e7801d59Ssowmini 887e7801d59Ssowmini bgep->param_link_rx_pause = B_FALSE; 888e7801d59Ssowmini bgep->param_link_tx_pause = B_FALSE; 889e7801d59Ssowmini break; 890e7801d59Ssowmini case LINK_FLOWCTRL_RX: 891e7801d59Ssowmini bgep->param_adv_pause = 1; 892e7801d59Ssowmini bgep->param_adv_asym_pause = 1; 893e7801d59Ssowmini 894e7801d59Ssowmini bgep->param_link_rx_pause = B_TRUE; 895e7801d59Ssowmini bgep->param_link_tx_pause = B_FALSE; 896e7801d59Ssowmini break; 897e7801d59Ssowmini case LINK_FLOWCTRL_TX: 898e7801d59Ssowmini bgep->param_adv_pause = 0; 899e7801d59Ssowmini bgep->param_adv_asym_pause = 1; 900e7801d59Ssowmini 901e7801d59Ssowmini bgep->param_link_rx_pause = B_FALSE; 902e7801d59Ssowmini bgep->param_link_tx_pause = B_TRUE; 903e7801d59Ssowmini break; 904e7801d59Ssowmini case LINK_FLOWCTRL_BI: 905e7801d59Ssowmini bgep->param_adv_pause = 1; 90627c3238fSyong tan - Sun Microsystems - Beijing China bgep->param_adv_asym_pause = 0; 907e7801d59Ssowmini 908e7801d59Ssowmini bgep->param_link_rx_pause = B_TRUE; 909e7801d59Ssowmini bgep->param_link_tx_pause = B_TRUE; 910e7801d59Ssowmini break; 911e7801d59Ssowmini } 912e7801d59Ssowmini 913e7801d59Ssowmini if (err == 0) { 914e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 915e7801d59Ssowmini err = EINVAL; 916e7801d59Ssowmini } 917e7801d59Ssowmini 918e7801d59Ssowmini break; 9193fd94f8cSam223141 case MAC_PROP_PRIVATE: 920e7801d59Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize, 921e7801d59Ssowmini pr_val); 922e7801d59Ssowmini break; 9234045d941Ssowmini default: 9244045d941Ssowmini err = ENOTSUP; 9254045d941Ssowmini break; 926e7801d59Ssowmini } 927e7801d59Ssowmini mutex_exit(bgep->genlock); 928e7801d59Ssowmini return (err); 929e7801d59Ssowmini } 9304045d941Ssowmini 931afdda45fSVasumathi Sundaram - Sun Microsystems /* ARGSUSED */ 932e7801d59Ssowmini static int 933e7801d59Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 9340dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 935e7801d59Ssowmini { 936e7801d59Ssowmini bge_t *bgep = barg; 937e7801d59Ssowmini int err = 0; 938afdda45fSVasumathi Sundaram - Sun Microsystems 939e7801d59Ssowmini switch (pr_num) { 9403fd94f8cSam223141 case MAC_PROP_DUPLEX: 9410dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_duplex_t)); 9424045d941Ssowmini bcopy(&bgep->param_link_duplex, pr_val, 9434045d941Ssowmini sizeof (link_duplex_t)); 944e7801d59Ssowmini break; 9450dc2366fSVenugopal Iyer case MAC_PROP_SPEED: { 9460dc2366fSVenugopal Iyer uint64_t speed = bgep->param_link_speed * 1000000ull; 9470dc2366fSVenugopal Iyer 9480dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (speed)); 9494045d941Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 950e7801d59Ssowmini break; 9510dc2366fSVenugopal Iyer } 9523fd94f8cSam223141 case MAC_PROP_STATUS: 9530dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_state_t)); 9544045d941Ssowmini bcopy(&bgep->link_state, pr_val, 9554045d941Ssowmini sizeof (link_state_t)); 956e7801d59Ssowmini break; 9573fd94f8cSam223141 case MAC_PROP_AUTONEG: 958e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg; 959e7801d59Ssowmini break; 9600dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: { 9610dc2366fSVenugopal Iyer link_flowctrl_t fl; 9620dc2366fSVenugopal Iyer 9630dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (fl)); 9644045d941Ssowmini 965e7801d59Ssowmini if (bgep->param_link_rx_pause && 966e7801d59Ssowmini !bgep->param_link_tx_pause) 967e7801d59Ssowmini fl = LINK_FLOWCTRL_RX; 968e7801d59Ssowmini 969e7801d59Ssowmini if (!bgep->param_link_rx_pause && 970e7801d59Ssowmini !bgep->param_link_tx_pause) 971e7801d59Ssowmini fl = LINK_FLOWCTRL_NONE; 972e7801d59Ssowmini 973e7801d59Ssowmini if (!bgep->param_link_rx_pause && 974e7801d59Ssowmini bgep->param_link_tx_pause) 975e7801d59Ssowmini fl = LINK_FLOWCTRL_TX; 976e7801d59Ssowmini 977e7801d59Ssowmini if (bgep->param_link_rx_pause && 978e7801d59Ssowmini bgep->param_link_tx_pause) 979e7801d59Ssowmini fl = LINK_FLOWCTRL_BI; 980e7801d59Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 981e7801d59Ssowmini break; 9825a506a18Syong tan - Sun Microsystems - Beijing China } 9830dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP: 984e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx; 985e7801d59Ssowmini break; 9863fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 987e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx; 988e7801d59Ssowmini break; 9893fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 990e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx; 991e7801d59Ssowmini break; 9923fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 993e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx; 994e7801d59Ssowmini break; 9953fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 996e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx; 997e7801d59Ssowmini break; 9983fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 999e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx; 1000e7801d59Ssowmini break; 10013fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 1002e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx; 1003e7801d59Ssowmini break; 10043fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 1005e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx; 1006e7801d59Ssowmini break; 10073fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 1008e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx; 1009e7801d59Ssowmini break; 10103fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 1011e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx; 1012e7801d59Ssowmini break; 10133fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 1014e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx; 1015e7801d59Ssowmini break; 10163fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 1017e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx; 1018e7801d59Ssowmini break; 10193fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP: 10203fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP: 10214045d941Ssowmini *(uint8_t *)pr_val = 0; 10224045d941Ssowmini break; 10233fd94f8cSam223141 case MAC_PROP_PRIVATE: 10240dc2366fSVenugopal Iyer err = bge_get_priv_prop(bgep, pr_name, 10254045d941Ssowmini pr_valsize, pr_val); 1026e7801d59Ssowmini return (err); 10274045d941Ssowmini default: 10284045d941Ssowmini return (ENOTSUP); 1029e7801d59Ssowmini } 1030e7801d59Ssowmini return (0); 1031e7801d59Ssowmini } 1032e7801d59Ssowmini 10330dc2366fSVenugopal Iyer static void 10340dc2366fSVenugopal Iyer bge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num, 10350dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 10360dc2366fSVenugopal Iyer { 10370dc2366fSVenugopal Iyer bge_t *bgep = barg; 10380dc2366fSVenugopal Iyer int flags = bgep->chipid.flags; 10390dc2366fSVenugopal Iyer 10400dc2366fSVenugopal Iyer /* 10410dc2366fSVenugopal Iyer * By default permissions are read/write unless specified 10420dc2366fSVenugopal Iyer * otherwise by the driver. 10430dc2366fSVenugopal Iyer */ 10440dc2366fSVenugopal Iyer 10450dc2366fSVenugopal Iyer switch (pr_num) { 10460dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX: 10470dc2366fSVenugopal Iyer case MAC_PROP_SPEED: 10480dc2366fSVenugopal Iyer case MAC_PROP_STATUS: 10490dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP: 10500dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP: 10510dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP: 10520dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP: 10530dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP: 10540dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP: 10550dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP: 10560dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP: 10570dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 10580dc2366fSVenugopal Iyer break; 10590dc2366fSVenugopal Iyer 10600dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP: 10610dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP: 10620dc2366fSVenugopal Iyer if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 10630dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 0); 10640dc2366fSVenugopal Iyer else 10650dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1); 10660dc2366fSVenugopal Iyer break; 10670dc2366fSVenugopal Iyer 10680dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP: 10690dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP: 10700dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP: 10710dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP: 10720dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 10730dc2366fSVenugopal Iyer (flags & CHIP_FLAG_SERDES) ? 0 : 1); 10740dc2366fSVenugopal Iyer break; 10750dc2366fSVenugopal Iyer 10760dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG: 10770dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1); 10780dc2366fSVenugopal Iyer break; 10790dc2366fSVenugopal Iyer 10800dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: 10810dc2366fSVenugopal Iyer mac_prop_info_set_default_link_flowctrl(prh, 10820dc2366fSVenugopal Iyer LINK_FLOWCTRL_BI); 10830dc2366fSVenugopal Iyer break; 10840dc2366fSVenugopal Iyer 10850dc2366fSVenugopal Iyer case MAC_PROP_MTU: 10860dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, BGE_DEFAULT_MTU, 10870dc2366fSVenugopal Iyer (flags & CHIP_FLAG_NO_JUMBO) ? 10880dc2366fSVenugopal Iyer BGE_DEFAULT_MTU : BGE_MAXIMUM_MTU); 10890dc2366fSVenugopal Iyer break; 10900dc2366fSVenugopal Iyer 10910dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE: 10920dc2366fSVenugopal Iyer bge_priv_propinfo(pr_name, prh); 10930dc2366fSVenugopal Iyer break; 10940dc2366fSVenugopal Iyer } 10950dc2366fSVenugopal Iyer 10960dc2366fSVenugopal Iyer mutex_enter(bgep->genlock); 10970dc2366fSVenugopal Iyer if ((bgep->param_loop_mode != BGE_LOOP_NONE && 10980dc2366fSVenugopal Iyer bge_param_locked(pr_num)) || 10990dc2366fSVenugopal Iyer ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 11000dc2366fSVenugopal Iyer ((pr_num == MAC_PROP_EN_100FDX_CAP) || 11010dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_100HDX_CAP) || 11020dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_10FDX_CAP) || 11030dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_10HDX_CAP))) || 11040dc2366fSVenugopal Iyer (DEVICE_5906_SERIES_CHIPSETS(bgep) && 11050dc2366fSVenugopal Iyer ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 11060dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_1000HDX_CAP)))) 11070dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 11080dc2366fSVenugopal Iyer mutex_exit(bgep->genlock); 11090dc2366fSVenugopal Iyer } 11100dc2366fSVenugopal Iyer 1111e7801d59Ssowmini /* ARGSUSED */ 1112e7801d59Ssowmini static int 1113e7801d59Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, 1114e7801d59Ssowmini const void *pr_val) 1115e7801d59Ssowmini { 1116e7801d59Ssowmini int err = 0; 1117e7801d59Ssowmini long result; 1118e7801d59Ssowmini 11194045d941Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 11204045d941Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11214045d941Ssowmini if (result > 1 || result < 0) { 11224045d941Ssowmini err = EINVAL; 11234045d941Ssowmini } else { 11244a06b59fSyt223700 bgep->param_adv_pause = (uint32_t)result; 11254045d941Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11264045d941Ssowmini err = EINVAL; 11274045d941Ssowmini } 11284045d941Ssowmini return (err); 11294045d941Ssowmini } 11304045d941Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 11314045d941Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11324045d941Ssowmini if (result > 1 || result < 0) { 11334045d941Ssowmini err = EINVAL; 11344045d941Ssowmini } else { 11354a06b59fSyt223700 bgep->param_adv_asym_pause = (uint32_t)result; 11364045d941Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11374045d941Ssowmini err = EINVAL; 11384045d941Ssowmini } 11394045d941Ssowmini return (err); 11404045d941Ssowmini } 1141e7801d59Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 1142e7801d59Ssowmini 1143e7801d59Ssowmini /* 1144e7801d59Ssowmini * on the Tx side, we need to update the h/w register for 1145e7801d59Ssowmini * real packet transmission per packet. The drain_max parameter 1146e7801d59Ssowmini * is used to reduce the register access. This parameter 1147e7801d59Ssowmini * controls the max number of packets that we will hold before 1148e7801d59Ssowmini * updating the bge h/w to trigger h/w transmit. The bge 1149e7801d59Ssowmini * chipset usually has a max of 512 Tx descriptors, thus 1150e7801d59Ssowmini * the upper bound on drain_max is 512. 1151e7801d59Ssowmini */ 1152e7801d59Ssowmini if (pr_val == NULL) { 1153e7801d59Ssowmini err = EINVAL; 1154e7801d59Ssowmini return (err); 1155e7801d59Ssowmini } 1156e7801d59Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 1157e7801d59Ssowmini if (result > 512 || result < 1) 1158e7801d59Ssowmini err = EINVAL; 1159e7801d59Ssowmini else { 1160e7801d59Ssowmini bgep->param_drain_max = (uint32_t)result; 1161e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 1162e7801d59Ssowmini err = EINVAL; 1163e7801d59Ssowmini } 1164e7801d59Ssowmini return (err); 1165e7801d59Ssowmini } 1166e7801d59Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 1167e7801d59Ssowmini 1168e7801d59Ssowmini if (pr_val == NULL) { 1169e7801d59Ssowmini err = EINVAL; 1170e7801d59Ssowmini return (err); 1171e7801d59Ssowmini } 1172e7801d59Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 1173e7801d59Ssowmini if (result > 7 || result < 0) 1174e7801d59Ssowmini err = EINVAL; 1175e7801d59Ssowmini else { 1176e7801d59Ssowmini bgep->param_msi_cnt = (uint32_t)result; 1177e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 1178e7801d59Ssowmini err = EINVAL; 1179e7801d59Ssowmini } 1180e7801d59Ssowmini return (err); 1181e7801d59Ssowmini } 11824d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0) { 11834045d941Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 1184e7801d59Ssowmini return (EINVAL); 11854d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0) 11864d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL; 11874d6eaea5Syong tan - Sun Microsystems - Beijing China else { 11884a06b59fSyt223700 bgep->chipid.rx_ticks_norm = (uint32_t)result; 11894d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep); 11904d6eaea5Syong tan - Sun Microsystems - Beijing China } 11914d6eaea5Syong tan - Sun Microsystems - Beijing China return (err); 1192e7801d59Ssowmini } 1193e7801d59Ssowmini 11944d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0) { 1195e7801d59Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 1196e7801d59Ssowmini return (EINVAL); 1197e7801d59Ssowmini 11984d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0) 11994d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL; 12004d6eaea5Syong tan - Sun Microsystems - Beijing China else { 12014a06b59fSyt223700 bgep->chipid.rx_count_norm = (uint32_t)result; 12024d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep); 12034d6eaea5Syong tan - Sun Microsystems - Beijing China } 12044d6eaea5Syong tan - Sun Microsystems - Beijing China return (err); 12054d6eaea5Syong tan - Sun Microsystems - Beijing China } 12064d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0) { 12074d6eaea5Syong tan - Sun Microsystems - Beijing China if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 12084d6eaea5Syong tan - Sun Microsystems - Beijing China return (EINVAL); 12094d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0) 12104d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL; 12114d6eaea5Syong tan - Sun Microsystems - Beijing China else { 12124d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_ticks_norm = (uint32_t)result; 12134d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep); 12144d6eaea5Syong tan - Sun Microsystems - Beijing China } 12154d6eaea5Syong tan - Sun Microsystems - Beijing China return (err); 12164d6eaea5Syong tan - Sun Microsystems - Beijing China } 12174d6eaea5Syong tan - Sun Microsystems - Beijing China 12184d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0) { 12194d6eaea5Syong tan - Sun Microsystems - Beijing China if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 12204d6eaea5Syong tan - Sun Microsystems - Beijing China return (EINVAL); 12214d6eaea5Syong tan - Sun Microsystems - Beijing China 12224d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0) 12234d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL; 12244d6eaea5Syong tan - Sun Microsystems - Beijing China else { 12254d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_count_norm = (uint32_t)result; 12264d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep); 12274d6eaea5Syong tan - Sun Microsystems - Beijing China } 12284d6eaea5Syong tan - Sun Microsystems - Beijing China return (err); 1229e7801d59Ssowmini } 12304045d941Ssowmini return (ENOTSUP); 1231e7801d59Ssowmini } 1232e7801d59Ssowmini 1233e7801d59Ssowmini static int 12340dc2366fSVenugopal Iyer bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_valsize, 12350dc2366fSVenugopal Iyer void *pr_val) 1236e7801d59Ssowmini { 12374045d941Ssowmini int value; 1238e7801d59Ssowmini 12390dc2366fSVenugopal Iyer if (strcmp(pr_name, "_adv_pause_cap") == 0) 12400dc2366fSVenugopal Iyer value = bge->param_adv_pause; 12410dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) 12420dc2366fSVenugopal Iyer value = bge->param_adv_asym_pause; 12430dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_drain_max") == 0) 12440dc2366fSVenugopal Iyer value = bge->param_drain_max; 12450dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_msi_cnt") == 0) 12460dc2366fSVenugopal Iyer value = bge->param_msi_cnt; 12470dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0) 12480dc2366fSVenugopal Iyer value = bge->chipid.rx_ticks_norm; 12490dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0) 12500dc2366fSVenugopal Iyer value = bge->chipid.tx_ticks_norm; 12510dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0) 12520dc2366fSVenugopal Iyer value = bge->chipid.rx_count_norm; 12530dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0) 12540dc2366fSVenugopal Iyer value = bge->chipid.tx_count_norm; 12550dc2366fSVenugopal Iyer else 12560dc2366fSVenugopal Iyer return (ENOTSUP); 1257e7801d59Ssowmini 12584045d941Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 12590dc2366fSVenugopal Iyer return (0); 12606b9e797cSsowmini } 12610dc2366fSVenugopal Iyer 12620dc2366fSVenugopal Iyer static void 12630dc2366fSVenugopal Iyer bge_priv_propinfo(const char *pr_name, mac_prop_info_handle_t mph) 12640dc2366fSVenugopal Iyer { 12650dc2366fSVenugopal Iyer char valstr[64]; 12660dc2366fSVenugopal Iyer int value; 12670dc2366fSVenugopal Iyer 12680dc2366fSVenugopal Iyer if (strcmp(pr_name, "_adv_pause_cap") == 0) 12690dc2366fSVenugopal Iyer value = 1; 12700dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) 12710dc2366fSVenugopal Iyer value = 1; 12720dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_drain_max") == 0) 12730dc2366fSVenugopal Iyer value = 64; 12740dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_msi_cnt") == 0) 12750dc2366fSVenugopal Iyer value = 0; 12760dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0) 12770dc2366fSVenugopal Iyer value = bge_rx_ticks_norm; 12780dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0) 12790dc2366fSVenugopal Iyer value = bge_tx_ticks_norm; 12800dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0) 12810dc2366fSVenugopal Iyer value = bge_rx_count_norm; 12820dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0) 12830dc2366fSVenugopal Iyer value = bge_tx_count_norm; 12840dc2366fSVenugopal Iyer else 12850dc2366fSVenugopal Iyer return; 12860dc2366fSVenugopal Iyer 12870dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", value); 12880dc2366fSVenugopal Iyer mac_prop_info_set_default_str(mph, valstr); 1289e7801d59Ssowmini } 1290e7801d59Ssowmini 1291087a28d1SDavid Gwynne 1292087a28d1SDavid Gwynne static int 1293087a28d1SDavid Gwynne bge_m_unicst(void * arg, const uint8_t * mac_addr) 1294087a28d1SDavid Gwynne { 1295087a28d1SDavid Gwynne bge_t *bgep = arg; 1296087a28d1SDavid Gwynne int i; 1297087a28d1SDavid Gwynne 1298087a28d1SDavid Gwynne /* XXX sets the mac address for all ring slots... OK? */ 1299087a28d1SDavid Gwynne for (i = 0; i < MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX); i++) 1300087a28d1SDavid Gwynne bge_addmac(&bgep->recv[i], mac_addr); 1301087a28d1SDavid Gwynne 1302087a28d1SDavid Gwynne return (0); 1303087a28d1SDavid Gwynne } 1304087a28d1SDavid Gwynne 1305087a28d1SDavid Gwynne 1306ed8845d8Skrgopi /* 130762387023Sdduvall * Compute the index of the required bit in the multicast hash map. 130862387023Sdduvall * This must mirror the way the hardware actually does it! 130962387023Sdduvall * See Broadcom document 570X-PG102-R page 125. 131062387023Sdduvall */ 131162387023Sdduvall static uint32_t 131262387023Sdduvall bge_hash_index(const uint8_t *mca) 131362387023Sdduvall { 131462387023Sdduvall uint32_t hash; 131562387023Sdduvall 131662387023Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 131762387023Sdduvall 131862387023Sdduvall return (hash); 131962387023Sdduvall } 132062387023Sdduvall 132162387023Sdduvall /* 132262387023Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 132362387023Sdduvall */ 132462387023Sdduvall static int 132562387023Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 132662387023Sdduvall { 132762387023Sdduvall bge_t *bgep = arg; /* private device info */ 132862387023Sdduvall uint32_t hash; 132962387023Sdduvall uint32_t index; 133062387023Sdduvall uint32_t word; 133162387023Sdduvall uint32_t bit; 133262387023Sdduvall uint8_t *refp; 133362387023Sdduvall 133462387023Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 133562387023Sdduvall (add) ? "add" : "remove", ether_sprintf((void *)mca))); 133662387023Sdduvall 133762387023Sdduvall /* 133862387023Sdduvall * Precalculate all required masks, pointers etc ... 133962387023Sdduvall */ 134062387023Sdduvall hash = bge_hash_index(mca); 134162387023Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 134262387023Sdduvall word = index/32u; 134362387023Sdduvall bit = 1 << (index % 32u); 134462387023Sdduvall refp = &bgep->mcast_refs[index]; 134562387023Sdduvall 134662387023Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 134762387023Sdduvall hash, index, word, bit, *refp)); 134862387023Sdduvall 134962387023Sdduvall /* 135062387023Sdduvall * We must set the appropriate bit in the hash map (and the 135162387023Sdduvall * corresponding h/w register) when the refcount goes from 0 135262387023Sdduvall * to >0, and clear it when the last ref goes away (refcount 135362387023Sdduvall * goes from >0 back to 0). If we change the hash map, we 135462387023Sdduvall * must also update the chip's hardware map registers. 135562387023Sdduvall */ 135662387023Sdduvall mutex_enter(bgep->genlock); 135700d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 135800d0963fSdilpreet /* can happen during autorecovery */ 135900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 136000d0963fSdilpreet mutex_exit(bgep->genlock); 136100d0963fSdilpreet return (EIO); 136200d0963fSdilpreet } 136362387023Sdduvall if (add) { 136462387023Sdduvall if ((*refp)++ == 0) { 136562387023Sdduvall bgep->mcast_hash[word] |= bit; 136667f02347Srandyf #ifdef BGE_IPMI_ASF 136700d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 136867f02347Srandyf #else 136900d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 137067f02347Srandyf #endif 137100d0963fSdilpreet (void) bge_check_acc_handle(bgep, 137200d0963fSdilpreet bgep->cfg_handle); 137300d0963fSdilpreet (void) bge_check_acc_handle(bgep, 137400d0963fSdilpreet bgep->io_handle); 137500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 137600d0963fSdilpreet DDI_SERVICE_DEGRADED); 137700d0963fSdilpreet mutex_exit(bgep->genlock); 137800d0963fSdilpreet return (EIO); 137900d0963fSdilpreet } 138062387023Sdduvall } 138162387023Sdduvall } else { 138262387023Sdduvall if (--(*refp) == 0) { 138362387023Sdduvall bgep->mcast_hash[word] &= ~bit; 138467f02347Srandyf #ifdef BGE_IPMI_ASF 138500d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 138667f02347Srandyf #else 138700d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 138867f02347Srandyf #endif 138900d0963fSdilpreet (void) bge_check_acc_handle(bgep, 139000d0963fSdilpreet bgep->cfg_handle); 139100d0963fSdilpreet (void) bge_check_acc_handle(bgep, 139200d0963fSdilpreet bgep->io_handle); 139300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 139400d0963fSdilpreet DDI_SERVICE_DEGRADED); 139500d0963fSdilpreet mutex_exit(bgep->genlock); 139600d0963fSdilpreet return (EIO); 139700d0963fSdilpreet } 139862387023Sdduvall } 139962387023Sdduvall } 140062387023Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 140100d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 140200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 140300d0963fSdilpreet mutex_exit(bgep->genlock); 140400d0963fSdilpreet return (EIO); 140500d0963fSdilpreet } 140600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 140700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 140800d0963fSdilpreet mutex_exit(bgep->genlock); 140900d0963fSdilpreet return (EIO); 141000d0963fSdilpreet } 141162387023Sdduvall mutex_exit(bgep->genlock); 141262387023Sdduvall 141362387023Sdduvall return (0); 141462387023Sdduvall } 141562387023Sdduvall 141662387023Sdduvall /* 141762387023Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 141862387023Sdduvall * 141962387023Sdduvall * Program the hardware to enable/disable promiscuous and/or 142062387023Sdduvall * receive-all-multicast modes. 142162387023Sdduvall */ 142262387023Sdduvall static int 142362387023Sdduvall bge_m_promisc(void *arg, boolean_t on) 142462387023Sdduvall { 142562387023Sdduvall bge_t *bgep = arg; 142662387023Sdduvall 142762387023Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 142862387023Sdduvall 142962387023Sdduvall /* 143062387023Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 143162387023Sdduvall */ 143262387023Sdduvall mutex_enter(bgep->genlock); 143300d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 143400d0963fSdilpreet /* can happen during autorecovery */ 143500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 143600d0963fSdilpreet mutex_exit(bgep->genlock); 143700d0963fSdilpreet return (EIO); 143800d0963fSdilpreet } 143962387023Sdduvall bgep->promisc = on; 144067f02347Srandyf #ifdef BGE_IPMI_ASF 144100d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 144267f02347Srandyf #else 144300d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 144467f02347Srandyf #endif 144500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 144600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 144700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 144800d0963fSdilpreet mutex_exit(bgep->genlock); 144900d0963fSdilpreet return (EIO); 145000d0963fSdilpreet } 145162387023Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 145200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 145300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 145400d0963fSdilpreet mutex_exit(bgep->genlock); 145500d0963fSdilpreet return (EIO); 145600d0963fSdilpreet } 145700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 145800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 145900d0963fSdilpreet mutex_exit(bgep->genlock); 146000d0963fSdilpreet return (EIO); 146100d0963fSdilpreet } 146262387023Sdduvall mutex_exit(bgep->genlock); 146362387023Sdduvall return (0); 146462387023Sdduvall } 146562387023Sdduvall 1466087a28d1SDavid Gwynne #ifdef MC_RESOURCES 1467087a28d1SDavid Gwynne 1468087a28d1SDavid Gwynne static void 1469087a28d1SDavid Gwynne bge_blank(void * arg, time_t tick_cnt, uint_t pkt_cnt) 1470087a28d1SDavid Gwynne { 1471087a28d1SDavid Gwynne (void)arg; 1472087a28d1SDavid Gwynne (void)tick_cnt; 1473087a28d1SDavid Gwynne (void)pkt_cnt; 1474087a28d1SDavid Gwynne } 1475087a28d1SDavid Gwynne 1476087a28d1SDavid Gwynne static void 1477087a28d1SDavid Gwynne bge_m_resources(void * arg) 1478087a28d1SDavid Gwynne { 1479087a28d1SDavid Gwynne bge_t *bgep = arg; 1480087a28d1SDavid Gwynne mac_rx_fifo_t mrf; 1481087a28d1SDavid Gwynne int i; 1482087a28d1SDavid Gwynne 1483087a28d1SDavid Gwynne mrf.mrf_type = MAC_RX_FIFO; 1484087a28d1SDavid Gwynne mrf.mrf_blank = bge_blank; 1485087a28d1SDavid Gwynne mrf.mrf_arg = (void *)bgep; 1486087a28d1SDavid Gwynne mrf.mrf_normal_blank_time = 25; 1487087a28d1SDavid Gwynne mrf.mrf_normal_pkt_count = 8; 1488087a28d1SDavid Gwynne 1489087a28d1SDavid Gwynne for (i = 0; i < BGE_RECV_RINGS_MAX; i++) { 1490087a28d1SDavid Gwynne bgep->macRxResourceHandles[i] = 1491087a28d1SDavid Gwynne mac_resource_add(bgep->mh, (mac_resource_t *)&mrf); 1492087a28d1SDavid Gwynne } 1493087a28d1SDavid Gwynne } 1494087a28d1SDavid Gwynne 1495087a28d1SDavid Gwynne #endif /* MC_RESOURCES */ 1496087a28d1SDavid Gwynne 1497da14cebeSEric Cheng /* 1498da14cebeSEric Cheng * Find the slot for the specified unicast address 1499da14cebeSEric Cheng */ 1500da14cebeSEric Cheng int 1501da14cebeSEric Cheng bge_unicst_find(bge_t *bgep, const uint8_t *mac_addr) 1502da14cebeSEric Cheng { 1503da14cebeSEric Cheng int slot; 1504da14cebeSEric Cheng 1505da14cebeSEric Cheng ASSERT(mutex_owned(bgep->genlock)); 1506da14cebeSEric Cheng 1507da14cebeSEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 1508da14cebeSEric Cheng if (bcmp(bgep->curr_addr[slot].addr, mac_addr, ETHERADDRL) == 0) 1509da14cebeSEric Cheng return (slot); 1510da14cebeSEric Cheng } 1511da14cebeSEric Cheng 1512da14cebeSEric Cheng return (-1); 1513da14cebeSEric Cheng } 1514da14cebeSEric Cheng 1515da14cebeSEric Cheng /* 1516da14cebeSEric Cheng * Programs the classifier to start steering packets matching 'mac_addr' to the 1517da14cebeSEric Cheng * specified ring 'arg'. 1518da14cebeSEric Cheng */ 1519da14cebeSEric Cheng static int 1520da14cebeSEric Cheng bge_addmac(void *arg, const uint8_t * mac_addr) 1521da14cebeSEric Cheng { 1522da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 1523da14cebeSEric Cheng bge_t *bgep = rrp->bgep; 1524da14cebeSEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 1525da14cebeSEric Cheng bge_rule_info_t *rinfop = NULL; 1526da14cebeSEric Cheng uint8_t ring = (uint8_t)(rrp - bgep->recv) + 1; 1527da14cebeSEric Cheng int i; 1528da14cebeSEric Cheng uint16_t tmp16; 1529da14cebeSEric Cheng uint32_t tmp32; 1530da14cebeSEric Cheng int slot; 1531da14cebeSEric Cheng int err; 1532da14cebeSEric Cheng 1533da14cebeSEric Cheng mutex_enter(bgep->genlock); 1534da14cebeSEric Cheng if (bgep->unicst_addr_avail == 0) { 1535da14cebeSEric Cheng mutex_exit(bgep->genlock); 1536da14cebeSEric Cheng return (ENOSPC); 1537da14cebeSEric Cheng } 1538da14cebeSEric Cheng 1539da14cebeSEric Cheng /* 1540da14cebeSEric Cheng * First add the unicast address to a available slot. 1541da14cebeSEric Cheng */ 1542da14cebeSEric Cheng slot = bge_unicst_find(bgep, mac_addr); 1543da14cebeSEric Cheng ASSERT(slot == -1); 1544da14cebeSEric Cheng 1545da14cebeSEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 1546da14cebeSEric Cheng if (!bgep->curr_addr[slot].set) { 1547da14cebeSEric Cheng bgep->curr_addr[slot].set = B_TRUE; 1548da14cebeSEric Cheng break; 1549da14cebeSEric Cheng } 1550da14cebeSEric Cheng } 1551da14cebeSEric Cheng 1552da14cebeSEric Cheng ASSERT(slot < bgep->unicst_addr_total); 1553da14cebeSEric Cheng bgep->unicst_addr_avail--; 1554da14cebeSEric Cheng mutex_exit(bgep->genlock); 1555da14cebeSEric Cheng 1556da14cebeSEric Cheng if ((err = bge_unicst_set(bgep, mac_addr, slot)) != 0) 1557da14cebeSEric Cheng goto fail; 1558da14cebeSEric Cheng 1559da14cebeSEric Cheng /* A rule is already here. Deny this. */ 1560da14cebeSEric Cheng if (rrp->mac_addr_rule != NULL) { 1561da14cebeSEric Cheng err = ether_cmp(mac_addr, rrp->mac_addr_val) ? EEXIST : EBUSY; 1562da14cebeSEric Cheng goto fail; 1563da14cebeSEric Cheng } 1564da14cebeSEric Cheng 1565da14cebeSEric Cheng /* 1566da14cebeSEric Cheng * Allocate a bge_rule_info_t to keep track of which rule slots 1567da14cebeSEric Cheng * are being used. 1568da14cebeSEric Cheng */ 1569da14cebeSEric Cheng rinfop = kmem_zalloc(sizeof (bge_rule_info_t), KM_NOSLEEP); 1570da14cebeSEric Cheng if (rinfop == NULL) { 1571da14cebeSEric Cheng err = ENOMEM; 1572da14cebeSEric Cheng goto fail; 1573da14cebeSEric Cheng } 1574da14cebeSEric Cheng 1575da14cebeSEric Cheng /* 1576da14cebeSEric Cheng * Look for the starting slot to place the rules. 1577da14cebeSEric Cheng * The two slots we reserve must be contiguous. 1578da14cebeSEric Cheng */ 1579da14cebeSEric Cheng for (i = 0; i + 1 < RECV_RULES_NUM_MAX; i++) 1580da14cebeSEric Cheng if ((rulep[i].control & RECV_RULE_CTL_ENABLE) == 0 && 1581da14cebeSEric Cheng (rulep[i+1].control & RECV_RULE_CTL_ENABLE) == 0) 1582da14cebeSEric Cheng break; 1583da14cebeSEric Cheng 1584da14cebeSEric Cheng ASSERT(i + 1 < RECV_RULES_NUM_MAX); 1585da14cebeSEric Cheng 1586da14cebeSEric Cheng bcopy(mac_addr, &tmp32, sizeof (tmp32)); 1587da14cebeSEric Cheng rulep[i].mask_value = ntohl(tmp32); 1588da14cebeSEric Cheng rulep[i].control = RULE_DEST_MAC_1(ring) | RECV_RULE_CTL_AND; 1589da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep[i].mask_value); 1590da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep[i].control); 1591da14cebeSEric Cheng 1592da14cebeSEric Cheng bcopy(mac_addr + 4, &tmp16, sizeof (tmp16)); 1593da14cebeSEric Cheng rulep[i+1].mask_value = 0xffff0000 | ntohs(tmp16); 1594da14cebeSEric Cheng rulep[i+1].control = RULE_DEST_MAC_2(ring); 1595da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i+1), rulep[i+1].mask_value); 1596da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i+1), rulep[i+1].control); 1597da14cebeSEric Cheng rinfop->start = i; 1598da14cebeSEric Cheng rinfop->count = 2; 1599da14cebeSEric Cheng 1600da14cebeSEric Cheng rrp->mac_addr_rule = rinfop; 1601da14cebeSEric Cheng bcopy(mac_addr, rrp->mac_addr_val, ETHERADDRL); 1602da14cebeSEric Cheng 1603da14cebeSEric Cheng return (0); 1604da14cebeSEric Cheng 1605da14cebeSEric Cheng fail: 1606da14cebeSEric Cheng /* Clear the address just set */ 1607da14cebeSEric Cheng (void) bge_unicst_set(bgep, zero_addr, slot); 1608da14cebeSEric Cheng mutex_enter(bgep->genlock); 1609da14cebeSEric Cheng bgep->curr_addr[slot].set = B_FALSE; 1610da14cebeSEric Cheng bgep->unicst_addr_avail++; 1611da14cebeSEric Cheng mutex_exit(bgep->genlock); 1612da14cebeSEric Cheng 1613da14cebeSEric Cheng return (err); 1614da14cebeSEric Cheng } 1615da14cebeSEric Cheng 1616da14cebeSEric Cheng /* 1617da14cebeSEric Cheng * Stop classifying packets matching the MAC address to the specified ring. 1618da14cebeSEric Cheng */ 1619da14cebeSEric Cheng static int 1620da14cebeSEric Cheng bge_remmac(void *arg, const uint8_t *mac_addr) 1621da14cebeSEric Cheng { 1622da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 1623da14cebeSEric Cheng bge_t *bgep = rrp->bgep; 1624da14cebeSEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 1625da14cebeSEric Cheng bge_rule_info_t *rinfop = rrp->mac_addr_rule; 1626da14cebeSEric Cheng int start; 1627da14cebeSEric Cheng int slot; 1628da14cebeSEric Cheng int err; 1629da14cebeSEric Cheng 1630da14cebeSEric Cheng /* 1631da14cebeSEric Cheng * Remove the MAC address from its slot. 1632da14cebeSEric Cheng */ 1633da14cebeSEric Cheng mutex_enter(bgep->genlock); 1634da14cebeSEric Cheng slot = bge_unicst_find(bgep, mac_addr); 1635da14cebeSEric Cheng if (slot == -1) { 1636da14cebeSEric Cheng mutex_exit(bgep->genlock); 1637da14cebeSEric Cheng return (EINVAL); 1638da14cebeSEric Cheng } 1639da14cebeSEric Cheng 1640da14cebeSEric Cheng ASSERT(bgep->curr_addr[slot].set); 1641da14cebeSEric Cheng mutex_exit(bgep->genlock); 1642da14cebeSEric Cheng 1643da14cebeSEric Cheng if ((err = bge_unicst_set(bgep, zero_addr, slot)) != 0) 1644da14cebeSEric Cheng return (err); 1645da14cebeSEric Cheng 1646da14cebeSEric Cheng if (rinfop == NULL || ether_cmp(mac_addr, rrp->mac_addr_val) != 0) 1647da14cebeSEric Cheng return (EINVAL); 1648da14cebeSEric Cheng 1649da14cebeSEric Cheng start = rinfop->start; 1650da14cebeSEric Cheng rulep[start].mask_value = 0; 1651da14cebeSEric Cheng rulep[start].control = 0; 1652da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 1653da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 1654da14cebeSEric Cheng start++; 1655da14cebeSEric Cheng rulep[start].mask_value = 0; 1656da14cebeSEric Cheng rulep[start].control = 0; 1657da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 1658da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 1659da14cebeSEric Cheng 1660da14cebeSEric Cheng kmem_free(rinfop, sizeof (bge_rule_info_t)); 1661da14cebeSEric Cheng rrp->mac_addr_rule = NULL; 1662da14cebeSEric Cheng bzero(rrp->mac_addr_val, ETHERADDRL); 1663da14cebeSEric Cheng 1664da14cebeSEric Cheng mutex_enter(bgep->genlock); 1665da14cebeSEric Cheng bgep->curr_addr[slot].set = B_FALSE; 1666da14cebeSEric Cheng bgep->unicst_addr_avail++; 1667da14cebeSEric Cheng mutex_exit(bgep->genlock); 1668da14cebeSEric Cheng 1669da14cebeSEric Cheng return (0); 1670da14cebeSEric Cheng } 1671da14cebeSEric Cheng 1672087a28d1SDavid Gwynne 1673da14cebeSEric Cheng static int 1674087a28d1SDavid Gwynne bge_flag_intr_enable(mac_ring_driver_t ih) 1675da14cebeSEric Cheng { 1676da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 1677da14cebeSEric Cheng bge_t *bgep = rrp->bgep; 1678da14cebeSEric Cheng 1679da14cebeSEric Cheng mutex_enter(bgep->genlock); 1680da14cebeSEric Cheng rrp->poll_flag = 0; 1681da14cebeSEric Cheng mutex_exit(bgep->genlock); 1682da14cebeSEric Cheng 1683da14cebeSEric Cheng return (0); 1684da14cebeSEric Cheng } 1685da14cebeSEric Cheng 1686da14cebeSEric Cheng static int 1687087a28d1SDavid Gwynne bge_flag_intr_disable(mac_ring_driver_t ih) 1688da14cebeSEric Cheng { 1689da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 1690da14cebeSEric Cheng bge_t *bgep = rrp->bgep; 1691da14cebeSEric Cheng 1692da14cebeSEric Cheng mutex_enter(bgep->genlock); 1693da14cebeSEric Cheng rrp->poll_flag = 1; 1694da14cebeSEric Cheng mutex_exit(bgep->genlock); 1695da14cebeSEric Cheng 1696da14cebeSEric Cheng return (0); 1697da14cebeSEric Cheng } 1698da14cebeSEric Cheng 1699da14cebeSEric Cheng static int 1700da14cebeSEric Cheng bge_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 1701da14cebeSEric Cheng { 1702da14cebeSEric Cheng recv_ring_t *rx_ring; 1703da14cebeSEric Cheng 1704da14cebeSEric Cheng rx_ring = (recv_ring_t *)rh; 1705da14cebeSEric Cheng mutex_enter(rx_ring->rx_lock); 1706da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num; 1707da14cebeSEric Cheng mutex_exit(rx_ring->rx_lock); 1708da14cebeSEric Cheng return (0); 1709da14cebeSEric Cheng } 1710da14cebeSEric Cheng 1711da14cebeSEric Cheng 1712da14cebeSEric Cheng /* 1713da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings 1714da14cebeSEric Cheng * for given ring_group, noted by rg_index. 1715da14cebeSEric Cheng */ 1716da14cebeSEric Cheng void 1717da14cebeSEric Cheng bge_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, 1718da14cebeSEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh) 1719da14cebeSEric Cheng { 1720da14cebeSEric Cheng bge_t *bgep = arg; 1721da14cebeSEric Cheng mac_intr_t *mintr; 1722da14cebeSEric Cheng 1723da14cebeSEric Cheng switch (rtype) { 1724da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 1725da14cebeSEric Cheng recv_ring_t *rx_ring; 1726da14cebeSEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 1727da14cebeSEric Cheng MAC_ADDRESS_REGS_MAX) && index == 0); 1728da14cebeSEric Cheng 1729da14cebeSEric Cheng rx_ring = &bgep->recv[rg_index]; 1730da14cebeSEric Cheng rx_ring->ring_handle = rh; 1731da14cebeSEric Cheng 1732da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 1733da14cebeSEric Cheng infop->mri_start = bge_ring_start; 1734da14cebeSEric Cheng infop->mri_stop = NULL; 1735da14cebeSEric Cheng infop->mri_poll = bge_poll_ring; 17360dc2366fSVenugopal Iyer infop->mri_stat = bge_rx_ring_stat; 1737da14cebeSEric Cheng 1738da14cebeSEric Cheng mintr = &infop->mri_intr; 1739087a28d1SDavid Gwynne mintr->mi_enable = (mac_intr_enable_t)bge_flag_intr_enable; 1740087a28d1SDavid Gwynne mintr->mi_disable = (mac_intr_disable_t)bge_flag_intr_disable; 1741da14cebeSEric Cheng 1742da14cebeSEric Cheng break; 1743da14cebeSEric Cheng } 1744da14cebeSEric Cheng case MAC_RING_TYPE_TX: 1745da14cebeSEric Cheng default: 1746da14cebeSEric Cheng ASSERT(0); 1747da14cebeSEric Cheng break; 1748da14cebeSEric Cheng } 1749da14cebeSEric Cheng } 1750da14cebeSEric Cheng 1751da14cebeSEric Cheng /* 1752da14cebeSEric Cheng * Fill infop passed as argument 1753da14cebeSEric Cheng * fill in respective ring_group info 1754da14cebeSEric Cheng * Each group has a single ring in it. We keep it simple 1755da14cebeSEric Cheng * and use the same internal handle for rings and groups. 1756da14cebeSEric Cheng */ 1757da14cebeSEric Cheng void 1758da14cebeSEric Cheng bge_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index, 1759da14cebeSEric Cheng mac_group_info_t * infop, mac_group_handle_t gh) 1760da14cebeSEric Cheng { 1761da14cebeSEric Cheng bge_t *bgep = arg; 1762da14cebeSEric Cheng 1763da14cebeSEric Cheng switch (rtype) { 1764da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 1765da14cebeSEric Cheng recv_ring_t *rx_ring; 1766da14cebeSEric Cheng 1767da14cebeSEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 1768da14cebeSEric Cheng MAC_ADDRESS_REGS_MAX)); 1769da14cebeSEric Cheng rx_ring = &bgep->recv[rg_index]; 1770da14cebeSEric Cheng rx_ring->ring_group_handle = gh; 1771da14cebeSEric Cheng 1772da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring; 1773da14cebeSEric Cheng infop->mgi_start = NULL; 1774da14cebeSEric Cheng infop->mgi_stop = NULL; 1775da14cebeSEric Cheng infop->mgi_addmac = bge_addmac; 1776da14cebeSEric Cheng infop->mgi_remmac = bge_remmac; 1777da14cebeSEric Cheng infop->mgi_count = 1; 1778da14cebeSEric Cheng break; 1779da14cebeSEric Cheng } 1780da14cebeSEric Cheng case MAC_RING_TYPE_TX: 1781da14cebeSEric Cheng default: 1782da14cebeSEric Cheng ASSERT(0); 1783da14cebeSEric Cheng break; 1784da14cebeSEric Cheng } 1785da14cebeSEric Cheng } 1786da14cebeSEric Cheng 1787087a28d1SDavid Gwynne 1788ba2e4443Sseb /*ARGSUSED*/ 1789ba2e4443Sseb static boolean_t 1790ba2e4443Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 1791ba2e4443Sseb { 1792ed8845d8Skrgopi bge_t *bgep = arg; 1793087a28d1SDavid Gwynne mac_capab_rings_t *cap_rings; 1794ed8845d8Skrgopi 1795ba2e4443Sseb switch (cap) { 1796ba2e4443Sseb case MAC_CAPAB_HCKSUM: { 1797ba2e4443Sseb uint32_t *txflags = cap_data; 1798ba2e4443Sseb 1799ba2e4443Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 1800ba2e4443Sseb break; 1801ba2e4443Sseb } 1802087a28d1SDavid Gwynne 1803087a28d1SDavid Gwynne case MAC_CAPAB_RINGS: 1804087a28d1SDavid Gwynne cap_rings = (mac_capab_rings_t *)cap_data; 1805ed8845d8Skrgopi 1806da14cebeSEric Cheng /* Temporarily disable multiple tx rings. */ 1807da14cebeSEric Cheng if (cap_rings->mr_type != MAC_RING_TYPE_RX) 1808da14cebeSEric Cheng return (B_FALSE); 1809ed8845d8Skrgopi 1810da14cebeSEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 1811087a28d1SDavid Gwynne cap_rings->mr_rnum = 1812087a28d1SDavid Gwynne cap_rings->mr_gnum = 1813da14cebeSEric Cheng MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX); 1814da14cebeSEric Cheng cap_rings->mr_rget = bge_fill_ring; 1815da14cebeSEric Cheng cap_rings->mr_gget = bge_fill_group; 1816ed8845d8Skrgopi break; 1817087a28d1SDavid Gwynne 1818ba2e4443Sseb default: 1819ba2e4443Sseb return (B_FALSE); 1820ba2e4443Sseb } 1821ba2e4443Sseb return (B_TRUE); 1822ba2e4443Sseb } 1823ba2e4443Sseb 1824087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX 1825087a28d1SDavid Gwynne 182662387023Sdduvall /* 182762387023Sdduvall * Loopback ioctl code 182862387023Sdduvall */ 182962387023Sdduvall 183062387023Sdduvall static lb_property_t loopmodes[] = { 183162387023Sdduvall { normal, "normal", BGE_LOOP_NONE }, 183262387023Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 183362387023Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 183462387023Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 183562387023Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 183662387023Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 183762387023Sdduvall }; 183862387023Sdduvall 183962387023Sdduvall static enum ioc_reply 184062387023Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 184162387023Sdduvall { 184262387023Sdduvall /* 184362387023Sdduvall * If the mode isn't being changed, there's nothing to do ... 184462387023Sdduvall */ 184562387023Sdduvall if (mode == bgep->param_loop_mode) 184662387023Sdduvall return (IOC_ACK); 184762387023Sdduvall 184862387023Sdduvall /* 184962387023Sdduvall * Validate the requested mode and prepare a suitable message 185062387023Sdduvall * to explain the link down/up cycle that the change will 185162387023Sdduvall * probably induce ... 185262387023Sdduvall */ 185362387023Sdduvall switch (mode) { 185462387023Sdduvall default: 185562387023Sdduvall return (IOC_INVAL); 185662387023Sdduvall 185762387023Sdduvall case BGE_LOOP_NONE: 185862387023Sdduvall case BGE_LOOP_EXTERNAL_1000: 185962387023Sdduvall case BGE_LOOP_EXTERNAL_100: 186062387023Sdduvall case BGE_LOOP_EXTERNAL_10: 186162387023Sdduvall case BGE_LOOP_INTERNAL_PHY: 186262387023Sdduvall case BGE_LOOP_INTERNAL_MAC: 186362387023Sdduvall break; 186462387023Sdduvall } 186562387023Sdduvall 186662387023Sdduvall /* 186762387023Sdduvall * All OK; tell the caller to reprogram 186862387023Sdduvall * the PHY and/or MAC for the new mode ... 186962387023Sdduvall */ 187062387023Sdduvall bgep->param_loop_mode = mode; 187162387023Sdduvall return (IOC_RESTART_ACK); 187262387023Sdduvall } 187362387023Sdduvall 187462387023Sdduvall static enum ioc_reply 187562387023Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 187662387023Sdduvall { 187762387023Sdduvall lb_info_sz_t *lbsp; 187862387023Sdduvall lb_property_t *lbpp; 187962387023Sdduvall uint32_t *lbmp; 188062387023Sdduvall int cmd; 188162387023Sdduvall 188262387023Sdduvall _NOTE(ARGUNUSED(wq)) 188362387023Sdduvall 188462387023Sdduvall /* 188562387023Sdduvall * Validate format of ioctl 188662387023Sdduvall */ 188762387023Sdduvall if (mp->b_cont == NULL) 188862387023Sdduvall return (IOC_INVAL); 188962387023Sdduvall 189062387023Sdduvall cmd = iocp->ioc_cmd; 189162387023Sdduvall switch (cmd) { 189262387023Sdduvall default: 189362387023Sdduvall /* NOTREACHED */ 189462387023Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 189562387023Sdduvall return (IOC_INVAL); 189662387023Sdduvall 189762387023Sdduvall case LB_GET_INFO_SIZE: 189862387023Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 189962387023Sdduvall return (IOC_INVAL); 19004a06b59fSyt223700 lbsp = (void *)mp->b_cont->b_rptr; 190162387023Sdduvall *lbsp = sizeof (loopmodes); 190262387023Sdduvall return (IOC_REPLY); 190362387023Sdduvall 190462387023Sdduvall case LB_GET_INFO: 190562387023Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 190662387023Sdduvall return (IOC_INVAL); 19074a06b59fSyt223700 lbpp = (void *)mp->b_cont->b_rptr; 190862387023Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 190962387023Sdduvall return (IOC_REPLY); 191062387023Sdduvall 191162387023Sdduvall case LB_GET_MODE: 191262387023Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 191362387023Sdduvall return (IOC_INVAL); 19144a06b59fSyt223700 lbmp = (void *)mp->b_cont->b_rptr; 191562387023Sdduvall *lbmp = bgep->param_loop_mode; 191662387023Sdduvall return (IOC_REPLY); 191762387023Sdduvall 191862387023Sdduvall case LB_SET_MODE: 191962387023Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 192062387023Sdduvall return (IOC_INVAL); 19214a06b59fSyt223700 lbmp = (void *)mp->b_cont->b_rptr; 192262387023Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 192362387023Sdduvall } 192462387023Sdduvall } 192562387023Sdduvall 1926087a28d1SDavid Gwynne #endif /* NOT_SUPPORTED_XXX */ 1927087a28d1SDavid Gwynne 192862387023Sdduvall /* 192962387023Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 193062387023Sdduvall */ 193162387023Sdduvall static void 193262387023Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 193362387023Sdduvall { 193462387023Sdduvall bge_t *bgep = arg; 193562387023Sdduvall struct iocblk *iocp; 193662387023Sdduvall enum ioc_reply status; 193762387023Sdduvall boolean_t need_privilege; 193862387023Sdduvall int err; 193962387023Sdduvall int cmd; 194062387023Sdduvall 194162387023Sdduvall /* 194262387023Sdduvall * Validate the command before bothering with the mutex ... 194362387023Sdduvall */ 19444a06b59fSyt223700 iocp = (void *)mp->b_rptr; 194562387023Sdduvall iocp->ioc_error = 0; 194662387023Sdduvall need_privilege = B_TRUE; 194762387023Sdduvall cmd = iocp->ioc_cmd; 194862387023Sdduvall switch (cmd) { 194962387023Sdduvall default: 195062387023Sdduvall miocnak(wq, mp, 0, EINVAL); 195162387023Sdduvall return; 195262387023Sdduvall 195362387023Sdduvall case BGE_MII_READ: 195462387023Sdduvall case BGE_MII_WRITE: 195562387023Sdduvall case BGE_SEE_READ: 195662387023Sdduvall case BGE_SEE_WRITE: 1957f724721bSzh199473 case BGE_FLASH_READ: 1958f724721bSzh199473 case BGE_FLASH_WRITE: 195962387023Sdduvall case BGE_DIAG: 196062387023Sdduvall case BGE_PEEK: 196162387023Sdduvall case BGE_POKE: 196262387023Sdduvall case BGE_PHY_RESET: 196362387023Sdduvall case BGE_SOFT_RESET: 196462387023Sdduvall case BGE_HARD_RESET: 196562387023Sdduvall break; 196662387023Sdduvall 1967087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX 196862387023Sdduvall case LB_GET_INFO_SIZE: 196962387023Sdduvall case LB_GET_INFO: 197062387023Sdduvall case LB_GET_MODE: 197162387023Sdduvall need_privilege = B_FALSE; 197262387023Sdduvall /* FALLTHRU */ 197362387023Sdduvall case LB_SET_MODE: 197462387023Sdduvall break; 1975087a28d1SDavid Gwynne #endif 197662387023Sdduvall 197762387023Sdduvall } 197862387023Sdduvall 197962387023Sdduvall if (need_privilege) { 198062387023Sdduvall /* 198162387023Sdduvall * Check for specific net_config privilege on Solaris 10+. 198262387023Sdduvall */ 198362387023Sdduvall err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 198462387023Sdduvall if (err != 0) { 198562387023Sdduvall miocnak(wq, mp, 0, err); 198662387023Sdduvall return; 198762387023Sdduvall } 198862387023Sdduvall } 198962387023Sdduvall 199062387023Sdduvall mutex_enter(bgep->genlock); 199100d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 199200d0963fSdilpreet /* can happen during autorecovery */ 199300d0963fSdilpreet mutex_exit(bgep->genlock); 199400d0963fSdilpreet miocnak(wq, mp, 0, EIO); 199500d0963fSdilpreet return; 199600d0963fSdilpreet } 199762387023Sdduvall 199862387023Sdduvall switch (cmd) { 199962387023Sdduvall default: 200062387023Sdduvall _NOTE(NOTREACHED) 200162387023Sdduvall status = IOC_INVAL; 200262387023Sdduvall break; 200362387023Sdduvall 200462387023Sdduvall case BGE_MII_READ: 200562387023Sdduvall case BGE_MII_WRITE: 200662387023Sdduvall case BGE_SEE_READ: 200762387023Sdduvall case BGE_SEE_WRITE: 2008f724721bSzh199473 case BGE_FLASH_READ: 2009f724721bSzh199473 case BGE_FLASH_WRITE: 201062387023Sdduvall case BGE_DIAG: 201162387023Sdduvall case BGE_PEEK: 201262387023Sdduvall case BGE_POKE: 201362387023Sdduvall case BGE_PHY_RESET: 201462387023Sdduvall case BGE_SOFT_RESET: 201562387023Sdduvall case BGE_HARD_RESET: 201662387023Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 201762387023Sdduvall break; 201862387023Sdduvall 2019087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX 202062387023Sdduvall case LB_GET_INFO_SIZE: 202162387023Sdduvall case LB_GET_INFO: 202262387023Sdduvall case LB_GET_MODE: 202362387023Sdduvall case LB_SET_MODE: 202462387023Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 202562387023Sdduvall break; 2026087a28d1SDavid Gwynne #endif 202762387023Sdduvall 202862387023Sdduvall } 202962387023Sdduvall 203062387023Sdduvall /* 203162387023Sdduvall * Do we need to reprogram the PHY and/or the MAC? 203262387023Sdduvall * Do it now, while we still have the mutex. 203362387023Sdduvall * 203462387023Sdduvall * Note: update the PHY first, 'cos it controls the 203562387023Sdduvall * speed/duplex parameters that the MAC code uses. 203662387023Sdduvall */ 203762387023Sdduvall switch (status) { 203862387023Sdduvall case IOC_RESTART_REPLY: 203962387023Sdduvall case IOC_RESTART_ACK: 2040e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 204100d0963fSdilpreet status = IOC_INVAL; 204262387023Sdduvall break; 204362387023Sdduvall } 204462387023Sdduvall 204500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 204600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 204700d0963fSdilpreet status = IOC_INVAL; 204800d0963fSdilpreet } 204900d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 205000d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 205100d0963fSdilpreet status = IOC_INVAL; 205200d0963fSdilpreet } 205362387023Sdduvall mutex_exit(bgep->genlock); 205462387023Sdduvall 205562387023Sdduvall /* 205662387023Sdduvall * Finally, decide how to reply 205762387023Sdduvall */ 205862387023Sdduvall switch (status) { 205962387023Sdduvall default: 206062387023Sdduvall case IOC_INVAL: 206162387023Sdduvall /* 206262387023Sdduvall * Error, reply with a NAK and EINVAL or the specified error 206362387023Sdduvall */ 206462387023Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 206562387023Sdduvall EINVAL : iocp->ioc_error); 206662387023Sdduvall break; 206762387023Sdduvall 206862387023Sdduvall case IOC_DONE: 206962387023Sdduvall /* 207062387023Sdduvall * OK, reply already sent 207162387023Sdduvall */ 207262387023Sdduvall break; 207362387023Sdduvall 207462387023Sdduvall case IOC_RESTART_ACK: 207562387023Sdduvall case IOC_ACK: 207662387023Sdduvall /* 207762387023Sdduvall * OK, reply with an ACK 207862387023Sdduvall */ 207962387023Sdduvall miocack(wq, mp, 0, 0); 208062387023Sdduvall break; 208162387023Sdduvall 208262387023Sdduvall case IOC_RESTART_REPLY: 208362387023Sdduvall case IOC_REPLY: 208462387023Sdduvall /* 208562387023Sdduvall * OK, send prepared reply as ACK or NAK 208662387023Sdduvall */ 208762387023Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 208862387023Sdduvall M_IOCACK : M_IOCNAK; 208962387023Sdduvall qreply(wq, mp); 209062387023Sdduvall break; 209162387023Sdduvall } 209262387023Sdduvall } 209362387023Sdduvall 209462387023Sdduvall /* 209562387023Sdduvall * ========== Per-instance setup/teardown code ========== 209662387023Sdduvall */ 209762387023Sdduvall 209862387023Sdduvall #undef BGE_DBG 2099087a28d1SDavid Gwynne #define BGE_DBG BGE_DBG_MEM /* debug flag for this code */ 2100931dca7dSgs150176 /* 2101931dca7dSgs150176 * Allocate an area of memory and a DMA handle for accessing it 2102931dca7dSgs150176 */ 2103931dca7dSgs150176 static int 2104931dca7dSgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 2105931dca7dSgs150176 uint_t dma_flags, dma_area_t *dma_p) 2106931dca7dSgs150176 { 2107931dca7dSgs150176 caddr_t va; 2108931dca7dSgs150176 int err; 210962387023Sdduvall 2110931dca7dSgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 2111931dca7dSgs150176 (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 2112931dca7dSgs150176 2113931dca7dSgs150176 /* 2114931dca7dSgs150176 * Allocate handle 2115931dca7dSgs150176 */ 2116931dca7dSgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 2117931dca7dSgs150176 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 2118931dca7dSgs150176 if (err != DDI_SUCCESS) 2119931dca7dSgs150176 return (DDI_FAILURE); 2120931dca7dSgs150176 2121931dca7dSgs150176 /* 2122931dca7dSgs150176 * Allocate memory 2123931dca7dSgs150176 */ 2124931dca7dSgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 2125931dca7dSgs150176 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, 2126931dca7dSgs150176 &dma_p->acc_hdl); 2127931dca7dSgs150176 if (err != DDI_SUCCESS) 2128931dca7dSgs150176 return (DDI_FAILURE); 2129931dca7dSgs150176 2130931dca7dSgs150176 /* 2131931dca7dSgs150176 * Bind the two together 2132931dca7dSgs150176 */ 2133931dca7dSgs150176 dma_p->mem_va = va; 2134931dca7dSgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 2135931dca7dSgs150176 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 2136931dca7dSgs150176 &dma_p->cookie, &dma_p->ncookies); 2137931dca7dSgs150176 2138931dca7dSgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 2139931dca7dSgs150176 dma_p->alength, err, dma_p->ncookies)); 2140931dca7dSgs150176 2141931dca7dSgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 2142931dca7dSgs150176 return (DDI_FAILURE); 2143931dca7dSgs150176 2144931dca7dSgs150176 dma_p->nslots = ~0U; 2145931dca7dSgs150176 dma_p->size = ~0U; 2146931dca7dSgs150176 dma_p->token = ~0U; 2147931dca7dSgs150176 dma_p->offset = 0; 2148931dca7dSgs150176 return (DDI_SUCCESS); 2149931dca7dSgs150176 } 2150931dca7dSgs150176 2151931dca7dSgs150176 /* 2152931dca7dSgs150176 * Free one allocated area of DMAable memory 2153931dca7dSgs150176 */ 2154931dca7dSgs150176 static void 2155931dca7dSgs150176 bge_free_dma_mem(dma_area_t *dma_p) 2156931dca7dSgs150176 { 2157931dca7dSgs150176 if (dma_p->dma_hdl != NULL) { 2158931dca7dSgs150176 if (dma_p->ncookies) { 2159931dca7dSgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 2160931dca7dSgs150176 dma_p->ncookies = 0; 2161931dca7dSgs150176 } 2162931dca7dSgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 2163931dca7dSgs150176 dma_p->dma_hdl = NULL; 2164931dca7dSgs150176 } 2165931dca7dSgs150176 2166931dca7dSgs150176 if (dma_p->acc_hdl != NULL) { 2167931dca7dSgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 2168931dca7dSgs150176 dma_p->acc_hdl = NULL; 2169931dca7dSgs150176 } 2170931dca7dSgs150176 } 217162387023Sdduvall /* 217262387023Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 217362387023Sdduvall * updating the chunk descriptor accordingly. The size of the slice 217462387023Sdduvall * is given by the product of the <qty> and <size> parameters. 217562387023Sdduvall */ 217662387023Sdduvall static void 217762387023Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 217862387023Sdduvall uint32_t qty, uint32_t size) 217962387023Sdduvall { 218062387023Sdduvall static uint32_t sequence = 0xbcd5704a; 218162387023Sdduvall size_t totsize; 218262387023Sdduvall 218362387023Sdduvall totsize = qty*size; 218462387023Sdduvall ASSERT(totsize <= chunk->alength); 218562387023Sdduvall 218662387023Sdduvall *slice = *chunk; 218762387023Sdduvall slice->nslots = qty; 218862387023Sdduvall slice->size = size; 218962387023Sdduvall slice->alength = totsize; 219062387023Sdduvall slice->token = ++sequence; 219162387023Sdduvall 219262387023Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 219362387023Sdduvall chunk->alength -= totsize; 219462387023Sdduvall chunk->offset += totsize; 219562387023Sdduvall chunk->cookie.dmac_laddress += totsize; 219662387023Sdduvall chunk->cookie.dmac_size -= totsize; 219762387023Sdduvall } 219862387023Sdduvall 219962387023Sdduvall /* 220062387023Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 220162387023Sdduvall * the information in the <dma_area> descriptors that it contains 220262387023Sdduvall * to set up all the other fields. This routine should be called 220362387023Sdduvall * only once for each ring. 220462387023Sdduvall */ 220562387023Sdduvall static void 220662387023Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 220762387023Sdduvall { 220862387023Sdduvall buff_ring_t *brp; 220962387023Sdduvall bge_status_t *bsp; 221062387023Sdduvall sw_rbd_t *srbdp; 221162387023Sdduvall dma_area_t pbuf; 221262387023Sdduvall uint32_t bufsize; 221362387023Sdduvall uint32_t nslots; 221462387023Sdduvall uint32_t slot; 221562387023Sdduvall uint32_t split; 221662387023Sdduvall 221762387023Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 221862387023Sdduvall NIC_MEM_SHADOW_BUFF_STD, 221962387023Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 222062387023Sdduvall NIC_MEM_SHADOW_BUFF_MINI 222162387023Sdduvall }; 222262387023Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 222362387023Sdduvall RECV_STD_PROD_INDEX_REG, 222462387023Sdduvall RECV_JUMBO_PROD_INDEX_REG, 222562387023Sdduvall RECV_MINI_PROD_INDEX_REG 222662387023Sdduvall }; 222762387023Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 222862387023Sdduvall STATUS_STD_BUFF_CONS_INDEX, 222962387023Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 223062387023Sdduvall STATUS_MINI_BUFF_CONS_INDEX 223162387023Sdduvall }; 223262387023Sdduvall 223362387023Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 223462387023Sdduvall (void *)bgep, ring)); 223562387023Sdduvall 223662387023Sdduvall brp = &bgep->buff[ring]; 223762387023Sdduvall nslots = brp->desc.nslots; 223862387023Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 223962387023Sdduvall bufsize = brp->buf[0].size; 224062387023Sdduvall 224162387023Sdduvall /* 224262387023Sdduvall * Set up the copy of the h/w RCB 224362387023Sdduvall * 224462387023Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 224562387023Sdduvall * field holds the number of slots), in a Receive Buffer Ring 224662387023Sdduvall * this field indicates the size of each buffer in the ring. 224762387023Sdduvall */ 224862387023Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 22494a06b59fSyt223700 brp->hw_rcb.max_len = (uint16_t)bufsize; 225062387023Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 225162387023Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 225262387023Sdduvall 225362387023Sdduvall /* 225462387023Sdduvall * Other one-off initialisation of per-ring data 225562387023Sdduvall */ 225662387023Sdduvall brp->bgep = bgep; 225762387023Sdduvall bsp = DMA_VPTR(bgep->status_block); 225862387023Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 225962387023Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 226062387023Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 226162387023Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 226262387023Sdduvall 226362387023Sdduvall /* 226462387023Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 226562387023Sdduvall */ 226662387023Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 226762387023Sdduvall brp->sw_rbds = srbdp; 226862387023Sdduvall 226962387023Sdduvall /* 227062387023Sdduvall * Now initialise each array element once and for all 227162387023Sdduvall */ 227262387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 227362387023Sdduvall pbuf = brp->buf[split]; 227462387023Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 227562387023Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 227662387023Sdduvall ASSERT(pbuf.alength == 0); 227762387023Sdduvall } 227862387023Sdduvall } 227962387023Sdduvall 228062387023Sdduvall /* 228162387023Sdduvall * Clean up initialisation done above before the memory is freed 228262387023Sdduvall */ 228362387023Sdduvall static void 228462387023Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 228562387023Sdduvall { 228662387023Sdduvall buff_ring_t *brp; 228762387023Sdduvall sw_rbd_t *srbdp; 228862387023Sdduvall 228962387023Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 229062387023Sdduvall (void *)bgep, ring)); 229162387023Sdduvall 229262387023Sdduvall brp = &bgep->buff[ring]; 229362387023Sdduvall srbdp = brp->sw_rbds; 229462387023Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 229562387023Sdduvall 229662387023Sdduvall mutex_destroy(brp->rf_lock); 229762387023Sdduvall } 229862387023Sdduvall 229962387023Sdduvall /* 230062387023Sdduvall * Initialise the specified Receive (Return) Ring, using the 230162387023Sdduvall * information in the <dma_area> descriptors that it contains 230262387023Sdduvall * to set up all the other fields. This routine should be called 230362387023Sdduvall * only once for each ring. 230462387023Sdduvall */ 230562387023Sdduvall static void 230662387023Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 230762387023Sdduvall { 230862387023Sdduvall recv_ring_t *rrp; 230962387023Sdduvall bge_status_t *bsp; 231062387023Sdduvall uint32_t nslots; 231162387023Sdduvall 231262387023Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 231362387023Sdduvall (void *)bgep, ring)); 231462387023Sdduvall 231562387023Sdduvall /* 231662387023Sdduvall * The chip architecture requires that receive return rings have 231762387023Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 231862387023Sdduvall */ 231962387023Sdduvall rrp = &bgep->recv[ring]; 232062387023Sdduvall nslots = rrp->desc.nslots; 232162387023Sdduvall ASSERT(nslots == 0 || nslots == 512 || 232262387023Sdduvall nslots == 1024 || nslots == 2048); 232362387023Sdduvall 232462387023Sdduvall /* 232562387023Sdduvall * Set up the copy of the h/w RCB 232662387023Sdduvall */ 232762387023Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 23284a06b59fSyt223700 rrp->hw_rcb.max_len = (uint16_t)nslots; 232962387023Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 233062387023Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 233162387023Sdduvall 233262387023Sdduvall /* 233362387023Sdduvall * Other one-off initialisation of per-ring data 233462387023Sdduvall */ 233562387023Sdduvall rrp->bgep = bgep; 233662387023Sdduvall bsp = DMA_VPTR(bgep->status_block); 233762387023Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 233862387023Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 233962387023Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 234062387023Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 234162387023Sdduvall } 234262387023Sdduvall 234362387023Sdduvall 234462387023Sdduvall /* 234562387023Sdduvall * Clean up initialisation done above before the memory is freed 234662387023Sdduvall */ 234762387023Sdduvall static void 234862387023Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 234962387023Sdduvall { 235062387023Sdduvall recv_ring_t *rrp; 235162387023Sdduvall 235262387023Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 235362387023Sdduvall (void *)bgep, ring)); 235462387023Sdduvall 235562387023Sdduvall rrp = &bgep->recv[ring]; 235662387023Sdduvall if (rrp->rx_softint) 235762387023Sdduvall ddi_remove_softintr(rrp->rx_softint); 235862387023Sdduvall mutex_destroy(rrp->rx_lock); 235962387023Sdduvall } 236062387023Sdduvall 236162387023Sdduvall /* 236262387023Sdduvall * Initialise the specified Send Ring, using the information in the 236362387023Sdduvall * <dma_area> descriptors that it contains to set up all the other 236462387023Sdduvall * fields. This routine should be called only once for each ring. 236562387023Sdduvall */ 236662387023Sdduvall static void 236762387023Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 236862387023Sdduvall { 236962387023Sdduvall send_ring_t *srp; 237062387023Sdduvall bge_status_t *bsp; 237162387023Sdduvall sw_sbd_t *ssbdp; 237262387023Sdduvall dma_area_t desc; 237362387023Sdduvall dma_area_t pbuf; 237462387023Sdduvall uint32_t nslots; 237562387023Sdduvall uint32_t slot; 237662387023Sdduvall uint32_t split; 2377931dca7dSgs150176 sw_txbuf_t *txbuf; 237862387023Sdduvall 237962387023Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 238062387023Sdduvall (void *)bgep, ring)); 238162387023Sdduvall 238262387023Sdduvall /* 238362387023Sdduvall * The chip architecture requires that host-based send rings 238462387023Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 238562387023Sdduvall */ 238662387023Sdduvall srp = &bgep->send[ring]; 238762387023Sdduvall nslots = srp->desc.nslots; 238862387023Sdduvall ASSERT(nslots == 0 || nslots == 512); 238962387023Sdduvall 239062387023Sdduvall /* 239162387023Sdduvall * Set up the copy of the h/w RCB 239262387023Sdduvall */ 239362387023Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 23944a06b59fSyt223700 srp->hw_rcb.max_len = (uint16_t)nslots; 239562387023Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 239662387023Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 239762387023Sdduvall 239862387023Sdduvall /* 239962387023Sdduvall * Other one-off initialisation of per-ring data 240062387023Sdduvall */ 240162387023Sdduvall srp->bgep = bgep; 240262387023Sdduvall bsp = DMA_VPTR(bgep->status_block); 240362387023Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 240462387023Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 240562387023Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 240662387023Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 2407931dca7dSgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER, 2408931dca7dSgs150176 DDI_INTR_PRI(bgep->intr_pri)); 2409931dca7dSgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER, 2410931dca7dSgs150176 DDI_INTR_PRI(bgep->intr_pri)); 241162387023Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 241262387023Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 2413931dca7dSgs150176 if (nslots == 0) 2414931dca7dSgs150176 return; 241562387023Sdduvall 241662387023Sdduvall /* 241762387023Sdduvall * Allocate the array of s/w Send Buffer Descriptors 241862387023Sdduvall */ 241962387023Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 2420931dca7dSgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP); 2421931dca7dSgs150176 srp->txbuf_head = 2422931dca7dSgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP); 2423931dca7dSgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP); 242462387023Sdduvall srp->sw_sbds = ssbdp; 2425931dca7dSgs150176 srp->txbuf = txbuf; 2426931dca7dSgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 2427931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 2428931dca7dSgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT) 2429931dca7dSgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO; 2430931dca7dSgs150176 else 2431931dca7dSgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY; 2432931dca7dSgs150176 srp->tx_array = 1; 243362387023Sdduvall 243462387023Sdduvall /* 2435931dca7dSgs150176 * Chunk tx desc area 243662387023Sdduvall */ 243762387023Sdduvall desc = srp->desc; 2438931dca7dSgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) { 243962387023Sdduvall bge_slice_chunk(&ssbdp->desc, &desc, 1, 244062387023Sdduvall sizeof (bge_sbd_t)); 2441931dca7dSgs150176 } 2442931dca7dSgs150176 ASSERT(desc.alength == 0); 2443931dca7dSgs150176 2444931dca7dSgs150176 /* 2445931dca7dSgs150176 * Chunk tx buffer area 2446931dca7dSgs150176 */ 2447931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 2448931dca7dSgs150176 pbuf = srp->buf[0][split]; 2449931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 2450931dca7dSgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1, 245162387023Sdduvall bgep->chipid.snd_buff_size); 2452931dca7dSgs150176 txbuf++; 245362387023Sdduvall } 245462387023Sdduvall ASSERT(pbuf.alength == 0); 245562387023Sdduvall } 245662387023Sdduvall } 245762387023Sdduvall 245862387023Sdduvall /* 245962387023Sdduvall * Clean up initialisation done above before the memory is freed 246062387023Sdduvall */ 246162387023Sdduvall static void 246262387023Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 246362387023Sdduvall { 246462387023Sdduvall send_ring_t *srp; 2465931dca7dSgs150176 uint32_t array; 2466931dca7dSgs150176 uint32_t split; 2467931dca7dSgs150176 uint32_t nslots; 246862387023Sdduvall 246962387023Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 247062387023Sdduvall (void *)bgep, ring)); 247162387023Sdduvall 247262387023Sdduvall srp = &bgep->send[ring]; 247362387023Sdduvall mutex_destroy(srp->tc_lock); 2474931dca7dSgs150176 mutex_destroy(srp->freetxbuf_lock); 2475931dca7dSgs150176 mutex_destroy(srp->txbuf_lock); 2476931dca7dSgs150176 mutex_destroy(srp->tx_lock); 2477931dca7dSgs150176 nslots = srp->desc.nslots; 2478931dca7dSgs150176 if (nslots == 0) 2479931dca7dSgs150176 return; 2480931dca7dSgs150176 2481931dca7dSgs150176 for (array = 1; array < srp->tx_array; ++array) 2482931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) 2483931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][split]); 2484931dca7dSgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds)); 2485931dca7dSgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head)); 2486931dca7dSgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf)); 2487931dca7dSgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp)); 2488931dca7dSgs150176 srp->sw_sbds = NULL; 2489931dca7dSgs150176 srp->txbuf_head = NULL; 2490931dca7dSgs150176 srp->txbuf = NULL; 2491931dca7dSgs150176 srp->pktp = NULL; 249262387023Sdduvall } 249362387023Sdduvall 249462387023Sdduvall /* 249562387023Sdduvall * Initialise all transmit, receive, and buffer rings. 249662387023Sdduvall */ 249700d0963fSdilpreet void 249862387023Sdduvall bge_init_rings(bge_t *bgep) 249962387023Sdduvall { 2500931dca7dSgs150176 uint32_t ring; 250162387023Sdduvall 250262387023Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 250362387023Sdduvall 250462387023Sdduvall /* 250562387023Sdduvall * Perform one-off initialisation of each ring ... 250662387023Sdduvall */ 250762387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 250862387023Sdduvall bge_init_send_ring(bgep, ring); 250962387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 251062387023Sdduvall bge_init_recv_ring(bgep, ring); 251162387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 251262387023Sdduvall bge_init_buff_ring(bgep, ring); 251362387023Sdduvall } 251462387023Sdduvall 251562387023Sdduvall /* 251662387023Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 251762387023Sdduvall */ 251800d0963fSdilpreet void 251962387023Sdduvall bge_fini_rings(bge_t *bgep) 252062387023Sdduvall { 2521931dca7dSgs150176 uint32_t ring; 252262387023Sdduvall 252362387023Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 252462387023Sdduvall 252562387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 252662387023Sdduvall bge_fini_buff_ring(bgep, ring); 252762387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 252862387023Sdduvall bge_fini_recv_ring(bgep, ring); 252962387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 253062387023Sdduvall bge_fini_send_ring(bgep, ring); 253162387023Sdduvall } 253262387023Sdduvall 253362387023Sdduvall /* 2534931dca7dSgs150176 * Called from the bge_m_stop() to free the tx buffers which are 2535931dca7dSgs150176 * allocated from the tx process. 253662387023Sdduvall */ 2537931dca7dSgs150176 void 2538931dca7dSgs150176 bge_free_txbuf_arrays(send_ring_t *srp) 253962387023Sdduvall { 2540931dca7dSgs150176 uint32_t array; 2541931dca7dSgs150176 uint32_t split; 254262387023Sdduvall 2543931dca7dSgs150176 ASSERT(mutex_owned(srp->tx_lock)); 254462387023Sdduvall 254562387023Sdduvall /* 2546931dca7dSgs150176 * Free the extra tx buffer DMA area 254762387023Sdduvall */ 2548931dca7dSgs150176 for (array = 1; array < srp->tx_array; ++array) 2549931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) 2550931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][split]); 255162387023Sdduvall 255262387023Sdduvall /* 2553931dca7dSgs150176 * Restore initial tx buffer numbers 255462387023Sdduvall */ 2555931dca7dSgs150176 srp->tx_array = 1; 2556931dca7dSgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 2557931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 2558931dca7dSgs150176 srp->tx_flow = 0; 2559931dca7dSgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 256062387023Sdduvall } 256162387023Sdduvall 256262387023Sdduvall /* 2563931dca7dSgs150176 * Called from tx process to allocate more tx buffers 256462387023Sdduvall */ 2565931dca7dSgs150176 bge_queue_item_t * 2566931dca7dSgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp) 256762387023Sdduvall { 2568931dca7dSgs150176 bge_queue_t *txbuf_queue; 2569931dca7dSgs150176 bge_queue_item_t *txbuf_item_last; 2570931dca7dSgs150176 bge_queue_item_t *txbuf_item; 2571931dca7dSgs150176 bge_queue_item_t *txbuf_item_rtn; 2572931dca7dSgs150176 sw_txbuf_t *txbuf; 2573931dca7dSgs150176 dma_area_t area; 2574931dca7dSgs150176 size_t txbuffsize; 2575931dca7dSgs150176 uint32_t slot; 2576931dca7dSgs150176 uint32_t array; 2577931dca7dSgs150176 uint32_t split; 2578931dca7dSgs150176 uint32_t err; 2579931dca7dSgs150176 2580931dca7dSgs150176 ASSERT(mutex_owned(srp->tx_lock)); 2581931dca7dSgs150176 2582931dca7dSgs150176 array = srp->tx_array; 2583931dca7dSgs150176 if (array >= srp->tx_array_max) 2584931dca7dSgs150176 return (NULL); 2585931dca7dSgs150176 2586931dca7dSgs150176 /* 2587931dca7dSgs150176 * Allocate memory & handles for TX buffers 2588931dca7dSgs150176 */ 2589931dca7dSgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 2590931dca7dSgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0); 2591931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 2592931dca7dSgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 2593931dca7dSgs150176 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 2594931dca7dSgs150176 &srp->buf[array][split]); 2595931dca7dSgs150176 if (err != DDI_SUCCESS) { 2596931dca7dSgs150176 /* Free the last already allocated OK chunks */ 2597931dca7dSgs150176 for (slot = 0; slot <= split; ++slot) 2598931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][slot]); 2599931dca7dSgs150176 srp->tx_alloc_fail++; 2600931dca7dSgs150176 return (NULL); 260162387023Sdduvall } 260262387023Sdduvall } 260362387023Sdduvall 2604931dca7dSgs150176 /* 2605931dca7dSgs150176 * Chunk tx buffer area 2606931dca7dSgs150176 */ 2607931dca7dSgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 2608931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 2609931dca7dSgs150176 area = srp->buf[array][split]; 2610931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 2611931dca7dSgs150176 bge_slice_chunk(&txbuf->buf, &area, 1, 2612931dca7dSgs150176 bgep->chipid.snd_buff_size); 2613931dca7dSgs150176 txbuf++; 261462387023Sdduvall } 261562387023Sdduvall } 261662387023Sdduvall 261762387023Sdduvall /* 2618931dca7dSgs150176 * Add above buffers to the tx buffer pop queue 2619931dca7dSgs150176 */ 2620931dca7dSgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 2621931dca7dSgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 2622931dca7dSgs150176 txbuf_item_last = NULL; 2623931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) { 2624931dca7dSgs150176 txbuf_item->item = txbuf; 2625931dca7dSgs150176 txbuf_item->next = txbuf_item_last; 2626931dca7dSgs150176 txbuf_item_last = txbuf_item; 2627931dca7dSgs150176 txbuf++; 2628931dca7dSgs150176 txbuf_item++; 2629931dca7dSgs150176 } 2630931dca7dSgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 2631931dca7dSgs150176 txbuf_item_rtn = txbuf_item; 2632931dca7dSgs150176 txbuf_item++; 2633931dca7dSgs150176 txbuf_queue = srp->txbuf_pop_queue; 2634931dca7dSgs150176 mutex_enter(txbuf_queue->lock); 2635931dca7dSgs150176 txbuf_item->next = txbuf_queue->head; 2636931dca7dSgs150176 txbuf_queue->head = txbuf_item_last; 2637931dca7dSgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1; 2638931dca7dSgs150176 mutex_exit(txbuf_queue->lock); 2639931dca7dSgs150176 2640931dca7dSgs150176 srp->tx_array++; 2641931dca7dSgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM; 2642931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 2643931dca7dSgs150176 2644931dca7dSgs150176 return (txbuf_item_rtn); 2645931dca7dSgs150176 } 2646931dca7dSgs150176 2647931dca7dSgs150176 /* 264862387023Sdduvall * This function allocates all the transmit and receive buffers 2649931dca7dSgs150176 * and descriptors, in four chunks. 265062387023Sdduvall */ 265100d0963fSdilpreet int 265262387023Sdduvall bge_alloc_bufs(bge_t *bgep) 265362387023Sdduvall { 265462387023Sdduvall dma_area_t area; 265562387023Sdduvall size_t rxbuffsize; 265662387023Sdduvall size_t txbuffsize; 265762387023Sdduvall size_t rxbuffdescsize; 265862387023Sdduvall size_t rxdescsize; 265962387023Sdduvall size_t txdescsize; 2660931dca7dSgs150176 uint32_t ring; 2661931dca7dSgs150176 uint32_t rx_rings = bgep->chipid.rx_rings; 2662931dca7dSgs150176 uint32_t tx_rings = bgep->chipid.tx_rings; 266362387023Sdduvall int split; 266462387023Sdduvall int err; 266562387023Sdduvall 266662387023Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 266762387023Sdduvall (void *)bgep)); 266862387023Sdduvall 26691b5c96f3Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size; 267062387023Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 267162387023Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 267262387023Sdduvall 2673931dca7dSgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 267462387023Sdduvall txbuffsize *= tx_rings; 267562387023Sdduvall 267662387023Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 267762387023Sdduvall rxdescsize *= sizeof (bge_rbd_t); 267862387023Sdduvall 267962387023Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 268062387023Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 268162387023Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 268262387023Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 268362387023Sdduvall 268462387023Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 268562387023Sdduvall txdescsize *= sizeof (bge_sbd_t); 268662387023Sdduvall txdescsize += sizeof (bge_statistics_t); 268762387023Sdduvall txdescsize += sizeof (bge_status_t); 268862387023Sdduvall txdescsize += BGE_STATUS_PADDING; 268962387023Sdduvall 269062387023Sdduvall /* 26915952d588Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers 26925952d588Szh199473 */ 2693087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) || 2694087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) { 26955952d588Szh199473 if (bge_relaxed_ordering) 26965952d588Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING; 2697087a28d1SDavid Gwynne } 26985952d588Szh199473 26995952d588Szh199473 /* 270062387023Sdduvall * Allocate memory & handles for RX buffers 270162387023Sdduvall */ 270262387023Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 270362387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 270462387023Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 270562387023Sdduvall &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 270662387023Sdduvall &bgep->rx_buff[split]); 270762387023Sdduvall if (err != DDI_SUCCESS) 270862387023Sdduvall return (DDI_FAILURE); 270962387023Sdduvall } 2710087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Rx Buffers (rxbuffsize = %d)", 2711087a28d1SDavid Gwynne rxbuffsize/BGE_SPLIT, 2712087a28d1SDavid Gwynne rxbuffsize)); 271362387023Sdduvall 271462387023Sdduvall /* 271562387023Sdduvall * Allocate memory & handles for TX buffers 271662387023Sdduvall */ 271762387023Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 271862387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 271962387023Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 272062387023Sdduvall &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 272162387023Sdduvall &bgep->tx_buff[split]); 272262387023Sdduvall if (err != DDI_SUCCESS) 272362387023Sdduvall return (DDI_FAILURE); 272462387023Sdduvall } 2725087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Tx Buffers (txbuffsize = %d)", 2726087a28d1SDavid Gwynne txbuffsize/BGE_SPLIT, 2727087a28d1SDavid Gwynne txbuffsize)); 272862387023Sdduvall 2729087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) || 2730087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) { 2731087a28d1SDavid Gwynne /* no relaxed ordering for descriptors rings? */ 27325952d588Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING; 2733087a28d1SDavid Gwynne } 27345952d588Szh199473 273562387023Sdduvall /* 273662387023Sdduvall * Allocate memory & handles for receive return rings 273762387023Sdduvall */ 273862387023Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 273962387023Sdduvall for (split = 0; split < rx_rings; ++split) { 274062387023Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 274162387023Sdduvall &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 274262387023Sdduvall &bgep->rx_desc[split]); 274362387023Sdduvall if (err != DDI_SUCCESS) 274462387023Sdduvall return (DDI_FAILURE); 274562387023Sdduvall } 2746087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Rx Descs cons (rx_rings = %d, rxdescsize = %d)", 2747087a28d1SDavid Gwynne rxdescsize/rx_rings, 2748087a28d1SDavid Gwynne rx_rings, 2749087a28d1SDavid Gwynne rxdescsize)); 275062387023Sdduvall 275162387023Sdduvall /* 2752087a28d1SDavid Gwynne * Allocate memory & handles for buffer (producer) descriptor rings. 2753087a28d1SDavid Gwynne * Note that split=rx_rings. 275462387023Sdduvall */ 275562387023Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 275662387023Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 275762387023Sdduvall if (err != DDI_SUCCESS) 275862387023Sdduvall return (DDI_FAILURE); 2759087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated 1 chunks for Rx Descs prod (rxbuffdescsize = %d)", 2760087a28d1SDavid Gwynne rxdescsize)); 276162387023Sdduvall 276262387023Sdduvall /* 276362387023Sdduvall * Allocate memory & handles for TX descriptor rings, 276462387023Sdduvall * status block, and statistics area 276562387023Sdduvall */ 276662387023Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 276762387023Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 276862387023Sdduvall if (err != DDI_SUCCESS) 276962387023Sdduvall return (DDI_FAILURE); 2770087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated 1 chunks for Tx Descs / Status Block / Stats (txdescdize = %d)", 2771087a28d1SDavid Gwynne txdescsize)); 277262387023Sdduvall 277362387023Sdduvall /* 277462387023Sdduvall * Now carve up each of the allocated areas ... 277562387023Sdduvall */ 2776087a28d1SDavid Gwynne 2777087a28d1SDavid Gwynne /* rx buffers */ 277862387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 277962387023Sdduvall area = bgep->rx_buff[split]; 2780087a28d1SDavid Gwynne 2781087a28d1SDavid Gwynne BGE_DEBUG(("RXB CHNK %d INIT: va=%p alen=%d off=%d pa=%llx psz=%d", 2782087a28d1SDavid Gwynne split, 2783087a28d1SDavid Gwynne area.mem_va, 2784087a28d1SDavid Gwynne area.alength, 2785087a28d1SDavid Gwynne area.offset, 2786087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2787087a28d1SDavid Gwynne area.cookie.dmac_size)); 2788087a28d1SDavid Gwynne 278962387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 279062387023Sdduvall &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 27911b5c96f3Sly149593 bgep->chipid.std_buf_size); 2792087a28d1SDavid Gwynne 2793087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d STND: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2794087a28d1SDavid Gwynne split, 2795087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].mem_va, 2796087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].alength, 2797087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].offset, 2798087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].cookie.dmac_laddress, 2799087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].cookie.dmac_size, 2800087a28d1SDavid Gwynne BGE_STD_SLOTS_USED/BGE_SPLIT, 2801087a28d1SDavid Gwynne bgep->chipid.std_buf_size)); 2802087a28d1SDavid Gwynne 280362387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 280462387023Sdduvall &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 280562387023Sdduvall bgep->chipid.recv_jumbo_size); 2806087a28d1SDavid Gwynne 2807087a28d1SDavid Gwynne if ((bgep->chipid.jumbo_slots / BGE_SPLIT) > 0) 2808087a28d1SDavid Gwynne { 2809087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d JUMB: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2810087a28d1SDavid Gwynne split, 2811087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].mem_va, 2812087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].alength, 2813087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].offset, 2814087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].cookie.dmac_laddress, 2815087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].cookie.dmac_size, 2816087a28d1SDavid Gwynne bgep->chipid.jumbo_slots/BGE_SPLIT, 2817087a28d1SDavid Gwynne bgep->chipid.recv_jumbo_size)); 2818087a28d1SDavid Gwynne } 2819087a28d1SDavid Gwynne 282062387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 282162387023Sdduvall &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 282262387023Sdduvall BGE_MINI_BUFF_SIZE); 2823087a28d1SDavid Gwynne 2824087a28d1SDavid Gwynne if ((BGE_MINI_SLOTS_USED / BGE_SPLIT) > 0) 2825087a28d1SDavid Gwynne { 2826087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d MINI: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2827087a28d1SDavid Gwynne split, 2828087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].mem_va, 2829087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].alength, 2830087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].offset, 2831087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].cookie.dmac_laddress, 2832087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].cookie.dmac_size, 2833087a28d1SDavid Gwynne BGE_MINI_SLOTS_USED/BGE_SPLIT, 2834087a28d1SDavid Gwynne BGE_MINI_BUFF_SIZE)); 283562387023Sdduvall } 283662387023Sdduvall 2837087a28d1SDavid Gwynne BGE_DEBUG(("RXB CHNK %d DONE: va=%p alen=%d off=%d pa=%llx psz=%d", 2838087a28d1SDavid Gwynne split, 2839087a28d1SDavid Gwynne area.mem_va, 2840087a28d1SDavid Gwynne area.alength, 2841087a28d1SDavid Gwynne area.offset, 2842087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2843087a28d1SDavid Gwynne area.cookie.dmac_size)); 2844087a28d1SDavid Gwynne } 2845087a28d1SDavid Gwynne 2846087a28d1SDavid Gwynne /* tx buffers */ 284762387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 284862387023Sdduvall area = bgep->tx_buff[split]; 2849087a28d1SDavid Gwynne 2850087a28d1SDavid Gwynne BGE_DEBUG(("TXB CHNK %d INIT: va=%p alen=%d off=%d pa=%llx psz=%d", 2851087a28d1SDavid Gwynne split, 2852087a28d1SDavid Gwynne area.mem_va, 2853087a28d1SDavid Gwynne area.alength, 2854087a28d1SDavid Gwynne area.offset, 2855087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2856087a28d1SDavid Gwynne area.cookie.dmac_size)); 2857087a28d1SDavid Gwynne 2858087a28d1SDavid Gwynne for (ring = 0; ring < tx_rings; ++ring) { 2859931dca7dSgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 2860931dca7dSgs150176 &area, BGE_SEND_BUF_NUM/BGE_SPLIT, 286162387023Sdduvall bgep->chipid.snd_buff_size); 2862087a28d1SDavid Gwynne 2863087a28d1SDavid Gwynne BGE_DEBUG(("TXB SLCE %d RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2864087a28d1SDavid Gwynne split, ring, 2865087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].mem_va, 2866087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].alength, 2867087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].offset, 2868087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].cookie.dmac_laddress, 2869087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].cookie.dmac_size, 2870087a28d1SDavid Gwynne BGE_SEND_BUF_NUM/BGE_SPLIT, 2871087a28d1SDavid Gwynne bgep->chipid.snd_buff_size)); 2872087a28d1SDavid Gwynne } 2873087a28d1SDavid Gwynne 2874087a28d1SDavid Gwynne for (; ring < BGE_SEND_RINGS_MAX; ++ring) { 2875931dca7dSgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 2876931dca7dSgs150176 &area, 0, bgep->chipid.snd_buff_size); 287762387023Sdduvall } 287862387023Sdduvall 2879087a28d1SDavid Gwynne BGE_DEBUG(("TXB CHNK %d DONE: va=%p alen=%d off=%d pa=%llx psz=%d", 2880087a28d1SDavid Gwynne split, 2881087a28d1SDavid Gwynne area.mem_va, 2882087a28d1SDavid Gwynne area.alength, 2883087a28d1SDavid Gwynne area.offset, 2884087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2885087a28d1SDavid Gwynne area.cookie.dmac_size)); 2886087a28d1SDavid Gwynne } 2887087a28d1SDavid Gwynne 2888087a28d1SDavid Gwynne for (ring = 0; ring < rx_rings; ++ring) { 288962387023Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 289062387023Sdduvall bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 289162387023Sdduvall 2892087a28d1SDavid Gwynne BGE_DEBUG(("RXD CONS RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2893087a28d1SDavid Gwynne ring, 2894087a28d1SDavid Gwynne bgep->recv[ring].desc.mem_va, 2895087a28d1SDavid Gwynne bgep->recv[ring].desc.alength, 2896087a28d1SDavid Gwynne bgep->recv[ring].desc.offset, 2897087a28d1SDavid Gwynne bgep->recv[ring].desc.cookie.dmac_laddress, 2898087a28d1SDavid Gwynne bgep->recv[ring].desc.cookie.dmac_size, 2899087a28d1SDavid Gwynne bgep->chipid.recv_slots, 2900087a28d1SDavid Gwynne sizeof(bge_rbd_t))); 2901087a28d1SDavid Gwynne } 2902087a28d1SDavid Gwynne 2903087a28d1SDavid Gwynne /* dma alloc for rxbuffdescsize is located at bgep->rx_desc[#rings] */ 2904087a28d1SDavid Gwynne area = bgep->rx_desc[rx_rings]; /* note rx_rings = one beyond rings */ 2905087a28d1SDavid Gwynne 2906087a28d1SDavid Gwynne for (; ring < BGE_RECV_RINGS_MAX; ++ring) /* skip unused rings */ 290762387023Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 290862387023Sdduvall 0, sizeof (bge_rbd_t)); 2909087a28d1SDavid Gwynne 2910087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD INIT: va=%p alen=%d off=%d pa=%llx psz=%d", 2911087a28d1SDavid Gwynne area.mem_va, 2912087a28d1SDavid Gwynne area.alength, 2913087a28d1SDavid Gwynne area.offset, 2914087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2915087a28d1SDavid Gwynne area.cookie.dmac_size)); 2916087a28d1SDavid Gwynne 291762387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 291862387023Sdduvall BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 2919087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD STND: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2920087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.mem_va, 2921087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.alength, 2922087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.offset, 2923087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.cookie.dmac_laddress, 2924087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.cookie.dmac_size, 2925087a28d1SDavid Gwynne BGE_STD_SLOTS_USED, 2926087a28d1SDavid Gwynne sizeof(bge_rbd_t))); 2927087a28d1SDavid Gwynne 292862387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 292962387023Sdduvall bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 2930087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD JUMB: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2931087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.mem_va, 2932087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.alength, 2933087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.offset, 2934087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.cookie.dmac_laddress, 2935087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.cookie.dmac_size, 2936087a28d1SDavid Gwynne bgep->chipid.jumbo_slots, 2937087a28d1SDavid Gwynne sizeof(bge_rbd_t))); 2938087a28d1SDavid Gwynne 293962387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 294062387023Sdduvall BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 2941087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD MINI: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2942087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.mem_va, 2943087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.alength, 2944087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.offset, 2945087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.cookie.dmac_laddress, 2946087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.cookie.dmac_size, 2947087a28d1SDavid Gwynne BGE_MINI_SLOTS_USED, 2948087a28d1SDavid Gwynne sizeof(bge_rbd_t))); 2949087a28d1SDavid Gwynne 2950087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD DONE: va=%p alen=%d off=%d pa=%llx psz=%d", 2951087a28d1SDavid Gwynne area.mem_va, 2952087a28d1SDavid Gwynne area.alength, 2953087a28d1SDavid Gwynne area.offset, 2954087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2955087a28d1SDavid Gwynne area.cookie.dmac_size)); 2956087a28d1SDavid Gwynne 295762387023Sdduvall ASSERT(area.alength == 0); 295862387023Sdduvall 295962387023Sdduvall area = bgep->tx_desc; 2960087a28d1SDavid Gwynne 2961087a28d1SDavid Gwynne BGE_DEBUG(("TXD INIT: va=%p alen=%d off=%d pa=%llx psz=%d", 2962087a28d1SDavid Gwynne area.mem_va, 2963087a28d1SDavid Gwynne area.alength, 2964087a28d1SDavid Gwynne area.offset, 2965087a28d1SDavid Gwynne area.cookie.dmac_laddress, 2966087a28d1SDavid Gwynne area.cookie.dmac_size)); 2967087a28d1SDavid Gwynne 2968087a28d1SDavid Gwynne for (ring = 0; ring < tx_rings; ++ring) { 296962387023Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 297062387023Sdduvall BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 2971087a28d1SDavid Gwynne 2972087a28d1SDavid Gwynne BGE_DEBUG(("TXD RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2973087a28d1SDavid Gwynne ring, 2974087a28d1SDavid Gwynne bgep->send[ring].desc.mem_va, 2975087a28d1SDavid Gwynne bgep->send[ring].desc.alength, 2976087a28d1SDavid Gwynne bgep->send[ring].desc.offset, 2977087a28d1SDavid Gwynne bgep->send[ring].desc.cookie.dmac_laddress, 2978087a28d1SDavid Gwynne bgep->send[ring].desc.cookie.dmac_size, 2979087a28d1SDavid Gwynne BGE_SEND_SLOTS_USED, 2980087a28d1SDavid Gwynne sizeof(bge_sbd_t))); 2981087a28d1SDavid Gwynne } 2982087a28d1SDavid Gwynne 2983087a28d1SDavid Gwynne for (; ring < BGE_SEND_RINGS_MAX; ++ring) /* skip unused rings */ 298462387023Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 298562387023Sdduvall 0, sizeof (bge_sbd_t)); 2986087a28d1SDavid Gwynne 298762387023Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 2988087a28d1SDavid Gwynne BGE_DEBUG(("TXD STATISTICS: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2989087a28d1SDavid Gwynne bgep->statistics.mem_va, 2990087a28d1SDavid Gwynne bgep->statistics.alength, 2991087a28d1SDavid Gwynne bgep->statistics.offset, 2992087a28d1SDavid Gwynne bgep->statistics.cookie.dmac_laddress, 2993087a28d1SDavid Gwynne bgep->statistics.cookie.dmac_size, 2994087a28d1SDavid Gwynne 1, 2995087a28d1SDavid Gwynne sizeof(bge_statistics_t))); 2996087a28d1SDavid Gwynne 299762387023Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 2998087a28d1SDavid Gwynne BGE_DEBUG(("TXD STATUS BLOCK: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)", 2999087a28d1SDavid Gwynne bgep->status_block.mem_va, 3000087a28d1SDavid Gwynne bgep->status_block.alength, 3001087a28d1SDavid Gwynne bgep->status_block.offset, 3002087a28d1SDavid Gwynne bgep->status_block.cookie.dmac_laddress, 3003087a28d1SDavid Gwynne bgep->status_block.cookie.dmac_size, 3004087a28d1SDavid Gwynne 1, 3005087a28d1SDavid Gwynne sizeof(bge_status_t))); 3006087a28d1SDavid Gwynne 3007087a28d1SDavid Gwynne BGE_DEBUG(("TXD DONE: va=%p alen=%d off=%d pa=%llx psz=%d", 3008087a28d1SDavid Gwynne area.mem_va, 3009087a28d1SDavid Gwynne area.alength, 3010087a28d1SDavid Gwynne area.offset, 3011087a28d1SDavid Gwynne area.cookie.dmac_laddress, 3012087a28d1SDavid Gwynne area.cookie.dmac_size)); 3013087a28d1SDavid Gwynne 301462387023Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 3015087a28d1SDavid Gwynne 301662387023Sdduvall DMA_ZERO(bgep->status_block); 301762387023Sdduvall 301862387023Sdduvall return (DDI_SUCCESS); 301962387023Sdduvall } 302062387023Sdduvall 3021087a28d1SDavid Gwynne #undef BGE_DBG 3022087a28d1SDavid Gwynne #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 3023087a28d1SDavid Gwynne 302462387023Sdduvall /* 302562387023Sdduvall * This routine frees the transmit and receive buffers and descriptors. 302662387023Sdduvall * Make sure the chip is stopped before calling it! 302762387023Sdduvall */ 302800d0963fSdilpreet void 302962387023Sdduvall bge_free_bufs(bge_t *bgep) 303062387023Sdduvall { 303162387023Sdduvall int split; 303262387023Sdduvall 303362387023Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 303462387023Sdduvall (void *)bgep)); 303562387023Sdduvall 303662387023Sdduvall bge_free_dma_mem(&bgep->tx_desc); 303762387023Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 303862387023Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 303962387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 304062387023Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 304162387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 304262387023Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 304362387023Sdduvall } 304462387023Sdduvall 304562387023Sdduvall /* 304662387023Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 304762387023Sdduvall */ 304862387023Sdduvall 304962387023Sdduvall static void 305062387023Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 305162387023Sdduvall { 305262387023Sdduvall struct ether_addr sysaddr; 305362387023Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 305462387023Sdduvall uchar_t *bytes; 305562387023Sdduvall int *ints; 305662387023Sdduvall uint_t nelts; 305762387023Sdduvall int err; 305862387023Sdduvall 305962387023Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 306062387023Sdduvall (void *)bgep)); 306162387023Sdduvall 306262387023Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 306362387023Sdduvall cidp->hw_mac_addr, 306462387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 306562387023Sdduvall cidp->vendor_addr.set ? "" : "not ")); 306662387023Sdduvall 306762387023Sdduvall /* 306862387023Sdduvall * The "vendor's factory-set address" may already have 306962387023Sdduvall * been extracted from the chip, but if the property 307062387023Sdduvall * "local-mac-address" is set we use that instead. It 307162387023Sdduvall * will normally be set by OBP, but it could also be 307262387023Sdduvall * specified in a .conf file(!) 307362387023Sdduvall * 307462387023Sdduvall * There doesn't seem to be a way to define byte-array 307562387023Sdduvall * properties in a .conf, so we check whether it looks 307662387023Sdduvall * like an array of 6 ints instead. 307762387023Sdduvall * 307862387023Sdduvall * Then, we check whether it looks like an array of 6 307962387023Sdduvall * bytes (which it should, if OBP set it). If we can't 308062387023Sdduvall * make sense of it either way, we'll ignore it. 308162387023Sdduvall */ 308262387023Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 308362387023Sdduvall DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 308462387023Sdduvall if (err == DDI_PROP_SUCCESS) { 308562387023Sdduvall if (nelts == ETHERADDRL) { 308662387023Sdduvall while (nelts--) 308762387023Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 3088ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE; 308962387023Sdduvall } 309062387023Sdduvall ddi_prop_free(ints); 309162387023Sdduvall } 309262387023Sdduvall 309362387023Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 309462387023Sdduvall DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 309562387023Sdduvall if (err == DDI_PROP_SUCCESS) { 309662387023Sdduvall if (nelts == ETHERADDRL) { 309762387023Sdduvall while (nelts--) 309862387023Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 3099ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE; 310062387023Sdduvall } 310162387023Sdduvall ddi_prop_free(bytes); 310262387023Sdduvall } 310362387023Sdduvall 310462387023Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 310562387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 310662387023Sdduvall cidp->vendor_addr.set ? "" : "not ")); 310762387023Sdduvall 310862387023Sdduvall /* 310962387023Sdduvall * Look up the OBP property "local-mac-address?". Note that even 311062387023Sdduvall * though its value is a string (which should be "true" or "false"), 311162387023Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 311262387023Sdduvall * the buffer first and then fetch the property as an untyped array; 311362387023Sdduvall * this may or may not include a final NUL, but since there will 311462387023Sdduvall * always be one left at the end of the buffer we can now treat it 311562387023Sdduvall * as a string anyway. 311662387023Sdduvall */ 311762387023Sdduvall nelts = sizeof (propbuf); 311862387023Sdduvall bzero(propbuf, nelts--); 311962387023Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 312062387023Sdduvall DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 312162387023Sdduvall 312262387023Sdduvall /* 312362387023Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 312462387023Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 312562387023Sdduvall * 'local-mac-address? = false', use "the system address" instead 312662387023Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 312762387023Sdduvall */ 3128ed8845d8Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0) 312962387023Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 313062387023Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 3131ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE; 313262387023Sdduvall } 313362387023Sdduvall 313462387023Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 313562387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 313662387023Sdduvall cidp->vendor_addr.set ? "" : "not ")); 313762387023Sdduvall 313862387023Sdduvall /* 313962387023Sdduvall * Finally(!), if there's a valid "mac-address" property (created 314062387023Sdduvall * if we netbooted from this interface), we must use this instead 314162387023Sdduvall * of any of the above to ensure that the NFS/install server doesn't 314262387023Sdduvall * get confused by the address changing as Solaris takes over! 314362387023Sdduvall */ 314462387023Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 314562387023Sdduvall DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 314662387023Sdduvall if (err == DDI_PROP_SUCCESS) { 314762387023Sdduvall if (nelts == ETHERADDRL) { 314862387023Sdduvall while (nelts--) 314962387023Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 3150ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE; 315162387023Sdduvall } 315262387023Sdduvall ddi_prop_free(bytes); 315362387023Sdduvall } 315462387023Sdduvall 315562387023Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 315662387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 315762387023Sdduvall cidp->vendor_addr.set ? "" : "not ")); 315862387023Sdduvall } 315962387023Sdduvall 316000d0963fSdilpreet /*ARGSUSED*/ 316100d0963fSdilpreet int 316200d0963fSdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 316300d0963fSdilpreet { 316400d0963fSdilpreet ddi_fm_error_t de; 316500d0963fSdilpreet 316600d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 316700d0963fSdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 316800d0963fSdilpreet return (de.fme_status); 316900d0963fSdilpreet } 317000d0963fSdilpreet 317100d0963fSdilpreet /*ARGSUSED*/ 317200d0963fSdilpreet int 317300d0963fSdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 317400d0963fSdilpreet { 317500d0963fSdilpreet ddi_fm_error_t de; 317600d0963fSdilpreet 317700d0963fSdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 317800d0963fSdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 317900d0963fSdilpreet return (de.fme_status); 318000d0963fSdilpreet } 318100d0963fSdilpreet 318200d0963fSdilpreet /* 318300d0963fSdilpreet * The IO fault service error handling callback function 318400d0963fSdilpreet */ 318500d0963fSdilpreet /*ARGSUSED*/ 318600d0963fSdilpreet static int 318700d0963fSdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 318800d0963fSdilpreet { 318900d0963fSdilpreet /* 319000d0963fSdilpreet * as the driver can always deal with an error in any dma or 319100d0963fSdilpreet * access handle, we can just return the fme_status value. 319200d0963fSdilpreet */ 319300d0963fSdilpreet pci_ereport_post(dip, err, NULL); 319400d0963fSdilpreet return (err->fme_status); 319500d0963fSdilpreet } 319600d0963fSdilpreet 319700d0963fSdilpreet static void 319800d0963fSdilpreet bge_fm_init(bge_t *bgep) 319900d0963fSdilpreet { 320000d0963fSdilpreet ddi_iblock_cookie_t iblk; 320100d0963fSdilpreet 320200d0963fSdilpreet /* Only register with IO Fault Services if we have some capability */ 320300d0963fSdilpreet if (bgep->fm_capabilities) { 320400d0963fSdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 320500d0963fSdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 320600d0963fSdilpreet 320700d0963fSdilpreet /* Register capabilities with IO Fault Services */ 320800d0963fSdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 320900d0963fSdilpreet 321000d0963fSdilpreet /* 321100d0963fSdilpreet * Initialize pci ereport capabilities if ereport capable 321200d0963fSdilpreet */ 321300d0963fSdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 321400d0963fSdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 321500d0963fSdilpreet pci_ereport_setup(bgep->devinfo); 321600d0963fSdilpreet 321700d0963fSdilpreet /* 321800d0963fSdilpreet * Register error callback if error callback capable 321900d0963fSdilpreet */ 322000d0963fSdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 322100d0963fSdilpreet ddi_fm_handler_register(bgep->devinfo, 322200d0963fSdilpreet bge_fm_error_cb, (void*) bgep); 322300d0963fSdilpreet } else { 322400d0963fSdilpreet /* 322500d0963fSdilpreet * These fields have to be cleared of FMA if there are no 322600d0963fSdilpreet * FMA capabilities at runtime. 322700d0963fSdilpreet */ 322800d0963fSdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 322900d0963fSdilpreet dma_attr.dma_attr_flags = 0; 323000d0963fSdilpreet } 323100d0963fSdilpreet } 323200d0963fSdilpreet 323300d0963fSdilpreet static void 323400d0963fSdilpreet bge_fm_fini(bge_t *bgep) 323500d0963fSdilpreet { 323600d0963fSdilpreet /* Only unregister FMA capabilities if we registered some */ 323700d0963fSdilpreet if (bgep->fm_capabilities) { 323800d0963fSdilpreet 323900d0963fSdilpreet /* 324000d0963fSdilpreet * Release any resources allocated by pci_ereport_setup() 324100d0963fSdilpreet */ 324200d0963fSdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 324300d0963fSdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 324400d0963fSdilpreet pci_ereport_teardown(bgep->devinfo); 324500d0963fSdilpreet 324600d0963fSdilpreet /* 324700d0963fSdilpreet * Un-register error callback if error callback capable 324800d0963fSdilpreet */ 324900d0963fSdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 325000d0963fSdilpreet ddi_fm_handler_unregister(bgep->devinfo); 325100d0963fSdilpreet 325200d0963fSdilpreet /* Unregister from IO Fault Services */ 325300d0963fSdilpreet ddi_fm_fini(bgep->devinfo); 325400d0963fSdilpreet } 325500d0963fSdilpreet } 325600d0963fSdilpreet 325762387023Sdduvall static void 325867f02347Srandyf #ifdef BGE_IPMI_ASF 325967f02347Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 326067f02347Srandyf #else 326162387023Sdduvall bge_unattach(bge_t *bgep) 326267f02347Srandyf #endif 326362387023Sdduvall { 326462387023Sdduvall BGE_TRACE(("bge_unattach($%p)", 326562387023Sdduvall (void *)bgep)); 326662387023Sdduvall 326762387023Sdduvall /* 326862387023Sdduvall * Flag that no more activity may be initiated 326962387023Sdduvall */ 327062387023Sdduvall bgep->progress &= ~PROGRESS_READY; 327162387023Sdduvall 327262387023Sdduvall /* 327362387023Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 327462387023Sdduvall * Clean up and free all BGE data structures 327562387023Sdduvall */ 3276dd4eeefdSeota if (bgep->periodic_id != NULL) { 3277dd4eeefdSeota ddi_periodic_delete(bgep->periodic_id); 3278dd4eeefdSeota bgep->periodic_id = NULL; 327962387023Sdduvall } 3280087a28d1SDavid Gwynne 328162387023Sdduvall if (bgep->progress & PROGRESS_KSTATS) 328262387023Sdduvall bge_fini_kstats(bgep); 328362387023Sdduvall if (bgep->progress & PROGRESS_PHY) 328462387023Sdduvall bge_phys_reset(bgep); 328562387023Sdduvall if (bgep->progress & PROGRESS_HWINT) { 328662387023Sdduvall mutex_enter(bgep->genlock); 328767f02347Srandyf #ifdef BGE_IPMI_ASF 328800d0963fSdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 328900d0963fSdilpreet #else 329000d0963fSdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 329100d0963fSdilpreet #endif 329200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 329300d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 329400d0963fSdilpreet #ifdef BGE_IPMI_ASF 329567f02347Srandyf if (bgep->asf_enabled) { 329667f02347Srandyf /* 329767f02347Srandyf * This register has been overlaid. We restore its 329867f02347Srandyf * initial value here. 329967f02347Srandyf */ 330067f02347Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 330167f02347Srandyf BGE_NIC_DATA_SIG); 330267f02347Srandyf } 330367f02347Srandyf #endif 330400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 330500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 330600d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 330700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 330800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 330900d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 331062387023Sdduvall mutex_exit(bgep->genlock); 331162387023Sdduvall } 331262387023Sdduvall if (bgep->progress & PROGRESS_INTR) { 331300d0963fSdilpreet bge_intr_disable(bgep); 331462387023Sdduvall bge_fini_rings(bgep); 331562387023Sdduvall } 331600d0963fSdilpreet if (bgep->progress & PROGRESS_HWINT) { 331700d0963fSdilpreet bge_rem_intrs(bgep); 331800d0963fSdilpreet rw_destroy(bgep->errlock); 331900d0963fSdilpreet mutex_destroy(bgep->softintrlock); 332000d0963fSdilpreet mutex_destroy(bgep->genlock); 332100d0963fSdilpreet } 332262387023Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 332362387023Sdduvall ddi_remove_softintr(bgep->factotum_id); 332462387023Sdduvall if (bgep->progress & PROGRESS_RESCHED) 3325931dca7dSgs150176 ddi_remove_softintr(bgep->drain_id); 332600d0963fSdilpreet if (bgep->progress & PROGRESS_BUFS) 332762387023Sdduvall bge_free_bufs(bgep); 3328087a28d1SDavid Gwynne if (bgep->progress & PROGRESS_REGS) { 332962387023Sdduvall ddi_regs_map_free(&bgep->io_handle); 3330087a28d1SDavid Gwynne if (bgep->ape_enabled) 3331087a28d1SDavid Gwynne ddi_regs_map_free(&bgep->ape_handle); 3332087a28d1SDavid Gwynne } 333362387023Sdduvall if (bgep->progress & PROGRESS_CFG) 333462387023Sdduvall pci_config_teardown(&bgep->cfg_handle); 333562387023Sdduvall 333600d0963fSdilpreet bge_fm_fini(bgep); 333700d0963fSdilpreet 333862387023Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 3339931dca7dSgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t)); 334062387023Sdduvall kmem_free(bgep, sizeof (*bgep)); 334162387023Sdduvall } 334262387023Sdduvall 334362387023Sdduvall static int 334462387023Sdduvall bge_resume(dev_info_t *devinfo) 334562387023Sdduvall { 334662387023Sdduvall bge_t *bgep; /* Our private data */ 334762387023Sdduvall chip_id_t *cidp; 334862387023Sdduvall chip_id_t chipid; 334962387023Sdduvall 335062387023Sdduvall bgep = ddi_get_driver_private(devinfo); 335162387023Sdduvall if (bgep == NULL) 335262387023Sdduvall return (DDI_FAILURE); 335362387023Sdduvall 335462387023Sdduvall /* 335562387023Sdduvall * Refuse to resume if the data structures aren't consistent 335662387023Sdduvall */ 335762387023Sdduvall if (bgep->devinfo != devinfo) 335862387023Sdduvall return (DDI_FAILURE); 335962387023Sdduvall 336067f02347Srandyf #ifdef BGE_IPMI_ASF 336167f02347Srandyf /* 336267f02347Srandyf * Power management hasn't been supported in BGE now. If you 336367f02347Srandyf * want to implement it, please add the ASF/IPMI related 336467f02347Srandyf * code here. 336567f02347Srandyf */ 336667f02347Srandyf 336767f02347Srandyf #endif 336867f02347Srandyf 336962387023Sdduvall /* 337062387023Sdduvall * Read chip ID & set up config space command register(s) 337162387023Sdduvall * Refuse to resume if the chip has changed its identity! 337262387023Sdduvall */ 337362387023Sdduvall cidp = &bgep->chipid; 337400d0963fSdilpreet mutex_enter(bgep->genlock); 337562387023Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 337600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 337700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 337800d0963fSdilpreet mutex_exit(bgep->genlock); 337900d0963fSdilpreet return (DDI_FAILURE); 338000d0963fSdilpreet } 338100d0963fSdilpreet mutex_exit(bgep->genlock); 338262387023Sdduvall if (chipid.vendor != cidp->vendor) 338362387023Sdduvall return (DDI_FAILURE); 338462387023Sdduvall if (chipid.device != cidp->device) 338562387023Sdduvall return (DDI_FAILURE); 338662387023Sdduvall if (chipid.revision != cidp->revision) 338762387023Sdduvall return (DDI_FAILURE); 338862387023Sdduvall if (chipid.asic_rev != cidp->asic_rev) 338962387023Sdduvall return (DDI_FAILURE); 339062387023Sdduvall 339162387023Sdduvall /* 339262387023Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 339362387023Sdduvall */ 339462387023Sdduvall mutex_enter(bgep->genlock); 339500d0963fSdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 339600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 339700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 339800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 339900d0963fSdilpreet mutex_exit(bgep->genlock); 340000d0963fSdilpreet return (DDI_FAILURE); 340100d0963fSdilpreet } 340200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 340300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 340400d0963fSdilpreet mutex_exit(bgep->genlock); 340500d0963fSdilpreet return (DDI_FAILURE); 340600d0963fSdilpreet } 340700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 340800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 340900d0963fSdilpreet mutex_exit(bgep->genlock); 341000d0963fSdilpreet return (DDI_FAILURE); 341100d0963fSdilpreet } 341262387023Sdduvall mutex_exit(bgep->genlock); 341362387023Sdduvall return (DDI_SUCCESS); 341462387023Sdduvall } 341562387023Sdduvall 3416087a28d1SDavid Gwynne static int 3417087a28d1SDavid Gwynne bge_fw_img_is_valid(bge_t *bgep, uint32_t offset) 3418087a28d1SDavid Gwynne { 3419087a28d1SDavid Gwynne uint32_t val; 3420087a28d1SDavid Gwynne 3421087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val) || 3422087a28d1SDavid Gwynne (val & 0xfc000000) != 0x0c000000 || 3423087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 4, &val) || 3424087a28d1SDavid Gwynne val != 0) 3425087a28d1SDavid Gwynne return (0); 3426087a28d1SDavid Gwynne 3427087a28d1SDavid Gwynne return (1); 3428087a28d1SDavid Gwynne } 3429087a28d1SDavid Gwynne 3430087a28d1SDavid Gwynne static void 3431087a28d1SDavid Gwynne bge_read_mgmtfw_ver(bge_t *bgep) 3432087a28d1SDavid Gwynne { 3433087a28d1SDavid Gwynne uint32_t val; 3434087a28d1SDavid Gwynne uint32_t offset; 3435087a28d1SDavid Gwynne uint32_t start; 3436087a28d1SDavid Gwynne int i, vlen; 3437087a28d1SDavid Gwynne 3438087a28d1SDavid Gwynne for (offset = NVM_DIR_START; 3439087a28d1SDavid Gwynne offset < NVM_DIR_END; 3440087a28d1SDavid Gwynne offset += NVM_DIRENT_SIZE) { 3441087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val)) 3442087a28d1SDavid Gwynne return; 3443087a28d1SDavid Gwynne 3444087a28d1SDavid Gwynne if ((val >> NVM_DIRTYPE_SHIFT) == NVM_DIRTYPE_ASFINI) 3445087a28d1SDavid Gwynne break; 3446087a28d1SDavid Gwynne } 3447087a28d1SDavid Gwynne 3448087a28d1SDavid Gwynne if (offset == NVM_DIR_END) 3449087a28d1SDavid Gwynne return; 3450087a28d1SDavid Gwynne 3451087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset - 4, &start)) 3452087a28d1SDavid Gwynne return; 3453087a28d1SDavid Gwynne 3454087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + 4, &offset) || 3455087a28d1SDavid Gwynne !bge_fw_img_is_valid(bgep, offset) || 3456087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 8, &val)) 3457087a28d1SDavid Gwynne return; 3458087a28d1SDavid Gwynne 3459087a28d1SDavid Gwynne offset += val - start; 3460087a28d1SDavid Gwynne 3461087a28d1SDavid Gwynne vlen = strlen(bgep->fw_version); 3462087a28d1SDavid Gwynne 3463087a28d1SDavid Gwynne bgep->fw_version[vlen++] = ','; 3464087a28d1SDavid Gwynne bgep->fw_version[vlen++] = ' '; 3465087a28d1SDavid Gwynne 3466087a28d1SDavid Gwynne for (i = 0; i < 4; i++) { 3467087a28d1SDavid Gwynne uint32_t v; 3468087a28d1SDavid Gwynne 3469087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &v)) 3470087a28d1SDavid Gwynne return; 3471087a28d1SDavid Gwynne 3472087a28d1SDavid Gwynne v = BE_32(v); 3473087a28d1SDavid Gwynne 3474087a28d1SDavid Gwynne offset += sizeof(v); 3475087a28d1SDavid Gwynne 3476087a28d1SDavid Gwynne if (vlen > BGE_FW_VER_SIZE - sizeof(v)) { 3477087a28d1SDavid Gwynne memcpy(&bgep->fw_version[vlen], &v, BGE_FW_VER_SIZE - vlen); 3478087a28d1SDavid Gwynne break; 3479087a28d1SDavid Gwynne } 3480087a28d1SDavid Gwynne 3481087a28d1SDavid Gwynne memcpy(&bgep->fw_version[vlen], &v, sizeof(v)); 3482087a28d1SDavid Gwynne vlen += sizeof(v); 3483087a28d1SDavid Gwynne } 3484087a28d1SDavid Gwynne } 3485087a28d1SDavid Gwynne 3486087a28d1SDavid Gwynne static void 3487087a28d1SDavid Gwynne bge_read_dash_ver(bge_t *bgep) 3488087a28d1SDavid Gwynne { 3489087a28d1SDavid Gwynne int vlen; 3490087a28d1SDavid Gwynne uint32_t apedata; 3491087a28d1SDavid Gwynne char *fwtype; 3492087a28d1SDavid Gwynne 3493087a28d1SDavid Gwynne if (!bgep->ape_enabled || !bgep->asf_enabled) 3494087a28d1SDavid Gwynne return; 3495087a28d1SDavid Gwynne 3496087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_SEG_SIG); 3497087a28d1SDavid Gwynne if (apedata != APE_SEG_SIG_MAGIC) 3498087a28d1SDavid Gwynne return; 3499087a28d1SDavid Gwynne 3500087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS); 3501087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY)) 3502087a28d1SDavid Gwynne return; 3503087a28d1SDavid Gwynne 3504087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_VERSION); 3505087a28d1SDavid Gwynne 3506087a28d1SDavid Gwynne if (bge_ape_get32(bgep, BGE_APE_FW_FEATURES) & 3507087a28d1SDavid Gwynne BGE_APE_FW_FEATURE_NCSI) { 3508087a28d1SDavid Gwynne bgep->ape_has_ncsi = B_TRUE; 3509087a28d1SDavid Gwynne fwtype = "NCSI"; 3510087a28d1SDavid Gwynne } else if ((bgep->chipid.device == DEVICE_ID_5725) || 3511087a28d1SDavid Gwynne (bgep->chipid.device == DEVICE_ID_5727)) { 3512087a28d1SDavid Gwynne fwtype = "SMASH"; 3513087a28d1SDavid Gwynne } else { 3514087a28d1SDavid Gwynne fwtype = "DASH"; 3515087a28d1SDavid Gwynne } 3516087a28d1SDavid Gwynne 3517087a28d1SDavid Gwynne vlen = strlen(bgep->fw_version); 3518087a28d1SDavid Gwynne 3519087a28d1SDavid Gwynne snprintf(&bgep->fw_version[vlen], BGE_FW_VER_SIZE - vlen, 3520087a28d1SDavid Gwynne " %s v%d.%d.%d.%d", fwtype, 3521087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT, 3522087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT, 3523087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT, 3524087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_BLDMSK)); 3525087a28d1SDavid Gwynne } 3526087a28d1SDavid Gwynne 3527087a28d1SDavid Gwynne static void 3528087a28d1SDavid Gwynne bge_read_bc_ver(bge_t *bgep) 3529087a28d1SDavid Gwynne { 3530087a28d1SDavid Gwynne uint32_t val; 3531087a28d1SDavid Gwynne uint32_t offset; 3532087a28d1SDavid Gwynne uint32_t start; 3533087a28d1SDavid Gwynne uint32_t ver_offset; 3534087a28d1SDavid Gwynne int i, dst_off; 3535087a28d1SDavid Gwynne uint32_t major; 3536087a28d1SDavid Gwynne uint32_t minor; 3537087a28d1SDavid Gwynne boolean_t newver = B_FALSE; 3538087a28d1SDavid Gwynne 3539087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, 0xc, &offset) || 3540087a28d1SDavid Gwynne bge_nvmem_read32(bgep, 0x4, &start)) 3541087a28d1SDavid Gwynne return; 3542087a28d1SDavid Gwynne 3543087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val)) 3544087a28d1SDavid Gwynne return; 3545087a28d1SDavid Gwynne 3546087a28d1SDavid Gwynne if ((val & 0xfc000000) == 0x0c000000) { 3547087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + 4, &val)) 3548087a28d1SDavid Gwynne return; 3549087a28d1SDavid Gwynne 3550087a28d1SDavid Gwynne if (val == 0) 3551087a28d1SDavid Gwynne newver = B_TRUE; 3552087a28d1SDavid Gwynne } 3553087a28d1SDavid Gwynne 3554087a28d1SDavid Gwynne dst_off = strlen(bgep->fw_version); 3555087a28d1SDavid Gwynne 3556087a28d1SDavid Gwynne if (newver) { 3557087a28d1SDavid Gwynne if (((BGE_FW_VER_SIZE - dst_off) < 16) || 3558087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 8, &ver_offset)) 3559087a28d1SDavid Gwynne return; 3560087a28d1SDavid Gwynne 3561087a28d1SDavid Gwynne offset = offset + ver_offset - start; 3562087a28d1SDavid Gwynne for (i = 0; i < 16; i += 4) { 3563087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + i, &val)) 3564087a28d1SDavid Gwynne return; 3565087a28d1SDavid Gwynne val = BE_32(val); 3566087a28d1SDavid Gwynne memcpy(bgep->fw_version + dst_off + i, &val, 3567087a28d1SDavid Gwynne sizeof(val)); 3568087a28d1SDavid Gwynne } 3569087a28d1SDavid Gwynne } else { 3570087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, NVM_PTREV_BCVER, &ver_offset)) 3571087a28d1SDavid Gwynne return; 3572087a28d1SDavid Gwynne 3573087a28d1SDavid Gwynne major = (ver_offset & NVM_BCVER_MAJMSK) >> NVM_BCVER_MAJSFT; 3574087a28d1SDavid Gwynne minor = ver_offset & NVM_BCVER_MINMSK; 3575087a28d1SDavid Gwynne snprintf(&bgep->fw_version[dst_off], BGE_FW_VER_SIZE - dst_off, 3576087a28d1SDavid Gwynne "v%d.%02d", major, minor); 3577087a28d1SDavid Gwynne } 3578087a28d1SDavid Gwynne } 3579087a28d1SDavid Gwynne 3580087a28d1SDavid Gwynne static void 3581087a28d1SDavid Gwynne bge_read_fw_ver(bge_t *bgep) 3582087a28d1SDavid Gwynne { 3583087a28d1SDavid Gwynne uint32_t val; 3584087a28d1SDavid Gwynne uint32_t magic; 3585087a28d1SDavid Gwynne 3586087a28d1SDavid Gwynne *bgep->fw_version = 0; 3587087a28d1SDavid Gwynne 3588087a28d1SDavid Gwynne if ((bgep->chipid.nvtype == BGE_NVTYPE_NONE) || 3589087a28d1SDavid Gwynne (bgep->chipid.nvtype == BGE_NVTYPE_UNKNOWN)) { 3590087a28d1SDavid Gwynne snprintf(bgep->fw_version, sizeof(bgep->fw_version), "sb"); 3591087a28d1SDavid Gwynne return; 3592087a28d1SDavid Gwynne } 3593087a28d1SDavid Gwynne 3594087a28d1SDavid Gwynne mutex_enter(bgep->genlock); 3595087a28d1SDavid Gwynne 3596087a28d1SDavid Gwynne bge_nvmem_read32(bgep, 0, &magic); 3597087a28d1SDavid Gwynne 3598087a28d1SDavid Gwynne if (magic == EEPROM_MAGIC) { 3599087a28d1SDavid Gwynne bge_read_bc_ver(bgep); 3600087a28d1SDavid Gwynne } else { 3601087a28d1SDavid Gwynne /* ignore other configs for now */ 3602087a28d1SDavid Gwynne mutex_exit(bgep->genlock); 3603087a28d1SDavid Gwynne return; 3604087a28d1SDavid Gwynne } 3605087a28d1SDavid Gwynne 3606087a28d1SDavid Gwynne if (bgep->ape_enabled) { 3607087a28d1SDavid Gwynne if (bgep->asf_enabled) { 3608087a28d1SDavid Gwynne bge_read_dash_ver(bgep); 3609087a28d1SDavid Gwynne } 3610087a28d1SDavid Gwynne } else if (bgep->asf_enabled) { 3611087a28d1SDavid Gwynne bge_read_mgmtfw_ver(bgep); 3612087a28d1SDavid Gwynne } 3613087a28d1SDavid Gwynne 3614087a28d1SDavid Gwynne mutex_exit(bgep->genlock); 3615087a28d1SDavid Gwynne 3616087a28d1SDavid Gwynne bgep->fw_version[BGE_FW_VER_SIZE - 1] = 0; /* safety */ 3617087a28d1SDavid Gwynne } 3618087a28d1SDavid Gwynne 361962387023Sdduvall /* 362062387023Sdduvall * attach(9E) -- Attach a device to the system 362162387023Sdduvall * 362262387023Sdduvall * Called once for each board successfully probed. 362362387023Sdduvall */ 362462387023Sdduvall static int 362562387023Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 362662387023Sdduvall { 362762387023Sdduvall bge_t *bgep; /* Our private data */ 3628ba2e4443Sseb mac_register_t *macp; 362962387023Sdduvall chip_id_t *cidp; 363062387023Sdduvall caddr_t regs; 363162387023Sdduvall int instance; 363262387023Sdduvall int err; 363362387023Sdduvall int intr_types; 3634087a28d1SDavid Gwynne int *props = NULL; 3635087a28d1SDavid Gwynne uint_t numProps; 3636087a28d1SDavid Gwynne uint32_t regval; 3637087a28d1SDavid Gwynne uint32_t pci_state_reg; 363867f02347Srandyf #ifdef BGE_IPMI_ASF 363967f02347Srandyf uint32_t mhcrValue; 3640a4de4ba2Sml149210 #ifdef __sparc 3641a4de4ba2Sml149210 uint16_t value16; 3642a4de4ba2Sml149210 #endif 3643a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 3644a4de4ba2Sml149210 int retval; 3645a4de4ba2Sml149210 #endif 364667f02347Srandyf #endif 364762387023Sdduvall 364862387023Sdduvall instance = ddi_get_instance(devinfo); 364962387023Sdduvall 365062387023Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 365162387023Sdduvall (void *)devinfo, cmd, instance)); 365262387023Sdduvall BGE_BRKPT(NULL, "bge_attach"); 365362387023Sdduvall 365462387023Sdduvall switch (cmd) { 365562387023Sdduvall default: 365662387023Sdduvall return (DDI_FAILURE); 365762387023Sdduvall 365862387023Sdduvall case DDI_RESUME: 365962387023Sdduvall return (bge_resume(devinfo)); 366062387023Sdduvall 366162387023Sdduvall case DDI_ATTACH: 366262387023Sdduvall break; 366362387023Sdduvall } 366462387023Sdduvall 366562387023Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 3666931dca7dSgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP); 366762387023Sdduvall ddi_set_driver_private(devinfo, bgep); 366862387023Sdduvall bgep->bge_guard = BGE_GUARD; 366962387023Sdduvall bgep->devinfo = devinfo; 3670e7801d59Ssowmini bgep->param_drain_max = 64; 3671e7801d59Ssowmini bgep->param_msi_cnt = 0; 3672e7801d59Ssowmini bgep->param_loop_mode = 0; 367362387023Sdduvall 367462387023Sdduvall /* 367562387023Sdduvall * Initialize more fields in BGE private data 367662387023Sdduvall */ 367762387023Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 367862387023Sdduvall DDI_PROP_DONTPASS, debug_propname, bge_debug); 367962387023Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 368062387023Sdduvall BGE_DRIVER_NAME, instance); 368162387023Sdduvall 368262387023Sdduvall /* 368300d0963fSdilpreet * Initialize for fma support 368400d0963fSdilpreet */ 368500d0963fSdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 368600d0963fSdilpreet DDI_PROP_DONTPASS, fm_cap, 368700d0963fSdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 368800d0963fSdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 368900d0963fSdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 369000d0963fSdilpreet bge_fm_init(bgep); 369100d0963fSdilpreet 369200d0963fSdilpreet /* 369362387023Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 369462387023Sdduvall * a power of 2) and convert to a mask. This can be used to 369562387023Sdduvall * determine whether a message buffer crosses a page boundary. 369662387023Sdduvall * Note: in 2s complement binary notation, if X is a power of 369762387023Sdduvall * 2, then -X has the representation "11...1100...00". 369862387023Sdduvall */ 369962387023Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 370062387023Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 370162387023Sdduvall bgep->pagemask = -bgep->pagemask; 370262387023Sdduvall 370362387023Sdduvall /* 370462387023Sdduvall * Map config space registers 370562387023Sdduvall * Read chip ID & set up config space command register(s) 370662387023Sdduvall * 370762387023Sdduvall * Note: this leaves the chip accessible by Memory Space 370862387023Sdduvall * accesses, but with interrupts and Bus Mastering off. 370962387023Sdduvall * This should ensure that nothing untoward will happen 371062387023Sdduvall * if it has been left active by the (net-)bootloader. 371162387023Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 371262387023Sdduvall * and allow interrupts only when everything else is set up. 371362387023Sdduvall */ 371462387023Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 3715*76a3936eSHans Rosenfeld 3716*76a3936eSHans Rosenfeld bgep->ape_enabled = B_FALSE; 3717*76a3936eSHans Rosenfeld bgep->ape_regs = NULL; 3718*76a3936eSHans Rosenfeld 3719*76a3936eSHans Rosenfeld if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 3720*76a3936eSHans Rosenfeld DEVICE_5725_SERIES_CHIPSETS(bgep)) { 3721*76a3936eSHans Rosenfeld err = ddi_regs_map_setup(devinfo, BGE_PCI_APEREGS_RNUMBER, 3722*76a3936eSHans Rosenfeld ®s, 0, 0, &bge_reg_accattr, &bgep->ape_handle); 3723*76a3936eSHans Rosenfeld if (err != DDI_SUCCESS) { 3724*76a3936eSHans Rosenfeld ddi_regs_map_free(&bgep->io_handle); 3725*76a3936eSHans Rosenfeld bge_problem(bgep, "ddi_regs_map_setup() failed"); 3726*76a3936eSHans Rosenfeld goto attach_fail; 3727*76a3936eSHans Rosenfeld } 3728*76a3936eSHans Rosenfeld bgep->ape_regs = regs; 3729*76a3936eSHans Rosenfeld bgep->ape_enabled = B_TRUE; 3730*76a3936eSHans Rosenfeld 3731*76a3936eSHans Rosenfeld /* 3732*76a3936eSHans Rosenfeld * Allow reads and writes to the 3733*76a3936eSHans Rosenfeld * APE register and memory space. 3734*76a3936eSHans Rosenfeld */ 3735*76a3936eSHans Rosenfeld 3736*76a3936eSHans Rosenfeld pci_state_reg = pci_config_get32(bgep->cfg_handle, 3737*76a3936eSHans Rosenfeld PCI_CONF_BGE_PCISTATE); 3738*76a3936eSHans Rosenfeld pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR | 3739*76a3936eSHans Rosenfeld PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR; 3740*76a3936eSHans Rosenfeld pci_config_put32(bgep->cfg_handle, 3741*76a3936eSHans Rosenfeld PCI_CONF_BGE_PCISTATE, pci_state_reg); 3742*76a3936eSHans Rosenfeld bge_ape_lock_init(bgep); 3743*76a3936eSHans Rosenfeld } 3744*76a3936eSHans Rosenfeld 374567f02347Srandyf #ifdef BGE_IPMI_ASF 3746a4de4ba2Sml149210 #ifdef __sparc 3747dc3f9a75Syong tan - Sun Microsystems - Beijing China /* 3748dc3f9a75Syong tan - Sun Microsystems - Beijing China * We need to determine the type of chipset for accessing some configure 3749dc3f9a75Syong tan - Sun Microsystems - Beijing China * registers. (This information will be used by bge_ind_put32, 3750dc3f9a75Syong tan - Sun Microsystems - Beijing China * bge_ind_get32 and bge_nic_read32) 3751dc3f9a75Syong tan - Sun Microsystems - Beijing China */ 3752dc3f9a75Syong tan - Sun Microsystems - Beijing China bgep->chipid.device = pci_config_get16(bgep->cfg_handle, 3753dc3f9a75Syong tan - Sun Microsystems - Beijing China PCI_CONF_DEVID); 3754a4de4ba2Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM); 3755a4de4ba2Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME); 3756a4de4ba2Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16); 3757a4de4ba2Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 3758a4de4ba2Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 3759a4de4ba2Sml149210 MHCR_MASK_INTERRUPT_MODE | 3760a4de4ba2Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 3761a4de4ba2Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 3762a4de4ba2Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 3763a4de4ba2Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 3764dc3f9a75Syong tan - Sun Microsystems - Beijing China /* 3765dc3f9a75Syong tan - Sun Microsystems - Beijing China * For some chipsets (e.g., BCM5718), if MHCR_ENABLE_ENDIAN_BYTE_SWAP 3766dc3f9a75Syong tan - Sun Microsystems - Beijing China * has been set in PCI_CONF_COMM already, we need to write the 3767dc3f9a75Syong tan - Sun Microsystems - Beijing China * byte-swapped value to it. So we just write zero first for simplicity. 3768dc3f9a75Syong tan - Sun Microsystems - Beijing China */ 3769087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 3770087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) 3771dc3f9a75Syong tan - Sun Microsystems - Beijing China pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, 0); 3772087a28d1SDavid Gwynne #else 3773087a28d1SDavid Gwynne mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 3774087a28d1SDavid Gwynne MHCR_ENABLE_TAGGED_STATUS_MODE | 3775087a28d1SDavid Gwynne MHCR_MASK_INTERRUPT_MODE | 3776087a28d1SDavid Gwynne MHCR_MASK_PCI_INT_OUTPUT | 3777087a28d1SDavid Gwynne MHCR_CLEAR_INTERRUPT_INTA; 3778087a28d1SDavid Gwynne #endif 3779a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue); 3780a4de4ba2Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG, 3781a4de4ba2Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) | 3782a4de4ba2Sml149210 MEMORY_ARBITER_ENABLE); 378367f02347Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 378467f02347Srandyf bgep->asf_wordswapped = B_TRUE; 378567f02347Srandyf } else { 378667f02347Srandyf bgep->asf_wordswapped = B_FALSE; 378767f02347Srandyf } 378867f02347Srandyf bge_asf_get_config(bgep); 378967f02347Srandyf #endif 379062387023Sdduvall if (err != DDI_SUCCESS) { 379162387023Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 379262387023Sdduvall goto attach_fail; 379362387023Sdduvall } 379462387023Sdduvall bgep->progress |= PROGRESS_CFG; 379562387023Sdduvall cidp = &bgep->chipid; 379662387023Sdduvall bzero(cidp, sizeof(*cidp)); 379762387023Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 379800d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 379900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 380000d0963fSdilpreet goto attach_fail; 380100d0963fSdilpreet } 380262387023Sdduvall 380367f02347Srandyf #ifdef BGE_IPMI_ASF 380467f02347Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 380567f02347Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 380667f02347Srandyf bgep->asf_newhandshake = B_TRUE; 380767f02347Srandyf } else { 380867f02347Srandyf bgep->asf_newhandshake = B_FALSE; 380967f02347Srandyf } 381067f02347Srandyf #endif 381167f02347Srandyf 381262387023Sdduvall /* 381362387023Sdduvall * Update those parts of the chip ID derived from volatile 381462387023Sdduvall * registers with the values seen by OBP (in case the chip 381562387023Sdduvall * has been reset externally and therefore lost them). 381662387023Sdduvall */ 381762387023Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 381862387023Sdduvall DDI_PROP_DONTPASS, subven_propname, cidp->subven); 381962387023Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 382062387023Sdduvall DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 382162387023Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 382262387023Sdduvall DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 382362387023Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 382462387023Sdduvall DDI_PROP_DONTPASS, latency_propname, cidp->latency); 382562387023Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 382662387023Sdduvall DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 382762387023Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 382862387023Sdduvall DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 3829087a28d1SDavid Gwynne cidp->eee = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 3830087a28d1SDavid Gwynne DDI_PROP_DONTPASS, eee_propname, cidp->eee); 383162387023Sdduvall 38326e6ed1baSyong tan - Sun Microsystems - Beijing China cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 38336e6ed1baSyong tan - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 38346e6ed1baSyong tan - Sun Microsystems - Beijing China if ((cidp->default_mtu < BGE_DEFAULT_MTU) || 38356e6ed1baSyong tan - Sun Microsystems - Beijing China (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 38366e6ed1baSyong tan - Sun Microsystems - Beijing China cidp->default_mtu = BGE_DEFAULT_MTU; 38376e6ed1baSyong tan - Sun Microsystems - Beijing China } 38386e6ed1baSyong tan - Sun Microsystems - Beijing China 383962387023Sdduvall /* 384062387023Sdduvall * Map operating registers 384162387023Sdduvall */ 384262387023Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 384362387023Sdduvall ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 384462387023Sdduvall if (err != DDI_SUCCESS) { 384562387023Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 384662387023Sdduvall goto attach_fail; 384762387023Sdduvall } 384862387023Sdduvall bgep->io_regs = regs; 3849087a28d1SDavid Gwynne 385062387023Sdduvall bgep->progress |= PROGRESS_REGS; 385162387023Sdduvall 385262387023Sdduvall /* 385362387023Sdduvall * Characterise the device, so we know its requirements. 385462387023Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 385562387023Sdduvall */ 385600d0963fSdilpreet if (bge_chip_id_init(bgep) == EIO) { 385700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 385800d0963fSdilpreet goto attach_fail; 385900d0963fSdilpreet } 38604045d941Ssowmini 3861087a28d1SDavid Gwynne err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 3862087a28d1SDavid Gwynne 0, "reg", &props, &numProps); 3863087a28d1SDavid Gwynne if ((err == DDI_PROP_SUCCESS) && (numProps > 0)) { 3864087a28d1SDavid Gwynne bgep->pci_bus = PCI_REG_BUS_G(props[0]); 3865087a28d1SDavid Gwynne bgep->pci_dev = PCI_REG_DEV_G(props[0]); 3866087a28d1SDavid Gwynne bgep->pci_func = PCI_REG_FUNC_G(props[0]); 3867087a28d1SDavid Gwynne ddi_prop_free(props); 3868087a28d1SDavid Gwynne } 3869087a28d1SDavid Gwynne 3870087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) || 3871087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) { 3872087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, CPMU_STATUS_REG); 3873087a28d1SDavid Gwynne if ((bgep->chipid.device == DEVICE_ID_5719) || 3874087a28d1SDavid Gwynne (bgep->chipid.device == DEVICE_ID_5720)) { 3875087a28d1SDavid Gwynne bgep->pci_func = 3876087a28d1SDavid Gwynne ((regval & CPMU_STATUS_FUNC_NUM_5719) >> 3877087a28d1SDavid Gwynne CPMU_STATUS_FUNC_NUM_5719_SHIFT); 3878087a28d1SDavid Gwynne } else { 3879087a28d1SDavid Gwynne bgep->pci_func = ((regval & CPMU_STATUS_FUNC_NUM) >> 3880087a28d1SDavid Gwynne CPMU_STATUS_FUNC_NUM_SHIFT); 3881087a28d1SDavid Gwynne } 3882087a28d1SDavid Gwynne } 3883087a28d1SDavid Gwynne 388462387023Sdduvall err = bge_alloc_bufs(bgep); 388562387023Sdduvall if (err != DDI_SUCCESS) { 388662387023Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 388762387023Sdduvall goto attach_fail; 388862387023Sdduvall } 388900d0963fSdilpreet bgep->progress |= PROGRESS_BUFS; 389062387023Sdduvall 389162387023Sdduvall /* 389262387023Sdduvall * Add the softint handlers: 389362387023Sdduvall * 389462387023Sdduvall * Both of these handlers are used to avoid restrictions on the 389562387023Sdduvall * context and/or mutexes required for some operations. In 389662387023Sdduvall * particular, the hardware interrupt handler and its subfunctions 389762387023Sdduvall * can detect a number of conditions that we don't want to handle 389862387023Sdduvall * in that context or with that set of mutexes held. So, these 389962387023Sdduvall * softints are triggered instead: 390062387023Sdduvall * 3901256e438eSzh199473 * the <resched> softint is triggered if we have previously 390262387023Sdduvall * had to refuse to send a packet because of resource shortage 390362387023Sdduvall * (we've run out of transmit buffers), but the send completion 390462387023Sdduvall * interrupt handler has now detected that more buffers have 390562387023Sdduvall * become available. 390662387023Sdduvall * 390762387023Sdduvall * the <factotum> is triggered if the h/w interrupt handler 390862387023Sdduvall * sees the <link state changed> or <error> bits in the status 390962387023Sdduvall * block. It's also triggered periodically to poll the link 391062387023Sdduvall * state, just in case we aren't getting link status change 391162387023Sdduvall * interrupts ... 391262387023Sdduvall */ 3913931dca7dSgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id, 3914931dca7dSgs150176 NULL, NULL, bge_send_drain, (caddr_t)bgep); 391562387023Sdduvall if (err != DDI_SUCCESS) { 391662387023Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 391762387023Sdduvall goto attach_fail; 391862387023Sdduvall } 391962387023Sdduvall bgep->progress |= PROGRESS_RESCHED; 392062387023Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 392162387023Sdduvall NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 392262387023Sdduvall if (err != DDI_SUCCESS) { 392362387023Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 392462387023Sdduvall goto attach_fail; 392562387023Sdduvall } 392662387023Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 392762387023Sdduvall 392862387023Sdduvall /* Get supported interrupt types */ 392962387023Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 393062387023Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 393162387023Sdduvall 393262387023Sdduvall goto attach_fail; 393362387023Sdduvall } 393462387023Sdduvall 3935f724721bSzh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x", 3936f724721bSzh199473 bgep->ifname, intr_types)); 393762387023Sdduvall 393862387023Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 393962387023Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 394062387023Sdduvall bge_error(bgep, "MSI registration failed, " 394162387023Sdduvall "trying FIXED interrupt type\n"); 394262387023Sdduvall } else { 3943f724721bSzh199473 BGE_DEBUG(("%s: Using MSI interrupt type", 3944f724721bSzh199473 bgep->ifname)); 394562387023Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 394600d0963fSdilpreet bgep->progress |= PROGRESS_HWINT; 394762387023Sdduvall } 394862387023Sdduvall } 394962387023Sdduvall 395000d0963fSdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 395162387023Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 395262387023Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 395362387023Sdduvall bge_error(bgep, "FIXED interrupt " 395462387023Sdduvall "registration failed\n"); 395562387023Sdduvall goto attach_fail; 395662387023Sdduvall } 395762387023Sdduvall 3958f724721bSzh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname)); 395962387023Sdduvall 396062387023Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 396100d0963fSdilpreet bgep->progress |= PROGRESS_HWINT; 396262387023Sdduvall } 396362387023Sdduvall 396400d0963fSdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 396562387023Sdduvall bge_error(bgep, "No interrupts registered\n"); 396662387023Sdduvall goto attach_fail; 396762387023Sdduvall } 396862387023Sdduvall 396962387023Sdduvall /* 397062387023Sdduvall * Note that interrupts are not enabled yet as 397100d0963fSdilpreet * mutex locks are not initialized. Initialize mutex locks. 397200d0963fSdilpreet */ 397300d0963fSdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 397400d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri)); 397500d0963fSdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 397600d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri)); 397700d0963fSdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 397800d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri)); 397900d0963fSdilpreet 398000d0963fSdilpreet /* 398100d0963fSdilpreet * Initialize rings. 398262387023Sdduvall */ 398362387023Sdduvall bge_init_rings(bgep); 398462387023Sdduvall 398562387023Sdduvall /* 398662387023Sdduvall * Now that mutex locks are initialized, enable interrupts. 398762387023Sdduvall */ 398800d0963fSdilpreet bge_intr_enable(bgep); 398900d0963fSdilpreet bgep->progress |= PROGRESS_INTR; 399062387023Sdduvall 399162387023Sdduvall /* 399262387023Sdduvall * Initialise link state variables 399362387023Sdduvall * Stop, reset & reinitialise the chip. 399462387023Sdduvall * Initialise the (internal) PHY. 399562387023Sdduvall */ 399662387023Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 399762387023Sdduvall 399862387023Sdduvall mutex_enter(bgep->genlock); 399962387023Sdduvall 400062387023Sdduvall /* 400162387023Sdduvall * Reset chip & rings to initial state; also reset address 400262387023Sdduvall * filtering, promiscuity, loopback mode. 400362387023Sdduvall */ 400467f02347Srandyf #ifdef BGE_IPMI_ASF 4005a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 4006a4de4ba2Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 4007a4de4ba2Sml149210 #else 400800d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 4009a4de4ba2Sml149210 #endif 401067f02347Srandyf #else 401100d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 401267f02347Srandyf #endif 401300d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 401400d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 401500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 401600d0963fSdilpreet mutex_exit(bgep->genlock); 401700d0963fSdilpreet goto attach_fail; 401800d0963fSdilpreet } 401962387023Sdduvall 4020f724721bSzh199473 #ifdef BGE_IPMI_ASF 4021f724721bSzh199473 if (bgep->asf_enabled) { 4022f724721bSzh199473 bgep->asf_status = ASF_STAT_RUN_INIT; 4023f724721bSzh199473 } 4024f724721bSzh199473 #endif 4025f724721bSzh199473 402662387023Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 402762387023Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 402862387023Sdduvall bgep->promisc = B_FALSE; 402962387023Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 403000d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 403100d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 403200d0963fSdilpreet mutex_exit(bgep->genlock); 403300d0963fSdilpreet goto attach_fail; 403400d0963fSdilpreet } 403500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 403600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 403700d0963fSdilpreet mutex_exit(bgep->genlock); 403800d0963fSdilpreet goto attach_fail; 403900d0963fSdilpreet } 404062387023Sdduvall 404162387023Sdduvall mutex_exit(bgep->genlock); 404262387023Sdduvall 404300d0963fSdilpreet if (bge_phys_init(bgep) == EIO) { 404400d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 404500d0963fSdilpreet goto attach_fail; 404600d0963fSdilpreet } 404762387023Sdduvall bgep->progress |= PROGRESS_PHY; 404862387023Sdduvall 404962387023Sdduvall /* 40504045d941Ssowmini * initialize NDD-tweakable parameters 405162387023Sdduvall */ 405262387023Sdduvall if (bge_nd_init(bgep)) { 405362387023Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 405462387023Sdduvall goto attach_fail; 405562387023Sdduvall } 405662387023Sdduvall bgep->progress |= PROGRESS_NDD; 405762387023Sdduvall 405862387023Sdduvall /* 405962387023Sdduvall * Create & initialise named kstats 406062387023Sdduvall */ 406162387023Sdduvall bge_init_kstats(bgep, instance); 406262387023Sdduvall bgep->progress |= PROGRESS_KSTATS; 406362387023Sdduvall 406462387023Sdduvall /* 406562387023Sdduvall * Determine whether to override the chip's own MAC address 406662387023Sdduvall */ 406762387023Sdduvall bge_find_mac_address(bgep, cidp); 4068087a28d1SDavid Gwynne { 4069087a28d1SDavid Gwynne int slot; 4070087a28d1SDavid Gwynne for (slot = 0; slot < MAC_ADDRESS_REGS_MAX; slot++) { 4071087a28d1SDavid Gwynne ethaddr_copy(cidp->vendor_addr.addr, 4072087a28d1SDavid Gwynne bgep->curr_addr[slot].addr); 4073087a28d1SDavid Gwynne bgep->curr_addr[slot].set = 1; 4074087a28d1SDavid Gwynne } 4075087a28d1SDavid Gwynne } 4076087a28d1SDavid Gwynne 4077087a28d1SDavid Gwynne bge_read_fw_ver(bgep); 4078ed8845d8Skrgopi 40798398201fSkrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX; 4080da14cebeSEric Cheng bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX; 408162387023Sdduvall 4082ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 4083ba2e4443Sseb goto attach_fail; 4084ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 4085ba2e4443Sseb macp->m_driver = bgep; 408662387023Sdduvall macp->m_dip = devinfo; 4087da14cebeSEric Cheng macp->m_src_addr = cidp->vendor_addr.addr; 4088ba2e4443Sseb macp->m_callbacks = &bge_m_callbacks; 4089ba2e4443Sseb macp->m_min_sdu = 0; 4090ba2e4443Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); 4091d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ; 40924045d941Ssowmini macp->m_priv_props = bge_priv_prop; 4093087a28d1SDavid Gwynne 4094087a28d1SDavid Gwynne #if defined(ILLUMOS) 4095087a28d1SDavid Gwynne bge_m_unicst(bgep, cidp->vendor_addr.addr); 4096087a28d1SDavid Gwynne #endif 40974045d941Ssowmini 409862387023Sdduvall /* 409962387023Sdduvall * Finally, we're ready to register ourselves with the MAC layer 410062387023Sdduvall * interface; if this succeeds, we're all ready to start() 410162387023Sdduvall */ 4102ba2e4443Sseb err = mac_register(macp, &bgep->mh); 4103ba2e4443Sseb mac_free(macp); 4104ba2e4443Sseb if (err != 0) 410562387023Sdduvall goto attach_fail; 410662387023Sdduvall 410746ffce64Syong tan - Sun Microsystems - Beijing China mac_link_update(bgep->mh, LINK_STATE_UNKNOWN); 410846ffce64Syong tan - Sun Microsystems - Beijing China 4109dd4eeefdSeota /* 4110dd4eeefdSeota * Register a periodical handler. 4111dd4eeefdSeota * bge_chip_cyclic() is invoked in kernel context. 4112dd4eeefdSeota */ 4113dd4eeefdSeota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep, 4114dd4eeefdSeota BGE_CYCLIC_PERIOD, DDI_IPL_0); 411562387023Sdduvall 411662387023Sdduvall bgep->progress |= PROGRESS_READY; 411762387023Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 4118a4de4ba2Sml149210 #ifdef BGE_IPMI_ASF 4119a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE 4120a4de4ba2Sml149210 if (bgep->asf_enabled) { 4121a4de4ba2Sml149210 mutex_enter(bgep->genlock); 4122a4de4ba2Sml149210 retval = bge_chip_start(bgep, B_TRUE); 4123a4de4ba2Sml149210 mutex_exit(bgep->genlock); 4124a4de4ba2Sml149210 if (retval != DDI_SUCCESS) 4125a4de4ba2Sml149210 goto attach_fail; 4126a4de4ba2Sml149210 } 4127a4de4ba2Sml149210 #endif 4128a4de4ba2Sml149210 #endif 412919397407SSherry Moore 413019397407SSherry Moore ddi_report_dev(devinfo); 413127c3238fSyong tan - Sun Microsystems - Beijing China 413262387023Sdduvall return (DDI_SUCCESS); 413362387023Sdduvall 413462387023Sdduvall attach_fail: 413567f02347Srandyf #ifdef BGE_IPMI_ASF 4136f724721bSzh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN); 413767f02347Srandyf #else 413862387023Sdduvall bge_unattach(bgep); 413967f02347Srandyf #endif 414062387023Sdduvall return (DDI_FAILURE); 414162387023Sdduvall } 414262387023Sdduvall 414362387023Sdduvall /* 414462387023Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 414562387023Sdduvall */ 414662387023Sdduvall static int 414762387023Sdduvall bge_suspend(bge_t *bgep) 414862387023Sdduvall { 414962387023Sdduvall /* 415062387023Sdduvall * Stop processing and idle (powerdown) the PHY ... 415162387023Sdduvall */ 415262387023Sdduvall mutex_enter(bgep->genlock); 415367f02347Srandyf #ifdef BGE_IPMI_ASF 415467f02347Srandyf /* 415567f02347Srandyf * Power management hasn't been supported in BGE now. If you 415667f02347Srandyf * want to implement it, please add the ASF/IPMI related 415767f02347Srandyf * code here. 415867f02347Srandyf */ 415967f02347Srandyf #endif 416062387023Sdduvall bge_stop(bgep); 416100d0963fSdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 416200d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 416300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 416400d0963fSdilpreet mutex_exit(bgep->genlock); 416500d0963fSdilpreet return (DDI_FAILURE); 416600d0963fSdilpreet } 416700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 416800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 416900d0963fSdilpreet mutex_exit(bgep->genlock); 417000d0963fSdilpreet return (DDI_FAILURE); 417100d0963fSdilpreet } 417262387023Sdduvall mutex_exit(bgep->genlock); 417362387023Sdduvall 417462387023Sdduvall return (DDI_SUCCESS); 417562387023Sdduvall } 417662387023Sdduvall 417762387023Sdduvall /* 417819397407SSherry Moore * quiesce(9E) entry point. 417919397407SSherry Moore * 418019397407SSherry Moore * This function is called when the system is single-threaded at high 418119397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 418219397407SSherry Moore * blocked. 418319397407SSherry Moore * 418419397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 418519397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 418619397407SSherry Moore */ 418719397407SSherry Moore #ifdef __sparc 418819397407SSherry Moore #define bge_quiesce ddi_quiesce_not_supported 418919397407SSherry Moore #else 419019397407SSherry Moore static int 419119397407SSherry Moore bge_quiesce(dev_info_t *devinfo) 419219397407SSherry Moore { 419319397407SSherry Moore bge_t *bgep = ddi_get_driver_private(devinfo); 419419397407SSherry Moore 419519397407SSherry Moore if (bgep == NULL) 419619397407SSherry Moore return (DDI_FAILURE); 419719397407SSherry Moore 419819397407SSherry Moore if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 419919397407SSherry Moore bge_reg_set32(bgep, PCI_CONF_BGE_MHCR, 420019397407SSherry Moore MHCR_MASK_PCI_INT_OUTPUT); 420119397407SSherry Moore } else { 420219397407SSherry Moore bge_reg_clr32(bgep, MSI_MODE_REG, MSI_MSI_ENABLE); 420319397407SSherry Moore } 420419397407SSherry Moore 420519397407SSherry Moore /* Stop the chip */ 420619397407SSherry Moore bge_chip_stop_nonblocking(bgep); 420719397407SSherry Moore 420819397407SSherry Moore return (DDI_SUCCESS); 420919397407SSherry Moore } 421019397407SSherry Moore #endif 421119397407SSherry Moore 421219397407SSherry Moore /* 421362387023Sdduvall * detach(9E) -- Detach a device from the system 421462387023Sdduvall */ 421562387023Sdduvall static int 421662387023Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 421762387023Sdduvall { 421862387023Sdduvall bge_t *bgep; 421967f02347Srandyf #ifdef BGE_IPMI_ASF 422067f02347Srandyf uint_t asf_mode; 422167f02347Srandyf asf_mode = ASF_MODE_NONE; 422267f02347Srandyf #endif 422362387023Sdduvall 422462387023Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 422562387023Sdduvall 422662387023Sdduvall bgep = ddi_get_driver_private(devinfo); 422762387023Sdduvall 422862387023Sdduvall switch (cmd) { 422962387023Sdduvall default: 423062387023Sdduvall return (DDI_FAILURE); 423162387023Sdduvall 423262387023Sdduvall case DDI_SUSPEND: 423362387023Sdduvall return (bge_suspend(bgep)); 423462387023Sdduvall 423562387023Sdduvall case DDI_DETACH: 423662387023Sdduvall break; 423762387023Sdduvall } 423862387023Sdduvall 423967f02347Srandyf #ifdef BGE_IPMI_ASF 424067f02347Srandyf mutex_enter(bgep->genlock); 4241f724721bSzh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) || 4242f724721bSzh199473 (bgep->asf_status == ASF_STAT_RUN_INIT))) { 424367f02347Srandyf 424467f02347Srandyf bge_asf_update_status(bgep); 4245f724721bSzh199473 if (bgep->asf_status == ASF_STAT_RUN) { 424667f02347Srandyf bge_asf_stop_timer(bgep); 4247f724721bSzh199473 } 424867f02347Srandyf bgep->asf_status = ASF_STAT_STOP; 424967f02347Srandyf 425067f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 425167f02347Srandyf 425267f02347Srandyf if (bgep->asf_pseudostop) { 425367f02347Srandyf bge_chip_stop(bgep, B_FALSE); 425467f02347Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 425567f02347Srandyf bgep->asf_pseudostop = B_FALSE; 425667f02347Srandyf } 425767f02347Srandyf 425867f02347Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 425900d0963fSdilpreet 426000d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 426100d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 426200d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 426300d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 426400d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, 426500d0963fSdilpreet DDI_SERVICE_UNAFFECTED); 426667f02347Srandyf } 426767f02347Srandyf mutex_exit(bgep->genlock); 426867f02347Srandyf #endif 426967f02347Srandyf 427062387023Sdduvall /* 427162387023Sdduvall * Unregister from the GLD subsystem. This can fail, in 427262387023Sdduvall * particular if there are DLPI style-2 streams still open - 427362387023Sdduvall * in which case we just return failure without shutting 427462387023Sdduvall * down chip operations. 427562387023Sdduvall */ 4276ba2e4443Sseb if (mac_unregister(bgep->mh) != 0) 427762387023Sdduvall return (DDI_FAILURE); 427862387023Sdduvall 427962387023Sdduvall /* 428062387023Sdduvall * All activity stopped, so we can clean up & exit 428162387023Sdduvall */ 428267f02347Srandyf #ifdef BGE_IPMI_ASF 428367f02347Srandyf bge_unattach(bgep, asf_mode); 428467f02347Srandyf #else 428562387023Sdduvall bge_unattach(bgep); 428667f02347Srandyf #endif 428762387023Sdduvall return (DDI_SUCCESS); 428862387023Sdduvall } 428962387023Sdduvall 429062387023Sdduvall 429162387023Sdduvall /* 429262387023Sdduvall * ========== Module Loading Data & Entry Points ========== 429362387023Sdduvall */ 429462387023Sdduvall 429562387023Sdduvall #undef BGE_DBG 429662387023Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 429762387023Sdduvall 429819397407SSherry Moore DDI_DEFINE_STREAM_OPS(bge_dev_ops, 429919397407SSherry Moore nulldev, /* identify */ 430019397407SSherry Moore nulldev, /* probe */ 430119397407SSherry Moore bge_attach, /* attach */ 430219397407SSherry Moore bge_detach, /* detach */ 430319397407SSherry Moore nodev, /* reset */ 430419397407SSherry Moore NULL, /* cb_ops */ 430519397407SSherry Moore D_MP, /* bus_ops */ 430619397407SSherry Moore NULL, /* power */ 430719397407SSherry Moore bge_quiesce /* quiesce */ 430819397407SSherry Moore ); 430962387023Sdduvall 431062387023Sdduvall static struct modldrv bge_modldrv = { 431162387023Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 431262387023Sdduvall bge_ident, /* short description */ 431362387023Sdduvall &bge_dev_ops /* driver specific ops */ 431462387023Sdduvall }; 431562387023Sdduvall 431662387023Sdduvall static struct modlinkage modlinkage = { 431762387023Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 431862387023Sdduvall }; 431962387023Sdduvall 432062387023Sdduvall 432162387023Sdduvall int 432262387023Sdduvall _info(struct modinfo *modinfop) 432362387023Sdduvall { 432462387023Sdduvall return (mod_info(&modlinkage, modinfop)); 432562387023Sdduvall } 432662387023Sdduvall 432762387023Sdduvall int 432862387023Sdduvall _init(void) 432962387023Sdduvall { 433062387023Sdduvall int status; 433162387023Sdduvall 433262387023Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 433362387023Sdduvall status = mod_install(&modlinkage); 433462387023Sdduvall if (status == DDI_SUCCESS) 433562387023Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 433662387023Sdduvall else 433762387023Sdduvall mac_fini_ops(&bge_dev_ops); 433862387023Sdduvall return (status); 433962387023Sdduvall } 434062387023Sdduvall 434162387023Sdduvall int 434262387023Sdduvall _fini(void) 434362387023Sdduvall { 434462387023Sdduvall int status; 434562387023Sdduvall 434662387023Sdduvall status = mod_remove(&modlinkage); 434762387023Sdduvall if (status == DDI_SUCCESS) { 434862387023Sdduvall mac_fini_ops(&bge_dev_ops); 434962387023Sdduvall mutex_destroy(bge_log_mutex); 435062387023Sdduvall } 435162387023Sdduvall return (status); 435262387023Sdduvall } 435362387023Sdduvall 435462387023Sdduvall 435562387023Sdduvall /* 435662387023Sdduvall * bge_add_intrs: 435762387023Sdduvall * 435862387023Sdduvall * Register FIXED or MSI interrupts. 435962387023Sdduvall */ 436062387023Sdduvall static int 436162387023Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 436262387023Sdduvall { 436362387023Sdduvall dev_info_t *dip = bgep->devinfo; 436462387023Sdduvall int avail, actual, intr_size, count = 0; 436562387023Sdduvall int i, flag, ret; 436662387023Sdduvall 4367f724721bSzh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type)); 436862387023Sdduvall 436962387023Sdduvall /* Get number of interrupts */ 437062387023Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 437162387023Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 437262387023Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 437362387023Sdduvall "count: %d", ret, count); 437462387023Sdduvall 437562387023Sdduvall return (DDI_FAILURE); 437662387023Sdduvall } 437762387023Sdduvall 437862387023Sdduvall /* Get number of available interrupts */ 437962387023Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 438062387023Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 438162387023Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 438262387023Sdduvall "ret: %d, avail: %d\n", ret, avail); 438362387023Sdduvall 438462387023Sdduvall return (DDI_FAILURE); 438562387023Sdduvall } 438662387023Sdduvall 438762387023Sdduvall if (avail < count) { 4388f724721bSzh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d", 4389f724721bSzh199473 bgep->ifname, count, avail)); 439062387023Sdduvall } 439162387023Sdduvall 439262387023Sdduvall /* 439362387023Sdduvall * BGE hardware generates only single MSI even though it claims 439462387023Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 439562387023Sdduvall */ 439662387023Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 439762387023Sdduvall count = 1; 439862387023Sdduvall flag = DDI_INTR_ALLOC_STRICT; 439962387023Sdduvall } else { 440062387023Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 440162387023Sdduvall } 440262387023Sdduvall 440362387023Sdduvall /* Allocate an array of interrupt handles */ 440462387023Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 440562387023Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 440662387023Sdduvall 440762387023Sdduvall /* Call ddi_intr_alloc() */ 440862387023Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 440962387023Sdduvall count, &actual, flag); 441062387023Sdduvall 441162387023Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 441262387023Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 441362387023Sdduvall 441462387023Sdduvall kmem_free(bgep->htable, intr_size); 441562387023Sdduvall return (DDI_FAILURE); 441662387023Sdduvall } 441762387023Sdduvall 441862387023Sdduvall if (actual < count) { 4419f724721bSzh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d", 4420f724721bSzh199473 bgep->ifname, count, actual)); 442162387023Sdduvall } 442262387023Sdduvall 442362387023Sdduvall bgep->intr_cnt = actual; 442462387023Sdduvall 442562387023Sdduvall /* 442662387023Sdduvall * Get priority for first msi, assume remaining are all the same 442762387023Sdduvall */ 442862387023Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 442962387023Sdduvall DDI_SUCCESS) { 443062387023Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 443162387023Sdduvall 443262387023Sdduvall /* Free already allocated intr */ 443362387023Sdduvall for (i = 0; i < actual; i++) { 443462387023Sdduvall (void) ddi_intr_free(bgep->htable[i]); 443562387023Sdduvall } 443662387023Sdduvall 443762387023Sdduvall kmem_free(bgep->htable, intr_size); 443862387023Sdduvall return (DDI_FAILURE); 443962387023Sdduvall } 444062387023Sdduvall 444162387023Sdduvall /* Call ddi_intr_add_handler() */ 444262387023Sdduvall for (i = 0; i < actual; i++) { 444362387023Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 444462387023Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 444562387023Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 444662387023Sdduvall "failed %d\n", ret); 444762387023Sdduvall 444862387023Sdduvall /* Free already allocated intr */ 444962387023Sdduvall for (i = 0; i < actual; i++) { 445062387023Sdduvall (void) ddi_intr_free(bgep->htable[i]); 445162387023Sdduvall } 445262387023Sdduvall 445362387023Sdduvall kmem_free(bgep->htable, intr_size); 445462387023Sdduvall return (DDI_FAILURE); 445562387023Sdduvall } 445662387023Sdduvall } 445762387023Sdduvall 445862387023Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 445962387023Sdduvall != DDI_SUCCESS) { 446062387023Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 446162387023Sdduvall 446262387023Sdduvall for (i = 0; i < actual; i++) { 446362387023Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 446462387023Sdduvall (void) ddi_intr_free(bgep->htable[i]); 446562387023Sdduvall } 446662387023Sdduvall 446762387023Sdduvall kmem_free(bgep->htable, intr_size); 446862387023Sdduvall return (DDI_FAILURE); 446962387023Sdduvall } 447062387023Sdduvall 447162387023Sdduvall return (DDI_SUCCESS); 447262387023Sdduvall } 447362387023Sdduvall 447462387023Sdduvall /* 447562387023Sdduvall * bge_rem_intrs: 447662387023Sdduvall * 447762387023Sdduvall * Unregister FIXED or MSI interrupts 447862387023Sdduvall */ 447962387023Sdduvall static void 448062387023Sdduvall bge_rem_intrs(bge_t *bgep) 448162387023Sdduvall { 448262387023Sdduvall int i; 448362387023Sdduvall 4484f724721bSzh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep)); 448562387023Sdduvall 448600d0963fSdilpreet /* Call ddi_intr_remove_handler() */ 448700d0963fSdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 448800d0963fSdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 448900d0963fSdilpreet (void) ddi_intr_free(bgep->htable[i]); 449000d0963fSdilpreet } 449100d0963fSdilpreet 449200d0963fSdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 449300d0963fSdilpreet } 449400d0963fSdilpreet 449500d0963fSdilpreet 449600d0963fSdilpreet void 449700d0963fSdilpreet bge_intr_enable(bge_t *bgep) 449800d0963fSdilpreet { 449900d0963fSdilpreet int i; 450000d0963fSdilpreet 450100d0963fSdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 450200d0963fSdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 450300d0963fSdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 450400d0963fSdilpreet } else { 450500d0963fSdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 450600d0963fSdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 450700d0963fSdilpreet (void) ddi_intr_enable(bgep->htable[i]); 450800d0963fSdilpreet } 450900d0963fSdilpreet } 451000d0963fSdilpreet } 451100d0963fSdilpreet 451200d0963fSdilpreet 451300d0963fSdilpreet void 451400d0963fSdilpreet bge_intr_disable(bge_t *bgep) 451500d0963fSdilpreet { 451600d0963fSdilpreet int i; 451700d0963fSdilpreet 451862387023Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 451962387023Sdduvall /* Call ddi_intr_block_disable() */ 452062387023Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 452162387023Sdduvall } else { 452262387023Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 452362387023Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 452462387023Sdduvall } 452562387023Sdduvall } 452662387023Sdduvall } 4527e7801d59Ssowmini 4528e7801d59Ssowmini int 4529e7801d59Ssowmini bge_reprogram(bge_t *bgep) 4530e7801d59Ssowmini { 4531e7801d59Ssowmini int status = 0; 4532e7801d59Ssowmini 4533e7801d59Ssowmini ASSERT(mutex_owned(bgep->genlock)); 4534e7801d59Ssowmini 4535e7801d59Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) { 4536e7801d59Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 4537e7801d59Ssowmini status = IOC_INVAL; 4538e7801d59Ssowmini } 4539e7801d59Ssowmini #ifdef BGE_IPMI_ASF 4540e7801d59Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 4541e7801d59Ssowmini #else 4542e7801d59Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) { 4543e7801d59Ssowmini #endif 4544e7801d59Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 4545e7801d59Ssowmini status = IOC_INVAL; 4546e7801d59Ssowmini } 4547e7801d59Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI) 4548e7801d59Ssowmini bge_chip_msi_trig(bgep); 4549e7801d59Ssowmini return (status); 4550e7801d59Ssowmini } 4551