11369Sdduvall /* 21369Sdduvall * CDDL HEADER START 31369Sdduvall * 41369Sdduvall * The contents of this file are subject to the terms of the 51369Sdduvall * Common Development and Distribution License (the "License"). 61369Sdduvall * You may not use this file except in compliance with the License. 71369Sdduvall * 81369Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91369Sdduvall * or http://www.opensolaris.org/os/licensing. 101369Sdduvall * See the License for the specific language governing permissions 111369Sdduvall * and limitations under the License. 121369Sdduvall * 131369Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 141369Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151369Sdduvall * If applicable, add the following below this CDDL HEADER, with the 161369Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 171369Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 181369Sdduvall * 191369Sdduvall * CDDL HEADER END 201369Sdduvall */ 211369Sdduvall 221369Sdduvall /* 235895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 271369Sdduvall #pragma ident "%Z%%M% %I% %E% SMI" 281369Sdduvall 292675Szh199473 #include "bge_impl.h" 301369Sdduvall #include <sys/sdt.h> 316789Sam223141 #include <sys/mac.h> 321369Sdduvall 331369Sdduvall /* 341369Sdduvall * This is the string displayed by modinfo, etc. 351369Sdduvall * Make sure you keep the version ID up to date! 361369Sdduvall */ 37*7099Syt223700 static char bge_ident[] = "Broadcom Gb Ethernet v0.64"; 381369Sdduvall 391369Sdduvall /* 401369Sdduvall * Property names 411369Sdduvall */ 421369Sdduvall static char debug_propname[] = "bge-debug-flags"; 431369Sdduvall static char clsize_propname[] = "cache-line-size"; 441369Sdduvall static char latency_propname[] = "latency-timer"; 451369Sdduvall static char localmac_boolname[] = "local-mac-address?"; 461369Sdduvall static char localmac_propname[] = "local-mac-address"; 471369Sdduvall static char macaddr_propname[] = "mac-address"; 481369Sdduvall static char subdev_propname[] = "subsystem-id"; 491369Sdduvall static char subven_propname[] = "subsystem-vendor-id"; 501369Sdduvall static char rxrings_propname[] = "bge-rx-rings"; 511369Sdduvall static char txrings_propname[] = "bge-tx-rings"; 521865Sdilpreet static char fm_cap[] = "fm-capable"; 531908Sly149593 static char default_mtu[] = "default_mtu"; 541369Sdduvall 551369Sdduvall static int bge_add_intrs(bge_t *, int); 561369Sdduvall static void bge_rem_intrs(bge_t *); 571369Sdduvall 581369Sdduvall /* 591369Sdduvall * Describes the chip's DMA engine 601369Sdduvall */ 611369Sdduvall static ddi_dma_attr_t dma_attr = { 621369Sdduvall DMA_ATTR_V0, /* dma_attr version */ 631369Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */ 641369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 651369Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 661369Sdduvall 0x0000000000000001ull, /* dma_attr_align */ 671369Sdduvall 0x00000FFF, /* dma_attr_burstsizes */ 681369Sdduvall 0x00000001, /* dma_attr_minxfer */ 691369Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */ 701369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 711369Sdduvall 1, /* dma_attr_sgllen */ 721369Sdduvall 0x00000001, /* dma_attr_granular */ 731865Sdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */ 741369Sdduvall }; 751369Sdduvall 761369Sdduvall /* 771369Sdduvall * PIO access attributes for registers 781369Sdduvall */ 791369Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = { 801369Sdduvall DDI_DEVICE_ATTR_V0, 811369Sdduvall DDI_NEVERSWAP_ACC, 821865Sdilpreet DDI_STRICTORDER_ACC, 831865Sdilpreet DDI_FLAGERR_ACC 841369Sdduvall }; 851369Sdduvall 861369Sdduvall /* 871369Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped. 881369Sdduvall */ 891369Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = { 901369Sdduvall DDI_DEVICE_ATTR_V0, 911369Sdduvall DDI_NEVERSWAP_ACC, 921865Sdilpreet DDI_STRICTORDER_ACC, 931865Sdilpreet DDI_FLAGERR_ACC 941369Sdduvall }; 951369Sdduvall 961369Sdduvall /* 971369Sdduvall * DMA access attributes for data: NOT to be byte swapped. 981369Sdduvall */ 991369Sdduvall static ddi_device_acc_attr_t bge_data_accattr = { 1001369Sdduvall DDI_DEVICE_ATTR_V0, 1011369Sdduvall DDI_NEVERSWAP_ACC, 1021369Sdduvall DDI_STRICTORDER_ACC 1031369Sdduvall }; 1041369Sdduvall 1052311Sseb static int bge_m_start(void *); 1062311Sseb static void bge_m_stop(void *); 1072311Sseb static int bge_m_promisc(void *, boolean_t); 1082311Sseb static int bge_m_multicst(void *, boolean_t, const uint8_t *); 1092311Sseb static int bge_m_unicst(void *, const uint8_t *); 1102311Sseb static void bge_m_resources(void *); 1112311Sseb static void bge_m_ioctl(void *, queue_t *, mblk_t *); 1122311Sseb static boolean_t bge_m_getcapab(void *, mac_capab_t, void *); 1132331Skrgopi static int bge_unicst_set(void *, const uint8_t *, 1142331Skrgopi mac_addr_slot_t); 1152331Skrgopi static int bge_m_unicst_add(void *, mac_multi_addr_t *); 1162331Skrgopi static int bge_m_unicst_remove(void *, mac_addr_slot_t); 1172331Skrgopi static int bge_m_unicst_modify(void *, mac_multi_addr_t *); 1182331Skrgopi static int bge_m_unicst_get(void *, mac_multi_addr_t *); 1195903Ssowmini static int bge_m_setprop(void *, const char *, mac_prop_id_t, 1205903Ssowmini uint_t, const void *); 1215903Ssowmini static int bge_m_getprop(void *, const char *, mac_prop_id_t, 1226512Ssowmini uint_t, uint_t, void *); 1235903Ssowmini static int bge_set_priv_prop(bge_t *, const char *, uint_t, 1245903Ssowmini const void *); 1255903Ssowmini static int bge_get_priv_prop(bge_t *, const char *, uint_t, 1266512Ssowmini uint_t, void *); 1275903Ssowmini 1285903Ssowmini #define BGE_M_CALLBACK_FLAGS\ 1295903Ssowmini (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1302311Sseb 1312311Sseb static mac_callbacks_t bge_m_callbacks = { 1322311Sseb BGE_M_CALLBACK_FLAGS, 1332311Sseb bge_m_stat, 1342311Sseb bge_m_start, 1352311Sseb bge_m_stop, 1362311Sseb bge_m_promisc, 1372311Sseb bge_m_multicst, 1382311Sseb bge_m_unicst, 1392311Sseb bge_m_tx, 1402311Sseb bge_m_resources, 1412311Sseb bge_m_ioctl, 1425903Ssowmini bge_m_getcapab, 1435903Ssowmini NULL, 1445903Ssowmini NULL, 1455903Ssowmini bge_m_setprop, 1465903Ssowmini bge_m_getprop 1472311Sseb }; 1482311Sseb 1496512Ssowmini mac_priv_prop_t bge_priv_prop[] = { 1506512Ssowmini {"_adv_asym_pause_cap", MAC_PROP_PERM_RW}, 1516512Ssowmini {"_adv_pause_cap", MAC_PROP_PERM_RW} 1526512Ssowmini }; 1536512Ssowmini 1546512Ssowmini #define BGE_MAX_PRIV_PROPS \ 1556512Ssowmini (sizeof (bge_priv_prop) / sizeof (mac_priv_prop_t)) 1566512Ssowmini 1571369Sdduvall /* 1581369Sdduvall * ========== Transmit and receive ring reinitialisation ========== 1591369Sdduvall */ 1601369Sdduvall 1611369Sdduvall /* 1621369Sdduvall * These <reinit> routines each reset the specified ring to an initial 1631369Sdduvall * state, assuming that the corresponding <init> routine has already 1641369Sdduvall * been called exactly once. 1651369Sdduvall */ 1661369Sdduvall 1671369Sdduvall static void 1681369Sdduvall bge_reinit_send_ring(send_ring_t *srp) 1691369Sdduvall { 1703334Sgs150176 bge_queue_t *txbuf_queue; 1713334Sgs150176 bge_queue_item_t *txbuf_head; 1723334Sgs150176 sw_txbuf_t *txbuf; 1733334Sgs150176 sw_sbd_t *ssbdp; 1743334Sgs150176 uint32_t slot; 1753334Sgs150176 1761369Sdduvall /* 1771369Sdduvall * Reinitialise control variables ... 1781369Sdduvall */ 1793334Sgs150176 srp->tx_flow = 0; 1801369Sdduvall srp->tx_next = 0; 1813334Sgs150176 srp->txfill_next = 0; 1821369Sdduvall srp->tx_free = srp->desc.nslots; 1831369Sdduvall ASSERT(mutex_owned(srp->tc_lock)); 1841369Sdduvall srp->tc_next = 0; 1853334Sgs150176 srp->txpkt_next = 0; 1863334Sgs150176 srp->tx_block = 0; 1873334Sgs150176 srp->tx_nobd = 0; 1883334Sgs150176 srp->tx_nobuf = 0; 1893334Sgs150176 1903334Sgs150176 /* 1913334Sgs150176 * Initialize the tx buffer push queue 1923334Sgs150176 */ 1933334Sgs150176 mutex_enter(srp->freetxbuf_lock); 1943334Sgs150176 mutex_enter(srp->txbuf_lock); 1953334Sgs150176 txbuf_queue = &srp->freetxbuf_queue; 1963334Sgs150176 txbuf_queue->head = NULL; 1973334Sgs150176 txbuf_queue->count = 0; 1983334Sgs150176 txbuf_queue->lock = srp->freetxbuf_lock; 1993334Sgs150176 srp->txbuf_push_queue = txbuf_queue; 2003334Sgs150176 2013334Sgs150176 /* 2023334Sgs150176 * Initialize the tx buffer pop queue 2033334Sgs150176 */ 2043334Sgs150176 txbuf_queue = &srp->txbuf_queue; 2053334Sgs150176 txbuf_queue->head = NULL; 2063334Sgs150176 txbuf_queue->count = 0; 2073334Sgs150176 txbuf_queue->lock = srp->txbuf_lock; 2083334Sgs150176 srp->txbuf_pop_queue = txbuf_queue; 2093334Sgs150176 txbuf_head = srp->txbuf_head; 2103334Sgs150176 txbuf = srp->txbuf; 2113334Sgs150176 for (slot = 0; slot < srp->tx_buffers; ++slot) { 2123334Sgs150176 txbuf_head->item = txbuf; 2133334Sgs150176 txbuf_head->next = txbuf_queue->head; 2143334Sgs150176 txbuf_queue->head = txbuf_head; 2153334Sgs150176 txbuf_queue->count++; 2163334Sgs150176 txbuf++; 2173334Sgs150176 txbuf_head++; 2183334Sgs150176 } 2193334Sgs150176 mutex_exit(srp->txbuf_lock); 2203334Sgs150176 mutex_exit(srp->freetxbuf_lock); 2211369Sdduvall 2221369Sdduvall /* 2231369Sdduvall * Zero and sync all the h/w Send Buffer Descriptors 2241369Sdduvall */ 2251369Sdduvall DMA_ZERO(srp->desc); 2261369Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 2273334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 2283334Sgs150176 ssbdp = srp->sw_sbds; 2293334Sgs150176 for (slot = 0; slot < srp->desc.nslots; ++ssbdp, ++slot) 2303334Sgs150176 ssbdp->pbuf = NULL; 2311369Sdduvall } 2321369Sdduvall 2331369Sdduvall static void 2341369Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp) 2351369Sdduvall { 2361369Sdduvall /* 2371369Sdduvall * Reinitialise control variables ... 2381369Sdduvall */ 2391369Sdduvall rrp->rx_next = 0; 2401369Sdduvall } 2411369Sdduvall 2421369Sdduvall static void 2433334Sgs150176 bge_reinit_buff_ring(buff_ring_t *brp, uint32_t ring) 2441369Sdduvall { 2451369Sdduvall bge_rbd_t *hw_rbd_p; 2461369Sdduvall sw_rbd_t *srbdp; 2471369Sdduvall uint32_t bufsize; 2481369Sdduvall uint32_t nslots; 2491369Sdduvall uint32_t slot; 2501369Sdduvall 2511369Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = { 2521369Sdduvall RBD_FLAG_STD_RING, 2531369Sdduvall RBD_FLAG_JUMBO_RING, 2541369Sdduvall RBD_FLAG_MINI_RING 2551369Sdduvall }; 2561369Sdduvall 2571369Sdduvall /* 2581369Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors 2591369Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>, 2601369Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>) 2611369Sdduvall * should be zeroed, and so don't need to be set up specifically 2621369Sdduvall * once the whole area has been cleared. 2631369Sdduvall */ 2641369Sdduvall DMA_ZERO(brp->desc); 2651369Sdduvall 2661369Sdduvall hw_rbd_p = DMA_VPTR(brp->desc); 2671369Sdduvall nslots = brp->desc.nslots; 2681369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 2691369Sdduvall bufsize = brp->buf[0].size; 2701369Sdduvall srbdp = brp->sw_rbds; 2711369Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) { 2721369Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress; 273*7099Syt223700 hw_rbd_p->index = (uint16_t)slot; 274*7099Syt223700 hw_rbd_p->len = (uint16_t)bufsize; 2751369Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token; 2761369Sdduvall hw_rbd_p->flags |= ring_type_flag[ring]; 2771369Sdduvall } 2781369Sdduvall 2791369Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV); 2801369Sdduvall 2811369Sdduvall /* 2821369Sdduvall * Finally, reinitialise the ring control variables ... 2831369Sdduvall */ 2841369Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0; 2851369Sdduvall } 2861369Sdduvall 2871369Sdduvall /* 2881369Sdduvall * Reinitialize all rings 2891369Sdduvall */ 2901369Sdduvall static void 2911369Sdduvall bge_reinit_rings(bge_t *bgep) 2921369Sdduvall { 2933334Sgs150176 uint32_t ring; 2941369Sdduvall 2951369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 2961369Sdduvall 2971369Sdduvall /* 2981369Sdduvall * Send Rings ... 2991369Sdduvall */ 3001369Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) 3011369Sdduvall bge_reinit_send_ring(&bgep->send[ring]); 3021369Sdduvall 3031369Sdduvall /* 3041369Sdduvall * Receive Return Rings ... 3051369Sdduvall */ 3061369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring) 3071369Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]); 3081369Sdduvall 3091369Sdduvall /* 3101369Sdduvall * Receive Producer Rings ... 3111369Sdduvall */ 3121369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 3131369Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring); 3141369Sdduvall } 3151369Sdduvall 3161369Sdduvall /* 3171369Sdduvall * ========== Internal state management entry points ========== 3181369Sdduvall */ 3191369Sdduvall 3201369Sdduvall #undef BGE_DBG 3211369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 3221369Sdduvall 3231369Sdduvall /* 3241369Sdduvall * These routines provide all the functionality required by the 3251369Sdduvall * corresponding GLD entry points, but don't update the GLD state 3261369Sdduvall * so they can be called internally without disturbing our record 3271369Sdduvall * of what GLD thinks we should be doing ... 3281369Sdduvall */ 3291369Sdduvall 3301369Sdduvall /* 3311369Sdduvall * bge_reset() -- reset h/w & rings to initial state 3321369Sdduvall */ 3331865Sdilpreet static int 3341408Srandyf #ifdef BGE_IPMI_ASF 3351408Srandyf bge_reset(bge_t *bgep, uint_t asf_mode) 3361408Srandyf #else 3371369Sdduvall bge_reset(bge_t *bgep) 3381408Srandyf #endif 3391369Sdduvall { 3403334Sgs150176 uint32_t ring; 3411865Sdilpreet int retval; 3421369Sdduvall 3431369Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep)); 3441369Sdduvall 3451369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3461369Sdduvall 3471369Sdduvall /* 3481369Sdduvall * Grab all the other mutexes in the world (this should 3491369Sdduvall * ensure no other threads are manipulating driver state) 3501369Sdduvall */ 3511369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 3521369Sdduvall mutex_enter(bgep->recv[ring].rx_lock); 3531369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 3541369Sdduvall mutex_enter(bgep->buff[ring].rf_lock); 3551369Sdduvall rw_enter(bgep->errlock, RW_WRITER); 3561369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3573334Sgs150176 mutex_enter(bgep->send[ring].tx_lock); 3583334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3591369Sdduvall mutex_enter(bgep->send[ring].tc_lock); 3601369Sdduvall 3611408Srandyf #ifdef BGE_IPMI_ASF 3621865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode); 3631408Srandyf #else 3641865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE); 3651408Srandyf #endif 3661369Sdduvall bge_reinit_rings(bgep); 3671369Sdduvall 3681369Sdduvall /* 3691369Sdduvall * Free the world ... 3701369Sdduvall */ 3711369Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; ) 3721369Sdduvall mutex_exit(bgep->send[ring].tc_lock); 3733334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3743334Sgs150176 mutex_exit(bgep->send[ring].tx_lock); 3751369Sdduvall rw_exit(bgep->errlock); 3761369Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; ) 3771369Sdduvall mutex_exit(bgep->buff[ring].rf_lock); 3781369Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; ) 3791369Sdduvall mutex_exit(bgep->recv[ring].rx_lock); 3801369Sdduvall 3811369Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep)); 3821865Sdilpreet return (retval); 3831369Sdduvall } 3841369Sdduvall 3851369Sdduvall /* 3861369Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings 3871369Sdduvall */ 3881369Sdduvall static void 3891369Sdduvall bge_stop(bge_t *bgep) 3901369Sdduvall { 3911369Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep)); 3921369Sdduvall 3931369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3941369Sdduvall 3951408Srandyf #ifdef BGE_IPMI_ASF 3961408Srandyf if (bgep->asf_enabled) { 3971408Srandyf bgep->asf_pseudostop = B_TRUE; 3981408Srandyf } else { 3991408Srandyf #endif 4001408Srandyf bge_chip_stop(bgep, B_FALSE); 4011408Srandyf #ifdef BGE_IPMI_ASF 4021408Srandyf } 4031408Srandyf #endif 4041369Sdduvall 4051369Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep)); 4061369Sdduvall } 4071369Sdduvall 4081369Sdduvall /* 4091369Sdduvall * bge_start() -- start transmitting/receiving 4101369Sdduvall */ 4111865Sdilpreet static int 4121369Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys) 4131369Sdduvall { 4141865Sdilpreet int retval; 4151865Sdilpreet 4161369Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys)); 4171369Sdduvall 4181369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4191369Sdduvall 4201369Sdduvall /* 4211369Sdduvall * Start chip processing, including enabling interrupts 4221369Sdduvall */ 4231865Sdilpreet retval = bge_chip_start(bgep, reset_phys); 4241369Sdduvall 4251369Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys)); 4261865Sdilpreet return (retval); 4271369Sdduvall } 4281369Sdduvall 4291369Sdduvall /* 4301369Sdduvall * bge_restart - restart transmitting/receiving after error or suspend 4311369Sdduvall */ 4321865Sdilpreet int 4331369Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys) 4341369Sdduvall { 4351865Sdilpreet int retval = DDI_SUCCESS; 4361369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4371369Sdduvall 4381408Srandyf #ifdef BGE_IPMI_ASF 4391408Srandyf if (bgep->asf_enabled) { 4401865Sdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS) 4411865Sdilpreet retval = DDI_FAILURE; 4421408Srandyf } else 4431865Sdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS) 4441865Sdilpreet retval = DDI_FAILURE; 4451408Srandyf #else 4461865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) 4471865Sdilpreet retval = DDI_FAILURE; 4481408Srandyf #endif 4493440Szh199473 if (bgep->bge_mac_state == BGE_MAC_STARTED) { 4501865Sdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS) 4511865Sdilpreet retval = DDI_FAILURE; 4521369Sdduvall bgep->watchdog = 0; 4533334Sgs150176 ddi_trigger_softintr(bgep->drain_id); 4541369Sdduvall } 4551369Sdduvall 4561369Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys)); 4571865Sdilpreet return (retval); 4581369Sdduvall } 4591369Sdduvall 4601369Sdduvall 4611369Sdduvall /* 4621369Sdduvall * ========== Nemo-required management entry points ========== 4631369Sdduvall */ 4641369Sdduvall 4651369Sdduvall #undef BGE_DBG 4661369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 4671369Sdduvall 4681369Sdduvall /* 4691369Sdduvall * bge_m_stop() -- stop transmitting/receiving 4701369Sdduvall */ 4711369Sdduvall static void 4721369Sdduvall bge_m_stop(void *arg) 4731369Sdduvall { 4741369Sdduvall bge_t *bgep = arg; /* private device info */ 4753334Sgs150176 send_ring_t *srp; 4763334Sgs150176 uint32_t ring; 4771369Sdduvall 4781369Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg)); 4791369Sdduvall 4801369Sdduvall /* 4811369Sdduvall * Just stop processing, then record new GLD state 4821369Sdduvall */ 4831369Sdduvall mutex_enter(bgep->genlock); 4841865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 4851865Sdilpreet /* can happen during autorecovery */ 4861865Sdilpreet mutex_exit(bgep->genlock); 4871865Sdilpreet return; 4881865Sdilpreet } 4891369Sdduvall bge_stop(bgep); 4906546Sgh162552 4916546Sgh162552 bgep->link_update_timer = 0; 4926546Sgh162552 bgep->link_state = LINK_STATE_UNKNOWN; 4936546Sgh162552 mac_link_update(bgep->mh, bgep->link_state); 4946546Sgh162552 4953334Sgs150176 /* 4963334Sgs150176 * Free the possible tx buffers allocated in tx process. 4973334Sgs150176 */ 4983334Sgs150176 #ifdef BGE_IPMI_ASF 4993334Sgs150176 if (!bgep->asf_pseudostop) 5003334Sgs150176 #endif 5013334Sgs150176 { 5023334Sgs150176 rw_enter(bgep->errlock, RW_WRITER); 5033334Sgs150176 for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) { 5043334Sgs150176 srp = &bgep->send[ring]; 5053334Sgs150176 mutex_enter(srp->tx_lock); 5063334Sgs150176 if (srp->tx_array > 1) 5073334Sgs150176 bge_free_txbuf_arrays(srp); 5083334Sgs150176 mutex_exit(srp->tx_lock); 5093334Sgs150176 } 5103334Sgs150176 rw_exit(bgep->errlock); 5113334Sgs150176 } 5121369Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED; 5131369Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg)); 5141865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 5151865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 5161369Sdduvall mutex_exit(bgep->genlock); 5171369Sdduvall } 5181369Sdduvall 5191369Sdduvall /* 5201369Sdduvall * bge_m_start() -- start transmitting/receiving 5211369Sdduvall */ 5221369Sdduvall static int 5231369Sdduvall bge_m_start(void *arg) 5241369Sdduvall { 5251369Sdduvall bge_t *bgep = arg; /* private device info */ 5261369Sdduvall 5271369Sdduvall BGE_TRACE(("bge_m_start($%p)", arg)); 5281369Sdduvall 5291369Sdduvall /* 5301369Sdduvall * Start processing and record new GLD state 5311369Sdduvall */ 5321369Sdduvall mutex_enter(bgep->genlock); 5331865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 5341865Sdilpreet /* can happen during autorecovery */ 5351865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5361865Sdilpreet mutex_exit(bgep->genlock); 5371865Sdilpreet return (EIO); 5381865Sdilpreet } 5391408Srandyf #ifdef BGE_IPMI_ASF 5401408Srandyf if (bgep->asf_enabled) { 5411408Srandyf if ((bgep->asf_status == ASF_STAT_RUN) && 5424588Sml149210 (bgep->asf_pseudostop)) { 5431408Srandyf bgep->bge_mac_state = BGE_MAC_STARTED; 5441408Srandyf mutex_exit(bgep->genlock); 5451408Srandyf return (0); 5461408Srandyf } 5471408Srandyf } 5481865Sdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 5491408Srandyf #else 5501865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 5511408Srandyf #endif 5521865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5531865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5541865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5551865Sdilpreet mutex_exit(bgep->genlock); 5561865Sdilpreet return (EIO); 5571865Sdilpreet } 5581865Sdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) { 5591865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5601865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5611865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5621865Sdilpreet mutex_exit(bgep->genlock); 5631865Sdilpreet return (EIO); 5641865Sdilpreet } 5651369Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 5661369Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 5671408Srandyf 5681865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 5691865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5701865Sdilpreet mutex_exit(bgep->genlock); 5711865Sdilpreet return (EIO); 5721865Sdilpreet } 5731865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 5741865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5751865Sdilpreet mutex_exit(bgep->genlock); 5761865Sdilpreet return (EIO); 5771865Sdilpreet } 5781408Srandyf #ifdef BGE_IPMI_ASF 5791408Srandyf if (bgep->asf_enabled) { 5801408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 5811408Srandyf /* start ASF heart beat */ 5821408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 5834588Sml149210 (void *)bgep, 5844588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 5851408Srandyf bgep->asf_status = ASF_STAT_RUN; 5861408Srandyf } 5871408Srandyf } 5881408Srandyf #endif 5891369Sdduvall mutex_exit(bgep->genlock); 5901369Sdduvall 5911369Sdduvall return (0); 5921369Sdduvall } 5931369Sdduvall 5941369Sdduvall /* 5952331Skrgopi * bge_m_unicst() -- set the physical network address 5961369Sdduvall */ 5971369Sdduvall static int 5981369Sdduvall bge_m_unicst(void *arg, const uint8_t *macaddr) 5991369Sdduvall { 6002331Skrgopi /* 6012331Skrgopi * Request to set address in 6022331Skrgopi * address slot 0, i.e., default address 6032331Skrgopi */ 6042331Skrgopi return (bge_unicst_set(arg, macaddr, 0)); 6052331Skrgopi } 6062331Skrgopi 6072331Skrgopi /* 6082331Skrgopi * bge_unicst_set() -- set the physical network address 6092331Skrgopi */ 6102331Skrgopi static int 6112331Skrgopi bge_unicst_set(void *arg, const uint8_t *macaddr, mac_addr_slot_t slot) 6122331Skrgopi { 6131369Sdduvall bge_t *bgep = arg; /* private device info */ 6141369Sdduvall 6151369Sdduvall BGE_TRACE(("bge_m_unicst_set($%p, %s)", arg, 6164588Sml149210 ether_sprintf((void *)macaddr))); 6171369Sdduvall /* 6181369Sdduvall * Remember the new current address in the driver state 6191369Sdduvall * Sync the chip's idea of the address too ... 6201369Sdduvall */ 6211369Sdduvall mutex_enter(bgep->genlock); 6221865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 6231865Sdilpreet /* can happen during autorecovery */ 6241865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6251865Sdilpreet mutex_exit(bgep->genlock); 6261865Sdilpreet return (EIO); 6271865Sdilpreet } 6282331Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr); 6291408Srandyf #ifdef BGE_IPMI_ASF 6301865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 6311865Sdilpreet #else 6321865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6331865Sdilpreet #endif 6341865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6351865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6361865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6371865Sdilpreet mutex_exit(bgep->genlock); 6381865Sdilpreet return (EIO); 6391865Sdilpreet } 6401865Sdilpreet #ifdef BGE_IPMI_ASF 6411408Srandyf if (bgep->asf_enabled) { 6421408Srandyf /* 6431408Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 6441408Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 6451408Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 6461408Srandyf */ 6471408Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 6481408Srandyf /* 6491408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 6501408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 6511408Srandyf * may crash. 6521408Srandyf */ 6531408Srandyf bge_asf_update_status(bgep); 6541408Srandyf bge_asf_stop_timer(bgep); 6551408Srandyf bgep->asf_status = ASF_STAT_STOP; 6561408Srandyf 6571408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 6581408Srandyf } 6591865Sdilpreet bge_chip_stop(bgep, B_FALSE); 6601408Srandyf 6611865Sdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 6621865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6631865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6641865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 6651865Sdilpreet DDI_SERVICE_DEGRADED); 6661865Sdilpreet mutex_exit(bgep->genlock); 6671865Sdilpreet return (EIO); 6681865Sdilpreet } 6691865Sdilpreet 6701408Srandyf /* 6711408Srandyf * Start our ASF heartbeat counter as soon as possible. 6721408Srandyf */ 6731408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 6741408Srandyf /* start ASF heart beat */ 6751408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 6764588Sml149210 (void *)bgep, 6774588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 6781408Srandyf bgep->asf_status = ASF_STAT_RUN; 6791408Srandyf } 6801408Srandyf } 6811408Srandyf #endif 6821369Sdduvall BGE_DEBUG(("bge_m_unicst_set($%p) done", arg)); 6831865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 6841865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6851865Sdilpreet mutex_exit(bgep->genlock); 6861865Sdilpreet return (EIO); 6871865Sdilpreet } 6881865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 6891865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6901865Sdilpreet mutex_exit(bgep->genlock); 6911865Sdilpreet return (EIO); 6921865Sdilpreet } 6931369Sdduvall mutex_exit(bgep->genlock); 6941369Sdduvall 6951369Sdduvall return (0); 6961369Sdduvall } 6971369Sdduvall 6981369Sdduvall /* 6992331Skrgopi * The following four routines are used as callbacks for multiple MAC 7002331Skrgopi * address support: 7012331Skrgopi * - bge_m_unicst_add(void *, mac_multi_addr_t *); 7022331Skrgopi * - bge_m_unicst_remove(void *, mac_addr_slot_t); 7032331Skrgopi * - bge_m_unicst_modify(void *, mac_multi_addr_t *); 7042331Skrgopi * - bge_m_unicst_get(void *, mac_multi_addr_t *); 7052331Skrgopi */ 7062331Skrgopi 7072331Skrgopi /* 7082331Skrgopi * bge_m_unicst_add() - will find an unused address slot, set the 7092331Skrgopi * address value to the one specified, reserve that slot and enable 7102331Skrgopi * the NIC to start filtering on the new MAC address. 7112331Skrgopi * address slot. Returns 0 on success. 7122331Skrgopi */ 7132331Skrgopi static int 7142331Skrgopi bge_m_unicst_add(void *arg, mac_multi_addr_t *maddr) 7152331Skrgopi { 7162331Skrgopi bge_t *bgep = arg; /* private device info */ 7172331Skrgopi mac_addr_slot_t slot; 7182406Skrgopi int err; 7192331Skrgopi 7202331Skrgopi if (mac_unicst_verify(bgep->mh, 7212331Skrgopi maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 7222331Skrgopi return (EINVAL); 7232331Skrgopi 7242331Skrgopi mutex_enter(bgep->genlock); 7252331Skrgopi if (bgep->unicst_addr_avail == 0) { 7262331Skrgopi /* no slots available */ 7272331Skrgopi mutex_exit(bgep->genlock); 7282331Skrgopi return (ENOSPC); 7292331Skrgopi } 7302331Skrgopi 7312331Skrgopi /* 7322331Skrgopi * Primary/default address is in slot 0. The next three 7332331Skrgopi * addresses are the multiple MAC addresses. So multiple 7342331Skrgopi * MAC address 0 is in slot 1, 1 in slot 2, and so on. 7352406Skrgopi * So the first multiple MAC address resides in slot 1. 7362331Skrgopi */ 7372406Skrgopi for (slot = 1; slot < bgep->unicst_addr_total; slot++) { 7382406Skrgopi if (bgep->curr_addr[slot].set == B_FALSE) { 7392406Skrgopi bgep->curr_addr[slot].set = B_TRUE; 7402331Skrgopi break; 7412331Skrgopi } 7422331Skrgopi } 7432331Skrgopi 7442406Skrgopi ASSERT(slot < bgep->unicst_addr_total); 7452331Skrgopi bgep->unicst_addr_avail--; 7462331Skrgopi mutex_exit(bgep->genlock); 7472331Skrgopi maddr->mma_slot = slot; 7482331Skrgopi 7492331Skrgopi if ((err = bge_unicst_set(bgep, maddr->mma_addr, slot)) != 0) { 7502331Skrgopi mutex_enter(bgep->genlock); 7512406Skrgopi bgep->curr_addr[slot].set = B_FALSE; 7522331Skrgopi bgep->unicst_addr_avail++; 7532331Skrgopi mutex_exit(bgep->genlock); 7542331Skrgopi } 7552331Skrgopi return (err); 7562331Skrgopi } 7572331Skrgopi 7582331Skrgopi /* 7592331Skrgopi * bge_m_unicst_remove() - removes a MAC address that was added by a 7602331Skrgopi * call to bge_m_unicst_add(). The slot number that was returned in 7612331Skrgopi * add() is passed in the call to remove the address. 7622331Skrgopi * Returns 0 on success. 7632331Skrgopi */ 7642331Skrgopi static int 7652331Skrgopi bge_m_unicst_remove(void *arg, mac_addr_slot_t slot) 7662331Skrgopi { 7672331Skrgopi bge_t *bgep = arg; /* private device info */ 7682331Skrgopi 7692406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 7702406Skrgopi return (EINVAL); 7712406Skrgopi 7722331Skrgopi mutex_enter(bgep->genlock); 7732406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 7742406Skrgopi bgep->curr_addr[slot].set = B_FALSE; 7752331Skrgopi bgep->unicst_addr_avail++; 7762331Skrgopi mutex_exit(bgep->genlock); 7772331Skrgopi /* 7782331Skrgopi * Copy the default address to the passed slot 7792331Skrgopi */ 7802406Skrgopi return (bge_unicst_set(bgep, bgep->curr_addr[0].addr, slot)); 7812331Skrgopi } 7822331Skrgopi mutex_exit(bgep->genlock); 7832331Skrgopi return (EINVAL); 7842331Skrgopi } 7852331Skrgopi 7862331Skrgopi /* 7872331Skrgopi * bge_m_unicst_modify() - modifies the value of an address that 7882331Skrgopi * has been added by bge_m_unicst_add(). The new address, address 7892331Skrgopi * length and the slot number that was returned in the call to add 7902331Skrgopi * should be passed to bge_m_unicst_modify(). mma_flags should be 7912331Skrgopi * set to 0. Returns 0 on success. 7922331Skrgopi */ 7932331Skrgopi static int 7942331Skrgopi bge_m_unicst_modify(void *arg, mac_multi_addr_t *maddr) 7952331Skrgopi { 7962331Skrgopi bge_t *bgep = arg; /* private device info */ 7972331Skrgopi mac_addr_slot_t slot; 7982331Skrgopi 7992331Skrgopi if (mac_unicst_verify(bgep->mh, 8002331Skrgopi maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 8012331Skrgopi return (EINVAL); 8022331Skrgopi 8032331Skrgopi slot = maddr->mma_slot; 8042331Skrgopi 8052406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 8062406Skrgopi return (EINVAL); 8072406Skrgopi 8082331Skrgopi mutex_enter(bgep->genlock); 8092406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 8102331Skrgopi mutex_exit(bgep->genlock); 8112331Skrgopi return (bge_unicst_set(bgep, maddr->mma_addr, slot)); 8122331Skrgopi } 8132331Skrgopi mutex_exit(bgep->genlock); 8142331Skrgopi 8152331Skrgopi return (EINVAL); 8162331Skrgopi } 8172331Skrgopi 8182331Skrgopi /* 8192331Skrgopi * bge_m_unicst_get() - will get the MAC address and all other 8202331Skrgopi * information related to the address slot passed in mac_multi_addr_t. 8212331Skrgopi * mma_flags should be set to 0 in the call. 8222331Skrgopi * On return, mma_flags can take the following values: 8232331Skrgopi * 1) MMAC_SLOT_UNUSED 8242331Skrgopi * 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR 8252331Skrgopi * 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR 8262331Skrgopi * 4) MMAC_SLOT_USED 8272331Skrgopi */ 8282331Skrgopi static int 8292331Skrgopi bge_m_unicst_get(void *arg, mac_multi_addr_t *maddr) 8302331Skrgopi { 8312331Skrgopi bge_t *bgep = arg; /* private device info */ 8322331Skrgopi mac_addr_slot_t slot; 8332331Skrgopi 8342331Skrgopi slot = maddr->mma_slot; 8352331Skrgopi 8362406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 8372331Skrgopi return (EINVAL); 8382331Skrgopi 8392331Skrgopi mutex_enter(bgep->genlock); 8402406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 8412406Skrgopi ethaddr_copy(bgep->curr_addr[slot].addr, 8422331Skrgopi maddr->mma_addr); 8432331Skrgopi maddr->mma_flags = MMAC_SLOT_USED; 8442331Skrgopi } else { 8452331Skrgopi maddr->mma_flags = MMAC_SLOT_UNUSED; 8462331Skrgopi } 8472331Skrgopi mutex_exit(bgep->genlock); 8482331Skrgopi 8492331Skrgopi return (0); 8502331Skrgopi } 8512331Skrgopi 8525903Ssowmini extern void bge_wake_factotum(bge_t *); 8535903Ssowmini 8545903Ssowmini static boolean_t 8555903Ssowmini bge_param_locked(mac_prop_id_t pr_num) 8565903Ssowmini { 8575903Ssowmini /* 8585903Ssowmini * All adv_* parameters are locked (read-only) while 8595903Ssowmini * the device is in any sort of loopback mode ... 8605903Ssowmini */ 8615903Ssowmini switch (pr_num) { 8626789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 8636789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 8646789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 8656789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 8666789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 8676789Sam223141 case MAC_PROP_EN_100FDX_CAP: 8686789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 8696789Sam223141 case MAC_PROP_EN_100HDX_CAP: 8706789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 8716789Sam223141 case MAC_PROP_EN_10FDX_CAP: 8726789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 8736789Sam223141 case MAC_PROP_EN_10HDX_CAP: 8746789Sam223141 case MAC_PROP_AUTONEG: 8756789Sam223141 case MAC_PROP_FLOWCTRL: 8765903Ssowmini return (B_TRUE); 8775903Ssowmini } 8785903Ssowmini return (B_FALSE); 8795903Ssowmini } 8805903Ssowmini /* 8815903Ssowmini * callback functions for set/get of properties 8825903Ssowmini */ 8835903Ssowmini static int 8845903Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 8855903Ssowmini uint_t pr_valsize, const void *pr_val) 8865903Ssowmini { 8875903Ssowmini bge_t *bgep = barg; 8885903Ssowmini int err = 0; 8896512Ssowmini uint32_t cur_mtu, new_mtu; 8905903Ssowmini uint_t maxsdu; 8915903Ssowmini link_flowctrl_t fl; 8925903Ssowmini 8935903Ssowmini mutex_enter(bgep->genlock); 8945903Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE && 8955903Ssowmini bge_param_locked(pr_num)) { 8965903Ssowmini /* 8975903Ssowmini * All adv_* parameters are locked (read-only) 8985903Ssowmini * while the device is in any sort of loopback mode. 8995903Ssowmini */ 9005903Ssowmini mutex_exit(bgep->genlock); 9015903Ssowmini return (EBUSY); 9025903Ssowmini } 9036512Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 9046789Sam223141 ((pr_num == MAC_PROP_EN_100FDX_CAP) || 9056789Sam223141 (pr_num == MAC_PROP_EN_100FDX_CAP) || 9066789Sam223141 (pr_num == MAC_PROP_EN_10FDX_CAP) || 9076789Sam223141 (pr_num == MAC_PROP_EN_10HDX_CAP))) { 9086512Ssowmini /* 9096512Ssowmini * these properties are read/write on copper, 9106512Ssowmini * read-only and 0 on serdes 9116512Ssowmini */ 9126512Ssowmini mutex_exit(bgep->genlock); 9136512Ssowmini return (ENOTSUP); 9146512Ssowmini } 9156512Ssowmini 9165903Ssowmini switch (pr_num) { 9176789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 9185903Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val; 9195903Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val; 9205903Ssowmini goto reprogram; 9216789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 9225903Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val; 9235903Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val; 9245903Ssowmini goto reprogram; 9256789Sam223141 case MAC_PROP_EN_100FDX_CAP: 9265903Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val; 9275903Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val; 9285903Ssowmini goto reprogram; 9296789Sam223141 case MAC_PROP_EN_100HDX_CAP: 9305903Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val; 9315903Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val; 9325903Ssowmini goto reprogram; 9336789Sam223141 case MAC_PROP_EN_10FDX_CAP: 9345903Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val; 9355903Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val; 9365903Ssowmini goto reprogram; 9376789Sam223141 case MAC_PROP_EN_10HDX_CAP: 9385903Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val; 9395903Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val; 9405903Ssowmini reprogram: 9415903Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) 9425903Ssowmini err = EINVAL; 9435903Ssowmini break; 9446789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 9456789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 9466789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 9476789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 9486789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 9496789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 9506789Sam223141 case MAC_PROP_STATUS: 9516789Sam223141 case MAC_PROP_SPEED: 9526789Sam223141 case MAC_PROP_DUPLEX: 9536512Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */ 9545903Ssowmini break; 9556789Sam223141 case MAC_PROP_AUTONEG: 9565903Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val; 9575903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 9585903Ssowmini err = EINVAL; 9595903Ssowmini break; 9606789Sam223141 case MAC_PROP_MTU: 9615903Ssowmini cur_mtu = bgep->chipid.default_mtu; 9625903Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 9636512Ssowmini 9645903Ssowmini if (new_mtu == cur_mtu) { 9655903Ssowmini err = 0; 9665903Ssowmini break; 9675903Ssowmini } 9685903Ssowmini if (new_mtu < BGE_DEFAULT_MTU || 9695903Ssowmini new_mtu > BGE_MAXIMUM_MTU) { 9705903Ssowmini err = EINVAL; 9715903Ssowmini break; 9725903Ssowmini } 9735903Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) && 9745903Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { 9755903Ssowmini err = EINVAL; 9765903Ssowmini break; 9775903Ssowmini } 9785903Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) { 9795903Ssowmini err = EBUSY; 9805903Ssowmini break; 9815903Ssowmini } 9825903Ssowmini bgep->chipid.default_mtu = new_mtu; 9835903Ssowmini if (bge_chip_id_init(bgep)) { 9845903Ssowmini err = EINVAL; 9855903Ssowmini break; 9865903Ssowmini } 9875903Ssowmini maxsdu = bgep->chipid.ethmax_size - 9885903Ssowmini sizeof (struct ether_header); 9895903Ssowmini err = mac_maxsdu_update(bgep->mh, maxsdu); 9905903Ssowmini if (err == 0) { 9915903Ssowmini bgep->bge_dma_error = B_TRUE; 9925903Ssowmini bgep->manual_reset = B_TRUE; 9935903Ssowmini bge_chip_stop(bgep, B_TRUE); 9945903Ssowmini bge_wake_factotum(bgep); 9955903Ssowmini err = 0; 9965903Ssowmini } 9975903Ssowmini break; 9986789Sam223141 case MAC_PROP_FLOWCTRL: 9995903Ssowmini bcopy(pr_val, &fl, sizeof (fl)); 10005903Ssowmini switch (fl) { 10015903Ssowmini default: 10026512Ssowmini err = ENOTSUP; 10035903Ssowmini break; 10045903Ssowmini case LINK_FLOWCTRL_NONE: 10055903Ssowmini bgep->param_adv_pause = 0; 10065903Ssowmini bgep->param_adv_asym_pause = 0; 10075903Ssowmini 10085903Ssowmini bgep->param_link_rx_pause = B_FALSE; 10095903Ssowmini bgep->param_link_tx_pause = B_FALSE; 10105903Ssowmini break; 10115903Ssowmini case LINK_FLOWCTRL_RX: 10125903Ssowmini if (!((bgep->param_lp_pause == 0) && 10135903Ssowmini (bgep->param_lp_asym_pause == 1))) { 10145903Ssowmini err = EINVAL; 10155903Ssowmini break; 10165903Ssowmini } 10175903Ssowmini bgep->param_adv_pause = 1; 10185903Ssowmini bgep->param_adv_asym_pause = 1; 10195903Ssowmini 10205903Ssowmini bgep->param_link_rx_pause = B_TRUE; 10215903Ssowmini bgep->param_link_tx_pause = B_FALSE; 10225903Ssowmini break; 10235903Ssowmini case LINK_FLOWCTRL_TX: 10245903Ssowmini if (!((bgep->param_lp_pause == 1) && 10255903Ssowmini (bgep->param_lp_asym_pause == 1))) { 10265903Ssowmini err = EINVAL; 10275903Ssowmini break; 10285903Ssowmini } 10295903Ssowmini bgep->param_adv_pause = 0; 10305903Ssowmini bgep->param_adv_asym_pause = 1; 10315903Ssowmini 10325903Ssowmini bgep->param_link_rx_pause = B_FALSE; 10335903Ssowmini bgep->param_link_tx_pause = B_TRUE; 10345903Ssowmini break; 10355903Ssowmini case LINK_FLOWCTRL_BI: 10365903Ssowmini if (bgep->param_lp_pause != 1) { 10375903Ssowmini err = EINVAL; 10385903Ssowmini break; 10395903Ssowmini } 10405903Ssowmini bgep->param_adv_pause = 1; 10415903Ssowmini 10425903Ssowmini bgep->param_link_rx_pause = B_TRUE; 10435903Ssowmini bgep->param_link_tx_pause = B_TRUE; 10445903Ssowmini break; 10455903Ssowmini } 10465903Ssowmini 10475903Ssowmini if (err == 0) { 10485903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 10495903Ssowmini err = EINVAL; 10505903Ssowmini } 10515903Ssowmini 10525903Ssowmini break; 10536789Sam223141 case MAC_PROP_PRIVATE: 10545903Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize, 10555903Ssowmini pr_val); 10565903Ssowmini break; 10576512Ssowmini default: 10586512Ssowmini err = ENOTSUP; 10596512Ssowmini break; 10605903Ssowmini } 10615903Ssowmini mutex_exit(bgep->genlock); 10625903Ssowmini return (err); 10635903Ssowmini } 10646512Ssowmini 10655903Ssowmini static int 10665903Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 10676512Ssowmini uint_t pr_flags, uint_t pr_valsize, void *pr_val) 10685903Ssowmini { 10695903Ssowmini bge_t *bgep = barg; 10705903Ssowmini int err = 0; 10715903Ssowmini link_flowctrl_t fl; 10726512Ssowmini uint64_t speed; 10736512Ssowmini int flags = bgep->chipid.flags; 10746789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 10756512Ssowmini 10766512Ssowmini if (pr_valsize == 0) 10776512Ssowmini return (EINVAL); 10785903Ssowmini bzero(pr_val, pr_valsize); 10795903Ssowmini switch (pr_num) { 10806789Sam223141 case MAC_PROP_DUPLEX: 10816512Ssowmini if (pr_valsize < sizeof (link_duplex_t)) 10825903Ssowmini return (EINVAL); 10836512Ssowmini bcopy(&bgep->param_link_duplex, pr_val, 10846512Ssowmini sizeof (link_duplex_t)); 10855903Ssowmini break; 10866789Sam223141 case MAC_PROP_SPEED: 10876512Ssowmini if (pr_valsize < sizeof (speed)) 10885903Ssowmini return (EINVAL); 10896512Ssowmini speed = bgep->param_link_speed * 1000000ull; 10906512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 10915903Ssowmini break; 10926789Sam223141 case MAC_PROP_STATUS: 10936512Ssowmini if (pr_valsize < sizeof (link_state_t)) 10945903Ssowmini return (EINVAL); 10956512Ssowmini bcopy(&bgep->link_state, pr_val, 10966512Ssowmini sizeof (link_state_t)); 10975903Ssowmini break; 10986789Sam223141 case MAC_PROP_AUTONEG: 10996512Ssowmini if (is_default) 11006512Ssowmini *(uint8_t *)pr_val = 1; 11016512Ssowmini else 11026512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg; 11035903Ssowmini break; 11046789Sam223141 case MAC_PROP_FLOWCTRL: 11056512Ssowmini if (pr_valsize < sizeof (fl)) 11065903Ssowmini return (EINVAL); 11076512Ssowmini if (is_default) { 11086512Ssowmini fl = LINK_FLOWCTRL_BI; 11096512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 11106512Ssowmini break; 11116512Ssowmini } 11126512Ssowmini 11135903Ssowmini if (bgep->param_link_rx_pause && 11145903Ssowmini !bgep->param_link_tx_pause) 11155903Ssowmini fl = LINK_FLOWCTRL_RX; 11165903Ssowmini 11175903Ssowmini if (!bgep->param_link_rx_pause && 11185903Ssowmini !bgep->param_link_tx_pause) 11195903Ssowmini fl = LINK_FLOWCTRL_NONE; 11205903Ssowmini 11215903Ssowmini if (!bgep->param_link_rx_pause && 11225903Ssowmini bgep->param_link_tx_pause) 11235903Ssowmini fl = LINK_FLOWCTRL_TX; 11245903Ssowmini 11255903Ssowmini if (bgep->param_link_rx_pause && 11265903Ssowmini bgep->param_link_tx_pause) 11275903Ssowmini fl = LINK_FLOWCTRL_BI; 11285903Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 11295903Ssowmini break; 11306789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 11316512Ssowmini if (is_default) 11326512Ssowmini *(uint8_t *)pr_val = 1; 11336512Ssowmini else 11346512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx; 11355903Ssowmini break; 11366789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 11376512Ssowmini if (is_default) 11386512Ssowmini *(uint8_t *)pr_val = 1; 11396512Ssowmini else 11406512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx; 11415903Ssowmini break; 11426789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 11436512Ssowmini if (is_default) 11446512Ssowmini *(uint8_t *)pr_val = 1; 11456512Ssowmini else 11466512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx; 11475903Ssowmini break; 11486789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 11496512Ssowmini if (is_default) 11506512Ssowmini *(uint8_t *)pr_val = 1; 11516512Ssowmini else 11526512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx; 11535903Ssowmini break; 11546789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 11556512Ssowmini if (is_default) { 11566512Ssowmini *(uint8_t *)pr_val = 11576512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11586512Ssowmini } else { 11596512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx; 11606512Ssowmini } 11615903Ssowmini break; 11626789Sam223141 case MAC_PROP_EN_100FDX_CAP: 11636512Ssowmini if (is_default) { 11646512Ssowmini *(uint8_t *)pr_val = 11656512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11666512Ssowmini } else { 11676512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx; 11686512Ssowmini } 11695903Ssowmini break; 11706789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 11716512Ssowmini if (is_default) { 11726512Ssowmini *(uint8_t *)pr_val = 11736512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11746512Ssowmini } else { 11756512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx; 11766512Ssowmini } 11775903Ssowmini break; 11786789Sam223141 case MAC_PROP_EN_100HDX_CAP: 11796512Ssowmini if (is_default) { 11806512Ssowmini *(uint8_t *)pr_val = 11816512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11826512Ssowmini } else { 11836512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx; 11846512Ssowmini } 11855903Ssowmini break; 11866789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 11876512Ssowmini if (is_default) { 11886512Ssowmini *(uint8_t *)pr_val = 11896512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11906512Ssowmini } else { 11916512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx; 11926512Ssowmini } 11935903Ssowmini break; 11946789Sam223141 case MAC_PROP_EN_10FDX_CAP: 11956512Ssowmini if (is_default) { 11966512Ssowmini *(uint8_t *)pr_val = 11976512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11986512Ssowmini } else { 11996512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx; 12006512Ssowmini } 12015903Ssowmini break; 12026789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 12036512Ssowmini if (is_default) { 12046512Ssowmini *(uint8_t *)pr_val = 12056512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12066512Ssowmini } else { 12076512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx; 12086512Ssowmini } 12095903Ssowmini break; 12106789Sam223141 case MAC_PROP_EN_10HDX_CAP: 12116512Ssowmini if (is_default) { 12126512Ssowmini *(uint8_t *)pr_val = 12136512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12146512Ssowmini } else { 12156512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx; 12166512Ssowmini } 12175903Ssowmini break; 12186789Sam223141 case MAC_PROP_ADV_100T4_CAP: 12196789Sam223141 case MAC_PROP_EN_100T4_CAP: 12206512Ssowmini *(uint8_t *)pr_val = 0; 12216512Ssowmini break; 12226789Sam223141 case MAC_PROP_PRIVATE: 12236512Ssowmini err = bge_get_priv_prop(bgep, pr_name, pr_flags, 12246512Ssowmini pr_valsize, pr_val); 12256512Ssowmini return (err); 12265903Ssowmini default: 12276512Ssowmini return (ENOTSUP); 12285903Ssowmini } 12295903Ssowmini return (0); 12305903Ssowmini } 12315903Ssowmini 12325903Ssowmini /* ARGSUSED */ 12335903Ssowmini static int 12345903Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, 12355903Ssowmini const void *pr_val) 12365903Ssowmini { 12375903Ssowmini int err = 0; 12385903Ssowmini long result; 12395903Ssowmini 12406512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 12416512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12426512Ssowmini if (result > 1 || result < 0) { 12436512Ssowmini err = EINVAL; 12446512Ssowmini } else { 1245*7099Syt223700 bgep->param_adv_pause = (uint32_t)result; 12466512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12476512Ssowmini err = EINVAL; 12486512Ssowmini } 12496512Ssowmini return (err); 12506512Ssowmini } 12516512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 12526512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12536512Ssowmini if (result > 1 || result < 0) { 12546512Ssowmini err = EINVAL; 12556512Ssowmini } else { 1256*7099Syt223700 bgep->param_adv_asym_pause = (uint32_t)result; 12576512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12586512Ssowmini err = EINVAL; 12596512Ssowmini } 12606512Ssowmini return (err); 12616512Ssowmini } 12625903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 12635903Ssowmini 12645903Ssowmini /* 12655903Ssowmini * on the Tx side, we need to update the h/w register for 12665903Ssowmini * real packet transmission per packet. The drain_max parameter 12675903Ssowmini * is used to reduce the register access. This parameter 12685903Ssowmini * controls the max number of packets that we will hold before 12695903Ssowmini * updating the bge h/w to trigger h/w transmit. The bge 12705903Ssowmini * chipset usually has a max of 512 Tx descriptors, thus 12715903Ssowmini * the upper bound on drain_max is 512. 12725903Ssowmini */ 12735903Ssowmini if (pr_val == NULL) { 12745903Ssowmini err = EINVAL; 12755903Ssowmini return (err); 12765903Ssowmini } 12775903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12785903Ssowmini if (result > 512 || result < 1) 12795903Ssowmini err = EINVAL; 12805903Ssowmini else { 12815903Ssowmini bgep->param_drain_max = (uint32_t)result; 12825903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12835903Ssowmini err = EINVAL; 12845903Ssowmini } 12855903Ssowmini return (err); 12865903Ssowmini } 12875903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 12885903Ssowmini 12895903Ssowmini if (pr_val == NULL) { 12905903Ssowmini err = EINVAL; 12915903Ssowmini return (err); 12925903Ssowmini } 12935903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12945903Ssowmini if (result > 7 || result < 0) 12955903Ssowmini err = EINVAL; 12965903Ssowmini else { 12975903Ssowmini bgep->param_msi_cnt = (uint32_t)result; 12985903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12995903Ssowmini err = EINVAL; 13005903Ssowmini } 13015903Ssowmini return (err); 13025903Ssowmini } 13035903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 13046512Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 13055903Ssowmini return (EINVAL); 13065903Ssowmini 1307*7099Syt223700 bgep->chipid.rx_ticks_norm = (uint32_t)result; 13085903Ssowmini return (0); 13095903Ssowmini } 13105903Ssowmini 13115903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 13125903Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 13135903Ssowmini return (EINVAL); 13145903Ssowmini 1315*7099Syt223700 bgep->chipid.rx_count_norm = (uint32_t)result; 13165903Ssowmini return (0); 13175903Ssowmini } 13186512Ssowmini return (ENOTSUP); 13195903Ssowmini } 13205903Ssowmini 13215903Ssowmini static int 13226512Ssowmini bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_flags, 13236512Ssowmini uint_t pr_valsize, void *pr_val) 13245903Ssowmini { 13256512Ssowmini int err = ENOTSUP; 13266789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 13276512Ssowmini int value; 13286512Ssowmini 13296512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 13306512Ssowmini value = (is_default? 1 : bge->param_adv_pause); 13316512Ssowmini err = 0; 13326512Ssowmini goto done; 13336512Ssowmini } 13346512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 13356512Ssowmini value = (is_default? 1 : bge->param_adv_asym_pause); 13366512Ssowmini err = 0; 13376512Ssowmini goto done; 13386512Ssowmini } 13395903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 13406512Ssowmini value = (is_default? 64 : bge->param_drain_max); 13415903Ssowmini err = 0; 13425903Ssowmini goto done; 13435903Ssowmini } 13445903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 13456512Ssowmini value = (is_default? 0 : bge->param_msi_cnt); 13465903Ssowmini err = 0; 13475903Ssowmini goto done; 13485903Ssowmini } 13495903Ssowmini 13505903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 13516512Ssowmini value = (is_default? bge_rx_ticks_norm : 13526512Ssowmini bge->chipid.rx_ticks_norm); 13535903Ssowmini err = 0; 13545903Ssowmini goto done; 13555903Ssowmini } 13565903Ssowmini 13575903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 13586512Ssowmini value = (is_default? bge_rx_count_norm : 13596512Ssowmini bge->chipid.rx_count_norm); 13605903Ssowmini err = 0; 13615903Ssowmini goto done; 13625903Ssowmini } 13635903Ssowmini 13645903Ssowmini done: 13656512Ssowmini if (err == 0) { 13666512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 13675903Ssowmini } 13685903Ssowmini return (err); 13695903Ssowmini } 13705903Ssowmini 13712331Skrgopi /* 13721369Sdduvall * Compute the index of the required bit in the multicast hash map. 13731369Sdduvall * This must mirror the way the hardware actually does it! 13741369Sdduvall * See Broadcom document 570X-PG102-R page 125. 13751369Sdduvall */ 13761369Sdduvall static uint32_t 13771369Sdduvall bge_hash_index(const uint8_t *mca) 13781369Sdduvall { 13791369Sdduvall uint32_t hash; 13801369Sdduvall 13811369Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 13821369Sdduvall 13831369Sdduvall return (hash); 13841369Sdduvall } 13851369Sdduvall 13861369Sdduvall /* 13871369Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 13881369Sdduvall */ 13891369Sdduvall static int 13901369Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 13911369Sdduvall { 13921369Sdduvall bge_t *bgep = arg; /* private device info */ 13931369Sdduvall uint32_t hash; 13941369Sdduvall uint32_t index; 13951369Sdduvall uint32_t word; 13961369Sdduvall uint32_t bit; 13971369Sdduvall uint8_t *refp; 13981369Sdduvall 13991369Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 14004588Sml149210 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 14011369Sdduvall 14021369Sdduvall /* 14031369Sdduvall * Precalculate all required masks, pointers etc ... 14041369Sdduvall */ 14051369Sdduvall hash = bge_hash_index(mca); 14061369Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 14071369Sdduvall word = index/32u; 14081369Sdduvall bit = 1 << (index % 32u); 14091369Sdduvall refp = &bgep->mcast_refs[index]; 14101369Sdduvall 14111369Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 14124588Sml149210 hash, index, word, bit, *refp)); 14131369Sdduvall 14141369Sdduvall /* 14151369Sdduvall * We must set the appropriate bit in the hash map (and the 14161369Sdduvall * corresponding h/w register) when the refcount goes from 0 14171369Sdduvall * to >0, and clear it when the last ref goes away (refcount 14181369Sdduvall * goes from >0 back to 0). If we change the hash map, we 14191369Sdduvall * must also update the chip's hardware map registers. 14201369Sdduvall */ 14211369Sdduvall mutex_enter(bgep->genlock); 14221865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 14231865Sdilpreet /* can happen during autorecovery */ 14241865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14251865Sdilpreet mutex_exit(bgep->genlock); 14261865Sdilpreet return (EIO); 14271865Sdilpreet } 14281369Sdduvall if (add) { 14291369Sdduvall if ((*refp)++ == 0) { 14301369Sdduvall bgep->mcast_hash[word] |= bit; 14311408Srandyf #ifdef BGE_IPMI_ASF 14321865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 14331408Srandyf #else 14341865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 14351408Srandyf #endif 14361865Sdilpreet (void) bge_check_acc_handle(bgep, 14371865Sdilpreet bgep->cfg_handle); 14381865Sdilpreet (void) bge_check_acc_handle(bgep, 14391865Sdilpreet bgep->io_handle); 14401865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 14411865Sdilpreet DDI_SERVICE_DEGRADED); 14421865Sdilpreet mutex_exit(bgep->genlock); 14431865Sdilpreet return (EIO); 14441865Sdilpreet } 14451369Sdduvall } 14461369Sdduvall } else { 14471369Sdduvall if (--(*refp) == 0) { 14481369Sdduvall bgep->mcast_hash[word] &= ~bit; 14491408Srandyf #ifdef BGE_IPMI_ASF 14501865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 14511408Srandyf #else 14521865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 14531408Srandyf #endif 14541865Sdilpreet (void) bge_check_acc_handle(bgep, 14551865Sdilpreet bgep->cfg_handle); 14561865Sdilpreet (void) bge_check_acc_handle(bgep, 14571865Sdilpreet bgep->io_handle); 14581865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 14591865Sdilpreet DDI_SERVICE_DEGRADED); 14601865Sdilpreet mutex_exit(bgep->genlock); 14611865Sdilpreet return (EIO); 14621865Sdilpreet } 14631369Sdduvall } 14641369Sdduvall } 14651369Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 14661865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 14671865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14681865Sdilpreet mutex_exit(bgep->genlock); 14691865Sdilpreet return (EIO); 14701865Sdilpreet } 14711865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 14721865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14731865Sdilpreet mutex_exit(bgep->genlock); 14741865Sdilpreet return (EIO); 14751865Sdilpreet } 14761369Sdduvall mutex_exit(bgep->genlock); 14771369Sdduvall 14781369Sdduvall return (0); 14791369Sdduvall } 14801369Sdduvall 14811369Sdduvall /* 14821369Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 14831369Sdduvall * 14841369Sdduvall * Program the hardware to enable/disable promiscuous and/or 14851369Sdduvall * receive-all-multicast modes. 14861369Sdduvall */ 14871369Sdduvall static int 14881369Sdduvall bge_m_promisc(void *arg, boolean_t on) 14891369Sdduvall { 14901369Sdduvall bge_t *bgep = arg; 14911369Sdduvall 14921369Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 14931369Sdduvall 14941369Sdduvall /* 14951369Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 14961369Sdduvall */ 14971369Sdduvall mutex_enter(bgep->genlock); 14981865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 14991865Sdilpreet /* can happen during autorecovery */ 15001865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15011865Sdilpreet mutex_exit(bgep->genlock); 15021865Sdilpreet return (EIO); 15031865Sdilpreet } 15041369Sdduvall bgep->promisc = on; 15051408Srandyf #ifdef BGE_IPMI_ASF 15061865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 15071408Srandyf #else 15081865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 15091408Srandyf #endif 15101865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 15111865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 15121865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15131865Sdilpreet mutex_exit(bgep->genlock); 15141865Sdilpreet return (EIO); 15151865Sdilpreet } 15161369Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 15171865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 15181865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15191865Sdilpreet mutex_exit(bgep->genlock); 15201865Sdilpreet return (EIO); 15211865Sdilpreet } 15221865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 15231865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15241865Sdilpreet mutex_exit(bgep->genlock); 15251865Sdilpreet return (EIO); 15261865Sdilpreet } 15271369Sdduvall mutex_exit(bgep->genlock); 15281369Sdduvall return (0); 15291369Sdduvall } 15301369Sdduvall 15312311Sseb /*ARGSUSED*/ 15322311Sseb static boolean_t 15332311Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 15342311Sseb { 15352331Skrgopi bge_t *bgep = arg; 15362331Skrgopi 15372311Sseb switch (cap) { 15382311Sseb case MAC_CAPAB_HCKSUM: { 15392311Sseb uint32_t *txflags = cap_data; 15402311Sseb 15412311Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 15422311Sseb break; 15432311Sseb } 15442331Skrgopi 15452311Sseb case MAC_CAPAB_POLL: 15462311Sseb /* 15472311Sseb * There's nothing for us to fill in, simply returning 15482311Sseb * B_TRUE stating that we support polling is sufficient. 15492311Sseb */ 15502311Sseb break; 15512331Skrgopi 15522331Skrgopi case MAC_CAPAB_MULTIADDRESS: { 15532331Skrgopi multiaddress_capab_t *mmacp = cap_data; 15542331Skrgopi 15552331Skrgopi mutex_enter(bgep->genlock); 15562406Skrgopi /* 15572406Skrgopi * The number of MAC addresses made available by 15582406Skrgopi * this capability is one less than the total as 15592406Skrgopi * the primary address in slot 0 is counted in 15602406Skrgopi * the total. 15612406Skrgopi */ 15622406Skrgopi mmacp->maddr_naddr = bgep->unicst_addr_total - 1; 15632331Skrgopi mmacp->maddr_naddrfree = bgep->unicst_addr_avail; 15642331Skrgopi /* No multiple factory addresses, set mma_flag to 0 */ 15652331Skrgopi mmacp->maddr_flag = 0; 15662331Skrgopi mmacp->maddr_handle = bgep; 15672331Skrgopi mmacp->maddr_add = bge_m_unicst_add; 15682331Skrgopi mmacp->maddr_remove = bge_m_unicst_remove; 15692331Skrgopi mmacp->maddr_modify = bge_m_unicst_modify; 15702331Skrgopi mmacp->maddr_get = bge_m_unicst_get; 15712331Skrgopi mmacp->maddr_reserve = NULL; 15722331Skrgopi mutex_exit(bgep->genlock); 15732331Skrgopi break; 15742331Skrgopi } 15752331Skrgopi 15762311Sseb default: 15772311Sseb return (B_FALSE); 15782311Sseb } 15792311Sseb return (B_TRUE); 15802311Sseb } 15812311Sseb 15821369Sdduvall /* 15831369Sdduvall * Loopback ioctl code 15841369Sdduvall */ 15851369Sdduvall 15861369Sdduvall static lb_property_t loopmodes[] = { 15871369Sdduvall { normal, "normal", BGE_LOOP_NONE }, 15881369Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 15891369Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 15901369Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 15911369Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 15921369Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 15931369Sdduvall }; 15941369Sdduvall 15951369Sdduvall static enum ioc_reply 15961369Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 15971369Sdduvall { 15981369Sdduvall /* 15991369Sdduvall * If the mode isn't being changed, there's nothing to do ... 16001369Sdduvall */ 16011369Sdduvall if (mode == bgep->param_loop_mode) 16021369Sdduvall return (IOC_ACK); 16031369Sdduvall 16041369Sdduvall /* 16051369Sdduvall * Validate the requested mode and prepare a suitable message 16061369Sdduvall * to explain the link down/up cycle that the change will 16071369Sdduvall * probably induce ... 16081369Sdduvall */ 16091369Sdduvall switch (mode) { 16101369Sdduvall default: 16111369Sdduvall return (IOC_INVAL); 16121369Sdduvall 16131369Sdduvall case BGE_LOOP_NONE: 16141369Sdduvall case BGE_LOOP_EXTERNAL_1000: 16151369Sdduvall case BGE_LOOP_EXTERNAL_100: 16161369Sdduvall case BGE_LOOP_EXTERNAL_10: 16171369Sdduvall case BGE_LOOP_INTERNAL_PHY: 16181369Sdduvall case BGE_LOOP_INTERNAL_MAC: 16191369Sdduvall break; 16201369Sdduvall } 16211369Sdduvall 16221369Sdduvall /* 16231369Sdduvall * All OK; tell the caller to reprogram 16241369Sdduvall * the PHY and/or MAC for the new mode ... 16251369Sdduvall */ 16261369Sdduvall bgep->param_loop_mode = mode; 16271369Sdduvall return (IOC_RESTART_ACK); 16281369Sdduvall } 16291369Sdduvall 16301369Sdduvall static enum ioc_reply 16311369Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 16321369Sdduvall { 16331369Sdduvall lb_info_sz_t *lbsp; 16341369Sdduvall lb_property_t *lbpp; 16351369Sdduvall uint32_t *lbmp; 16361369Sdduvall int cmd; 16371369Sdduvall 16381369Sdduvall _NOTE(ARGUNUSED(wq)) 16391369Sdduvall 16401369Sdduvall /* 16411369Sdduvall * Validate format of ioctl 16421369Sdduvall */ 16431369Sdduvall if (mp->b_cont == NULL) 16441369Sdduvall return (IOC_INVAL); 16451369Sdduvall 16461369Sdduvall cmd = iocp->ioc_cmd; 16471369Sdduvall switch (cmd) { 16481369Sdduvall default: 16491369Sdduvall /* NOTREACHED */ 16501369Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 16511369Sdduvall return (IOC_INVAL); 16521369Sdduvall 16531369Sdduvall case LB_GET_INFO_SIZE: 16541369Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 16551369Sdduvall return (IOC_INVAL); 1656*7099Syt223700 lbsp = (void *)mp->b_cont->b_rptr; 16571369Sdduvall *lbsp = sizeof (loopmodes); 16581369Sdduvall return (IOC_REPLY); 16591369Sdduvall 16601369Sdduvall case LB_GET_INFO: 16611369Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 16621369Sdduvall return (IOC_INVAL); 1663*7099Syt223700 lbpp = (void *)mp->b_cont->b_rptr; 16641369Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 16651369Sdduvall return (IOC_REPLY); 16661369Sdduvall 16671369Sdduvall case LB_GET_MODE: 16681369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 16691369Sdduvall return (IOC_INVAL); 1670*7099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 16711369Sdduvall *lbmp = bgep->param_loop_mode; 16721369Sdduvall return (IOC_REPLY); 16731369Sdduvall 16741369Sdduvall case LB_SET_MODE: 16751369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 16761369Sdduvall return (IOC_INVAL); 1677*7099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 16781369Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 16791369Sdduvall } 16801369Sdduvall } 16811369Sdduvall 16821369Sdduvall /* 16831369Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 16841369Sdduvall */ 16851369Sdduvall static void 16861369Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 16871369Sdduvall { 16881369Sdduvall bge_t *bgep = arg; 16891369Sdduvall struct iocblk *iocp; 16901369Sdduvall enum ioc_reply status; 16911369Sdduvall boolean_t need_privilege; 16921369Sdduvall int err; 16931369Sdduvall int cmd; 16941369Sdduvall 16951369Sdduvall /* 16961369Sdduvall * Validate the command before bothering with the mutex ... 16971369Sdduvall */ 1698*7099Syt223700 iocp = (void *)mp->b_rptr; 16991369Sdduvall iocp->ioc_error = 0; 17001369Sdduvall need_privilege = B_TRUE; 17011369Sdduvall cmd = iocp->ioc_cmd; 17021369Sdduvall switch (cmd) { 17031369Sdduvall default: 17041369Sdduvall miocnak(wq, mp, 0, EINVAL); 17051369Sdduvall return; 17061369Sdduvall 17071369Sdduvall case BGE_MII_READ: 17081369Sdduvall case BGE_MII_WRITE: 17091369Sdduvall case BGE_SEE_READ: 17101369Sdduvall case BGE_SEE_WRITE: 17112675Szh199473 case BGE_FLASH_READ: 17122675Szh199473 case BGE_FLASH_WRITE: 17131369Sdduvall case BGE_DIAG: 17141369Sdduvall case BGE_PEEK: 17151369Sdduvall case BGE_POKE: 17161369Sdduvall case BGE_PHY_RESET: 17171369Sdduvall case BGE_SOFT_RESET: 17181369Sdduvall case BGE_HARD_RESET: 17191369Sdduvall break; 17201369Sdduvall 17211369Sdduvall case LB_GET_INFO_SIZE: 17221369Sdduvall case LB_GET_INFO: 17231369Sdduvall case LB_GET_MODE: 17241369Sdduvall need_privilege = B_FALSE; 17251369Sdduvall /* FALLTHRU */ 17261369Sdduvall case LB_SET_MODE: 17271369Sdduvall break; 17281369Sdduvall 17291369Sdduvall } 17301369Sdduvall 17311369Sdduvall if (need_privilege) { 17321369Sdduvall /* 17331369Sdduvall * Check for specific net_config privilege on Solaris 10+. 17341369Sdduvall */ 17352681Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 17361369Sdduvall if (err != 0) { 17371369Sdduvall miocnak(wq, mp, 0, err); 17381369Sdduvall return; 17391369Sdduvall } 17401369Sdduvall } 17411369Sdduvall 17421369Sdduvall mutex_enter(bgep->genlock); 17431865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 17441865Sdilpreet /* can happen during autorecovery */ 17451865Sdilpreet mutex_exit(bgep->genlock); 17461865Sdilpreet miocnak(wq, mp, 0, EIO); 17471865Sdilpreet return; 17481865Sdilpreet } 17491369Sdduvall 17501369Sdduvall switch (cmd) { 17511369Sdduvall default: 17521369Sdduvall _NOTE(NOTREACHED) 17531369Sdduvall status = IOC_INVAL; 17541369Sdduvall break; 17551369Sdduvall 17561369Sdduvall case BGE_MII_READ: 17571369Sdduvall case BGE_MII_WRITE: 17581369Sdduvall case BGE_SEE_READ: 17591369Sdduvall case BGE_SEE_WRITE: 17602675Szh199473 case BGE_FLASH_READ: 17612675Szh199473 case BGE_FLASH_WRITE: 17621369Sdduvall case BGE_DIAG: 17631369Sdduvall case BGE_PEEK: 17641369Sdduvall case BGE_POKE: 17651369Sdduvall case BGE_PHY_RESET: 17661369Sdduvall case BGE_SOFT_RESET: 17671369Sdduvall case BGE_HARD_RESET: 17681369Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 17691369Sdduvall break; 17701369Sdduvall 17711369Sdduvall case LB_GET_INFO_SIZE: 17721369Sdduvall case LB_GET_INFO: 17731369Sdduvall case LB_GET_MODE: 17741369Sdduvall case LB_SET_MODE: 17751369Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 17761369Sdduvall break; 17771369Sdduvall 17781369Sdduvall } 17791369Sdduvall 17801369Sdduvall /* 17811369Sdduvall * Do we need to reprogram the PHY and/or the MAC? 17821369Sdduvall * Do it now, while we still have the mutex. 17831369Sdduvall * 17841369Sdduvall * Note: update the PHY first, 'cos it controls the 17851369Sdduvall * speed/duplex parameters that the MAC code uses. 17861369Sdduvall */ 17871369Sdduvall switch (status) { 17881369Sdduvall case IOC_RESTART_REPLY: 17891369Sdduvall case IOC_RESTART_ACK: 17905903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 17911865Sdilpreet status = IOC_INVAL; 17921369Sdduvall break; 17931369Sdduvall } 17941369Sdduvall 17951865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 17961865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 17971865Sdilpreet status = IOC_INVAL; 17981865Sdilpreet } 17991865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 18001865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 18011865Sdilpreet status = IOC_INVAL; 18021865Sdilpreet } 18031369Sdduvall mutex_exit(bgep->genlock); 18041369Sdduvall 18051369Sdduvall /* 18061369Sdduvall * Finally, decide how to reply 18071369Sdduvall */ 18081369Sdduvall switch (status) { 18091369Sdduvall default: 18101369Sdduvall case IOC_INVAL: 18111369Sdduvall /* 18121369Sdduvall * Error, reply with a NAK and EINVAL or the specified error 18131369Sdduvall */ 18141369Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 18154588Sml149210 EINVAL : iocp->ioc_error); 18161369Sdduvall break; 18171369Sdduvall 18181369Sdduvall case IOC_DONE: 18191369Sdduvall /* 18201369Sdduvall * OK, reply already sent 18211369Sdduvall */ 18221369Sdduvall break; 18231369Sdduvall 18241369Sdduvall case IOC_RESTART_ACK: 18251369Sdduvall case IOC_ACK: 18261369Sdduvall /* 18271369Sdduvall * OK, reply with an ACK 18281369Sdduvall */ 18291369Sdduvall miocack(wq, mp, 0, 0); 18301369Sdduvall break; 18311369Sdduvall 18321369Sdduvall case IOC_RESTART_REPLY: 18331369Sdduvall case IOC_REPLY: 18341369Sdduvall /* 18351369Sdduvall * OK, send prepared reply as ACK or NAK 18361369Sdduvall */ 18371369Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 18384588Sml149210 M_IOCACK : M_IOCNAK; 18391369Sdduvall qreply(wq, mp); 18401369Sdduvall break; 18411369Sdduvall } 18421369Sdduvall } 18431369Sdduvall 18441369Sdduvall static void 18455903Ssowmini bge_resources_add(bge_t *bgep, time_t time, uint_t pkt_cnt) 18461369Sdduvall { 18475903Ssowmini 18481369Sdduvall recv_ring_t *rrp; 18491369Sdduvall mac_rx_fifo_t mrf; 18501369Sdduvall int ring; 18511369Sdduvall 18521369Sdduvall /* 18531369Sdduvall * Register Rx rings as resources and save mac 18541369Sdduvall * resource id for future reference 18551369Sdduvall */ 18561369Sdduvall mrf.mrf_type = MAC_RX_FIFO; 18571369Sdduvall mrf.mrf_blank = bge_chip_blank; 18581369Sdduvall mrf.mrf_arg = (void *)bgep; 18595903Ssowmini mrf.mrf_normal_blank_time = time; 18605903Ssowmini mrf.mrf_normal_pkt_count = pkt_cnt; 18611369Sdduvall 18621369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ring++) { 18631369Sdduvall rrp = &bgep->recv[ring]; 18642311Sseb rrp->handle = mac_resource_add(bgep->mh, 18651369Sdduvall (mac_resource_t *)&mrf); 18661369Sdduvall } 18675903Ssowmini } 18685903Ssowmini 18695903Ssowmini static void 18705903Ssowmini bge_m_resources(void *arg) 18715903Ssowmini { 18725903Ssowmini bge_t *bgep = arg; 18735903Ssowmini 18745903Ssowmini mutex_enter(bgep->genlock); 18755903Ssowmini 18765903Ssowmini bge_resources_add(bgep, bgep->chipid.rx_ticks_norm, 18775903Ssowmini bgep->chipid.rx_count_norm); 18781369Sdduvall mutex_exit(bgep->genlock); 18791369Sdduvall } 18801369Sdduvall 18811369Sdduvall /* 18821369Sdduvall * ========== Per-instance setup/teardown code ========== 18831369Sdduvall */ 18841369Sdduvall 18851369Sdduvall #undef BGE_DBG 18861369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 18873334Sgs150176 /* 18883334Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 18893334Sgs150176 */ 18903334Sgs150176 static int 18913334Sgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 18923334Sgs150176 uint_t dma_flags, dma_area_t *dma_p) 18933334Sgs150176 { 18943334Sgs150176 caddr_t va; 18953334Sgs150176 int err; 18963334Sgs150176 18973334Sgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 18984588Sml149210 (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 18993334Sgs150176 19003334Sgs150176 /* 19013334Sgs150176 * Allocate handle 19023334Sgs150176 */ 19033334Sgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 19044588Sml149210 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 19053334Sgs150176 if (err != DDI_SUCCESS) 19063334Sgs150176 return (DDI_FAILURE); 19073334Sgs150176 19083334Sgs150176 /* 19093334Sgs150176 * Allocate memory 19103334Sgs150176 */ 19113334Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 19124588Sml149210 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, 19134588Sml149210 &dma_p->acc_hdl); 19143334Sgs150176 if (err != DDI_SUCCESS) 19153334Sgs150176 return (DDI_FAILURE); 19163334Sgs150176 19173334Sgs150176 /* 19183334Sgs150176 * Bind the two together 19193334Sgs150176 */ 19203334Sgs150176 dma_p->mem_va = va; 19213334Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 19224588Sml149210 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 19234588Sml149210 &dma_p->cookie, &dma_p->ncookies); 19243334Sgs150176 19253334Sgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 19264588Sml149210 dma_p->alength, err, dma_p->ncookies)); 19273334Sgs150176 19283334Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 19293334Sgs150176 return (DDI_FAILURE); 19303334Sgs150176 19313334Sgs150176 dma_p->nslots = ~0U; 19323334Sgs150176 dma_p->size = ~0U; 19333334Sgs150176 dma_p->token = ~0U; 19343334Sgs150176 dma_p->offset = 0; 19353334Sgs150176 return (DDI_SUCCESS); 19363334Sgs150176 } 19373334Sgs150176 19383334Sgs150176 /* 19393334Sgs150176 * Free one allocated area of DMAable memory 19403334Sgs150176 */ 19413334Sgs150176 static void 19423334Sgs150176 bge_free_dma_mem(dma_area_t *dma_p) 19433334Sgs150176 { 19443334Sgs150176 if (dma_p->dma_hdl != NULL) { 19453334Sgs150176 if (dma_p->ncookies) { 19463334Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 19473334Sgs150176 dma_p->ncookies = 0; 19483334Sgs150176 } 19493334Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 19503334Sgs150176 dma_p->dma_hdl = NULL; 19513334Sgs150176 } 19523334Sgs150176 19533334Sgs150176 if (dma_p->acc_hdl != NULL) { 19543334Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 19553334Sgs150176 dma_p->acc_hdl = NULL; 19563334Sgs150176 } 19573334Sgs150176 } 19581369Sdduvall /* 19591369Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 19601369Sdduvall * updating the chunk descriptor accordingly. The size of the slice 19611369Sdduvall * is given by the product of the <qty> and <size> parameters. 19621369Sdduvall */ 19631369Sdduvall static void 19641369Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 19651369Sdduvall uint32_t qty, uint32_t size) 19661369Sdduvall { 19671369Sdduvall static uint32_t sequence = 0xbcd5704a; 19681369Sdduvall size_t totsize; 19691369Sdduvall 19701369Sdduvall totsize = qty*size; 19711369Sdduvall ASSERT(totsize <= chunk->alength); 19721369Sdduvall 19731369Sdduvall *slice = *chunk; 19741369Sdduvall slice->nslots = qty; 19751369Sdduvall slice->size = size; 19761369Sdduvall slice->alength = totsize; 19771369Sdduvall slice->token = ++sequence; 19781369Sdduvall 19791369Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 19801369Sdduvall chunk->alength -= totsize; 19811369Sdduvall chunk->offset += totsize; 19821369Sdduvall chunk->cookie.dmac_laddress += totsize; 19831369Sdduvall chunk->cookie.dmac_size -= totsize; 19841369Sdduvall } 19851369Sdduvall 19861369Sdduvall /* 19871369Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 19881369Sdduvall * the information in the <dma_area> descriptors that it contains 19891369Sdduvall * to set up all the other fields. This routine should be called 19901369Sdduvall * only once for each ring. 19911369Sdduvall */ 19921369Sdduvall static void 19931369Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 19941369Sdduvall { 19951369Sdduvall buff_ring_t *brp; 19961369Sdduvall bge_status_t *bsp; 19971369Sdduvall sw_rbd_t *srbdp; 19981369Sdduvall dma_area_t pbuf; 19991369Sdduvall uint32_t bufsize; 20001369Sdduvall uint32_t nslots; 20011369Sdduvall uint32_t slot; 20021369Sdduvall uint32_t split; 20031369Sdduvall 20041369Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 20051369Sdduvall NIC_MEM_SHADOW_BUFF_STD, 20061369Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 20071369Sdduvall NIC_MEM_SHADOW_BUFF_MINI 20081369Sdduvall }; 20091369Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 20101369Sdduvall RECV_STD_PROD_INDEX_REG, 20111369Sdduvall RECV_JUMBO_PROD_INDEX_REG, 20121369Sdduvall RECV_MINI_PROD_INDEX_REG 20131369Sdduvall }; 20141369Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 20151369Sdduvall STATUS_STD_BUFF_CONS_INDEX, 20161369Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 20171369Sdduvall STATUS_MINI_BUFF_CONS_INDEX 20181369Sdduvall }; 20191369Sdduvall 20201369Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 20214588Sml149210 (void *)bgep, ring)); 20221369Sdduvall 20231369Sdduvall brp = &bgep->buff[ring]; 20241369Sdduvall nslots = brp->desc.nslots; 20251369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 20261369Sdduvall bufsize = brp->buf[0].size; 20271369Sdduvall 20281369Sdduvall /* 20291369Sdduvall * Set up the copy of the h/w RCB 20301369Sdduvall * 20311369Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 20321369Sdduvall * field holds the number of slots), in a Receive Buffer Ring 20331369Sdduvall * this field indicates the size of each buffer in the ring. 20341369Sdduvall */ 20351369Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 2036*7099Syt223700 brp->hw_rcb.max_len = (uint16_t)bufsize; 20371369Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 20381369Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 20391369Sdduvall 20401369Sdduvall /* 20411369Sdduvall * Other one-off initialisation of per-ring data 20421369Sdduvall */ 20431369Sdduvall brp->bgep = bgep; 20441369Sdduvall bsp = DMA_VPTR(bgep->status_block); 20451369Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 20461369Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 20471369Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 20481369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 20491369Sdduvall 20501369Sdduvall /* 20511369Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 20521369Sdduvall */ 20531369Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 20541369Sdduvall brp->sw_rbds = srbdp; 20551369Sdduvall 20561369Sdduvall /* 20571369Sdduvall * Now initialise each array element once and for all 20581369Sdduvall */ 20591369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 20601369Sdduvall pbuf = brp->buf[split]; 20611369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 20621369Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 20631369Sdduvall ASSERT(pbuf.alength == 0); 20641369Sdduvall } 20651369Sdduvall } 20661369Sdduvall 20671369Sdduvall /* 20681369Sdduvall * Clean up initialisation done above before the memory is freed 20691369Sdduvall */ 20701369Sdduvall static void 20711369Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 20721369Sdduvall { 20731369Sdduvall buff_ring_t *brp; 20741369Sdduvall sw_rbd_t *srbdp; 20751369Sdduvall 20761369Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 20774588Sml149210 (void *)bgep, ring)); 20781369Sdduvall 20791369Sdduvall brp = &bgep->buff[ring]; 20801369Sdduvall srbdp = brp->sw_rbds; 20811369Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 20821369Sdduvall 20831369Sdduvall mutex_destroy(brp->rf_lock); 20841369Sdduvall } 20851369Sdduvall 20861369Sdduvall /* 20871369Sdduvall * Initialise the specified Receive (Return) Ring, using the 20881369Sdduvall * information in the <dma_area> descriptors that it contains 20891369Sdduvall * to set up all the other fields. This routine should be called 20901369Sdduvall * only once for each ring. 20911369Sdduvall */ 20921369Sdduvall static void 20931369Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 20941369Sdduvall { 20951369Sdduvall recv_ring_t *rrp; 20961369Sdduvall bge_status_t *bsp; 20971369Sdduvall uint32_t nslots; 20981369Sdduvall 20991369Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 21004588Sml149210 (void *)bgep, ring)); 21011369Sdduvall 21021369Sdduvall /* 21031369Sdduvall * The chip architecture requires that receive return rings have 21041369Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 21051369Sdduvall */ 21061369Sdduvall rrp = &bgep->recv[ring]; 21071369Sdduvall nslots = rrp->desc.nslots; 21081369Sdduvall ASSERT(nslots == 0 || nslots == 512 || 21094588Sml149210 nslots == 1024 || nslots == 2048); 21101369Sdduvall 21111369Sdduvall /* 21121369Sdduvall * Set up the copy of the h/w RCB 21131369Sdduvall */ 21141369Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 2115*7099Syt223700 rrp->hw_rcb.max_len = (uint16_t)nslots; 21161369Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21171369Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 21181369Sdduvall 21191369Sdduvall /* 21201369Sdduvall * Other one-off initialisation of per-ring data 21211369Sdduvall */ 21221369Sdduvall rrp->bgep = bgep; 21231369Sdduvall bsp = DMA_VPTR(bgep->status_block); 21241369Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 21251369Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 21261369Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 21271369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 21281369Sdduvall } 21291369Sdduvall 21301369Sdduvall 21311369Sdduvall /* 21321369Sdduvall * Clean up initialisation done above before the memory is freed 21331369Sdduvall */ 21341369Sdduvall static void 21351369Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 21361369Sdduvall { 21371369Sdduvall recv_ring_t *rrp; 21381369Sdduvall 21391369Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 21404588Sml149210 (void *)bgep, ring)); 21411369Sdduvall 21421369Sdduvall rrp = &bgep->recv[ring]; 21431369Sdduvall if (rrp->rx_softint) 21441369Sdduvall ddi_remove_softintr(rrp->rx_softint); 21451369Sdduvall mutex_destroy(rrp->rx_lock); 21461369Sdduvall } 21471369Sdduvall 21481369Sdduvall /* 21491369Sdduvall * Initialise the specified Send Ring, using the information in the 21501369Sdduvall * <dma_area> descriptors that it contains to set up all the other 21511369Sdduvall * fields. This routine should be called only once for each ring. 21521369Sdduvall */ 21531369Sdduvall static void 21541369Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 21551369Sdduvall { 21561369Sdduvall send_ring_t *srp; 21571369Sdduvall bge_status_t *bsp; 21581369Sdduvall sw_sbd_t *ssbdp; 21591369Sdduvall dma_area_t desc; 21601369Sdduvall dma_area_t pbuf; 21611369Sdduvall uint32_t nslots; 21621369Sdduvall uint32_t slot; 21631369Sdduvall uint32_t split; 21643334Sgs150176 sw_txbuf_t *txbuf; 21651369Sdduvall 21661369Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 21674588Sml149210 (void *)bgep, ring)); 21681369Sdduvall 21691369Sdduvall /* 21701369Sdduvall * The chip architecture requires that host-based send rings 21711369Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 21721369Sdduvall */ 21731369Sdduvall srp = &bgep->send[ring]; 21741369Sdduvall nslots = srp->desc.nslots; 21751369Sdduvall ASSERT(nslots == 0 || nslots == 512); 21761369Sdduvall 21771369Sdduvall /* 21781369Sdduvall * Set up the copy of the h/w RCB 21791369Sdduvall */ 21801369Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 2181*7099Syt223700 srp->hw_rcb.max_len = (uint16_t)nslots; 21821369Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21831369Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 21841369Sdduvall 21851369Sdduvall /* 21861369Sdduvall * Other one-off initialisation of per-ring data 21871369Sdduvall */ 21881369Sdduvall srp->bgep = bgep; 21891369Sdduvall bsp = DMA_VPTR(bgep->status_block); 21901369Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 21911369Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 21921369Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 21931369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 21943334Sgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER, 21953334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 21963334Sgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER, 21973334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 21981369Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 21991369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22003334Sgs150176 if (nslots == 0) 22013334Sgs150176 return; 22021369Sdduvall 22031369Sdduvall /* 22041369Sdduvall * Allocate the array of s/w Send Buffer Descriptors 22051369Sdduvall */ 22061369Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 22073334Sgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP); 22083334Sgs150176 srp->txbuf_head = 22093334Sgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP); 22103334Sgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP); 22111369Sdduvall srp->sw_sbds = ssbdp; 22123334Sgs150176 srp->txbuf = txbuf; 22133334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 22143334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 22153334Sgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT) 22163334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO; 22173334Sgs150176 else 22183334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY; 22193334Sgs150176 srp->tx_array = 1; 22201369Sdduvall 22211369Sdduvall /* 22223334Sgs150176 * Chunk tx desc area 22231369Sdduvall */ 22241369Sdduvall desc = srp->desc; 22253334Sgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) { 22263334Sgs150176 bge_slice_chunk(&ssbdp->desc, &desc, 1, 22273334Sgs150176 sizeof (bge_sbd_t)); 22283334Sgs150176 } 22293334Sgs150176 ASSERT(desc.alength == 0); 22303334Sgs150176 22313334Sgs150176 /* 22323334Sgs150176 * Chunk tx buffer area 22333334Sgs150176 */ 22341369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 22353334Sgs150176 pbuf = srp->buf[0][split]; 22363334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 22373334Sgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1, 22383334Sgs150176 bgep->chipid.snd_buff_size); 22393334Sgs150176 txbuf++; 22401369Sdduvall } 22411369Sdduvall ASSERT(pbuf.alength == 0); 22421369Sdduvall } 22431369Sdduvall } 22441369Sdduvall 22451369Sdduvall /* 22461369Sdduvall * Clean up initialisation done above before the memory is freed 22471369Sdduvall */ 22481369Sdduvall static void 22491369Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 22501369Sdduvall { 22511369Sdduvall send_ring_t *srp; 22523334Sgs150176 uint32_t array; 22533334Sgs150176 uint32_t split; 22543334Sgs150176 uint32_t nslots; 22551369Sdduvall 22561369Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 22574588Sml149210 (void *)bgep, ring)); 22581369Sdduvall 22591369Sdduvall srp = &bgep->send[ring]; 22603334Sgs150176 mutex_destroy(srp->tc_lock); 22613334Sgs150176 mutex_destroy(srp->freetxbuf_lock); 22623334Sgs150176 mutex_destroy(srp->txbuf_lock); 22631369Sdduvall mutex_destroy(srp->tx_lock); 22643334Sgs150176 nslots = srp->desc.nslots; 22653334Sgs150176 if (nslots == 0) 22663334Sgs150176 return; 22673334Sgs150176 22683334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 22693334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 22703334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 22713334Sgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds)); 22723334Sgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head)); 22733334Sgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf)); 22743334Sgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp)); 22753334Sgs150176 srp->sw_sbds = NULL; 22763334Sgs150176 srp->txbuf_head = NULL; 22773334Sgs150176 srp->txbuf = NULL; 22783334Sgs150176 srp->pktp = NULL; 22791369Sdduvall } 22801369Sdduvall 22811369Sdduvall /* 22821369Sdduvall * Initialise all transmit, receive, and buffer rings. 22831369Sdduvall */ 22841865Sdilpreet void 22851369Sdduvall bge_init_rings(bge_t *bgep) 22861369Sdduvall { 22873334Sgs150176 uint32_t ring; 22881369Sdduvall 22891369Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 22901369Sdduvall 22911369Sdduvall /* 22921369Sdduvall * Perform one-off initialisation of each ring ... 22931369Sdduvall */ 22941369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 22951369Sdduvall bge_init_send_ring(bgep, ring); 22961369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 22971369Sdduvall bge_init_recv_ring(bgep, ring); 22981369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 22991369Sdduvall bge_init_buff_ring(bgep, ring); 23001369Sdduvall } 23011369Sdduvall 23021369Sdduvall /* 23031369Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 23041369Sdduvall */ 23051865Sdilpreet void 23061369Sdduvall bge_fini_rings(bge_t *bgep) 23071369Sdduvall { 23083334Sgs150176 uint32_t ring; 23091369Sdduvall 23101369Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 23111369Sdduvall 23121369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 23131369Sdduvall bge_fini_buff_ring(bgep, ring); 23141369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 23151369Sdduvall bge_fini_recv_ring(bgep, ring); 23161369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 23171369Sdduvall bge_fini_send_ring(bgep, ring); 23181369Sdduvall } 23191369Sdduvall 23201369Sdduvall /* 23213334Sgs150176 * Called from the bge_m_stop() to free the tx buffers which are 23223334Sgs150176 * allocated from the tx process. 23231369Sdduvall */ 23243334Sgs150176 void 23253334Sgs150176 bge_free_txbuf_arrays(send_ring_t *srp) 23261369Sdduvall { 23273334Sgs150176 uint32_t array; 23283334Sgs150176 uint32_t split; 23293334Sgs150176 23303334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 23311369Sdduvall 23321369Sdduvall /* 23333334Sgs150176 * Free the extra tx buffer DMA area 23341369Sdduvall */ 23353334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 23363334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 23373334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 23381369Sdduvall 23391369Sdduvall /* 23403334Sgs150176 * Restore initial tx buffer numbers 23411369Sdduvall */ 23423334Sgs150176 srp->tx_array = 1; 23433334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 23443334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 23453334Sgs150176 srp->tx_flow = 0; 23463334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 23471369Sdduvall } 23481369Sdduvall 23491369Sdduvall /* 23503334Sgs150176 * Called from tx process to allocate more tx buffers 23511369Sdduvall */ 23523334Sgs150176 bge_queue_item_t * 23533334Sgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp) 23541369Sdduvall { 23553334Sgs150176 bge_queue_t *txbuf_queue; 23563334Sgs150176 bge_queue_item_t *txbuf_item_last; 23573334Sgs150176 bge_queue_item_t *txbuf_item; 23583334Sgs150176 bge_queue_item_t *txbuf_item_rtn; 23593334Sgs150176 sw_txbuf_t *txbuf; 23603334Sgs150176 dma_area_t area; 23613334Sgs150176 size_t txbuffsize; 23623334Sgs150176 uint32_t slot; 23633334Sgs150176 uint32_t array; 23643334Sgs150176 uint32_t split; 23653334Sgs150176 uint32_t err; 23663334Sgs150176 23673334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 23683334Sgs150176 23693334Sgs150176 array = srp->tx_array; 23703334Sgs150176 if (array >= srp->tx_array_max) 23713334Sgs150176 return (NULL); 23723334Sgs150176 23733334Sgs150176 /* 23743334Sgs150176 * Allocate memory & handles for TX buffers 23753334Sgs150176 */ 23763334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 23773334Sgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0); 23783334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 23793334Sgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 23804588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 23814588Sml149210 &srp->buf[array][split]); 23823334Sgs150176 if (err != DDI_SUCCESS) { 23833334Sgs150176 /* Free the last already allocated OK chunks */ 23843334Sgs150176 for (slot = 0; slot <= split; ++slot) 23853334Sgs150176 bge_free_dma_mem(&srp->buf[array][slot]); 23863334Sgs150176 srp->tx_alloc_fail++; 23873334Sgs150176 return (NULL); 23881369Sdduvall } 23893334Sgs150176 } 23903334Sgs150176 23913334Sgs150176 /* 23923334Sgs150176 * Chunk tx buffer area 23933334Sgs150176 */ 23943334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 23953334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 23963334Sgs150176 area = srp->buf[array][split]; 23973334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 23983334Sgs150176 bge_slice_chunk(&txbuf->buf, &area, 1, 23993334Sgs150176 bgep->chipid.snd_buff_size); 24003334Sgs150176 txbuf++; 24013334Sgs150176 } 24021369Sdduvall } 24031369Sdduvall 24043334Sgs150176 /* 24053334Sgs150176 * Add above buffers to the tx buffer pop queue 24063334Sgs150176 */ 24073334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 24083334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 24093334Sgs150176 txbuf_item_last = NULL; 24103334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) { 24113334Sgs150176 txbuf_item->item = txbuf; 24123334Sgs150176 txbuf_item->next = txbuf_item_last; 24133334Sgs150176 txbuf_item_last = txbuf_item; 24143334Sgs150176 txbuf++; 24153334Sgs150176 txbuf_item++; 24161369Sdduvall } 24173334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 24183334Sgs150176 txbuf_item_rtn = txbuf_item; 24193334Sgs150176 txbuf_item++; 24203334Sgs150176 txbuf_queue = srp->txbuf_pop_queue; 24213334Sgs150176 mutex_enter(txbuf_queue->lock); 24223334Sgs150176 txbuf_item->next = txbuf_queue->head; 24233334Sgs150176 txbuf_queue->head = txbuf_item_last; 24243334Sgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1; 24253334Sgs150176 mutex_exit(txbuf_queue->lock); 24263334Sgs150176 24273334Sgs150176 srp->tx_array++; 24283334Sgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM; 24293334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 24303334Sgs150176 24313334Sgs150176 return (txbuf_item_rtn); 24321369Sdduvall } 24331369Sdduvall 24341369Sdduvall /* 24351369Sdduvall * This function allocates all the transmit and receive buffers 24363334Sgs150176 * and descriptors, in four chunks. 24371369Sdduvall */ 24381865Sdilpreet int 24391369Sdduvall bge_alloc_bufs(bge_t *bgep) 24401369Sdduvall { 24411369Sdduvall dma_area_t area; 24421369Sdduvall size_t rxbuffsize; 24431369Sdduvall size_t txbuffsize; 24441369Sdduvall size_t rxbuffdescsize; 24451369Sdduvall size_t rxdescsize; 24461369Sdduvall size_t txdescsize; 24473334Sgs150176 uint32_t ring; 24483334Sgs150176 uint32_t rx_rings = bgep->chipid.rx_rings; 24493334Sgs150176 uint32_t tx_rings = bgep->chipid.tx_rings; 24501369Sdduvall int split; 24511369Sdduvall int err; 24521369Sdduvall 24531369Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 24544588Sml149210 (void *)bgep)); 24551369Sdduvall 24561908Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size; 24571369Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 24581369Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 24591369Sdduvall 24603334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 24611369Sdduvall txbuffsize *= tx_rings; 24621369Sdduvall 24631369Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 24641369Sdduvall rxdescsize *= sizeof (bge_rbd_t); 24651369Sdduvall 24661369Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 24671369Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 24681369Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 24691369Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 24701369Sdduvall 24711369Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 24721369Sdduvall txdescsize *= sizeof (bge_sbd_t); 24731369Sdduvall txdescsize += sizeof (bge_statistics_t); 24741369Sdduvall txdescsize += sizeof (bge_status_t); 24751369Sdduvall txdescsize += BGE_STATUS_PADDING; 24761369Sdduvall 24771369Sdduvall /* 24783907Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers 24793907Szh199473 */ 24803907Szh199473 if (bge_relaxed_ordering) 24813907Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING; 24823907Szh199473 24833907Szh199473 /* 24841369Sdduvall * Allocate memory & handles for RX buffers 24851369Sdduvall */ 24861369Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 24871369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 24881369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 24894588Sml149210 &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 24904588Sml149210 &bgep->rx_buff[split]); 24911369Sdduvall if (err != DDI_SUCCESS) 24921369Sdduvall return (DDI_FAILURE); 24931369Sdduvall } 24941369Sdduvall 24951369Sdduvall /* 24961369Sdduvall * Allocate memory & handles for TX buffers 24971369Sdduvall */ 24981369Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 24991369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25001369Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 25014588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 25024588Sml149210 &bgep->tx_buff[split]); 25031369Sdduvall if (err != DDI_SUCCESS) 25041369Sdduvall return (DDI_FAILURE); 25051369Sdduvall } 25061369Sdduvall 25073907Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING; 25083907Szh199473 25091369Sdduvall /* 25101369Sdduvall * Allocate memory & handles for receive return rings 25111369Sdduvall */ 25121369Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 25131369Sdduvall for (split = 0; split < rx_rings; ++split) { 25141369Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 25154588Sml149210 &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 25164588Sml149210 &bgep->rx_desc[split]); 25171369Sdduvall if (err != DDI_SUCCESS) 25181369Sdduvall return (DDI_FAILURE); 25191369Sdduvall } 25201369Sdduvall 25211369Sdduvall /* 25221369Sdduvall * Allocate memory & handles for buffer (producer) descriptor rings 25231369Sdduvall */ 25241369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 25254588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 25261369Sdduvall if (err != DDI_SUCCESS) 25271369Sdduvall return (DDI_FAILURE); 25281369Sdduvall 25291369Sdduvall /* 25301369Sdduvall * Allocate memory & handles for TX descriptor rings, 25311369Sdduvall * status block, and statistics area 25321369Sdduvall */ 25331369Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 25344588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 25351369Sdduvall if (err != DDI_SUCCESS) 25361369Sdduvall return (DDI_FAILURE); 25371369Sdduvall 25381369Sdduvall /* 25391369Sdduvall * Now carve up each of the allocated areas ... 25401369Sdduvall */ 25411369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25421369Sdduvall area = bgep->rx_buff[split]; 25431369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 25444588Sml149210 &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 25454588Sml149210 bgep->chipid.std_buf_size); 25461369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 25474588Sml149210 &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 25484588Sml149210 bgep->chipid.recv_jumbo_size); 25491369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 25504588Sml149210 &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 25514588Sml149210 BGE_MINI_BUFF_SIZE); 25521369Sdduvall } 25531369Sdduvall 25541369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25551369Sdduvall area = bgep->tx_buff[split]; 25561369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 25573334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 25584588Sml149210 &area, BGE_SEND_BUF_NUM/BGE_SPLIT, 25594588Sml149210 bgep->chipid.snd_buff_size); 25601369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 25613334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 25624588Sml149210 &area, 0, bgep->chipid.snd_buff_size); 25631369Sdduvall } 25641369Sdduvall 25651369Sdduvall for (ring = 0; ring < rx_rings; ++ring) 25661369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 25674588Sml149210 bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 25681369Sdduvall 25691369Sdduvall area = bgep->rx_desc[rx_rings]; 25701369Sdduvall for (; ring < BGE_RECV_RINGS_MAX; ++ring) 25711369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 25724588Sml149210 0, sizeof (bge_rbd_t)); 25731369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 25744588Sml149210 BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 25751369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 25764588Sml149210 bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 25771369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 25784588Sml149210 BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 25791369Sdduvall ASSERT(area.alength == 0); 25801369Sdduvall 25811369Sdduvall area = bgep->tx_desc; 25821369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 25831369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 25844588Sml149210 BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 25851369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 25861369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 25874588Sml149210 0, sizeof (bge_sbd_t)); 25881369Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 25891369Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 25901369Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 25911369Sdduvall DMA_ZERO(bgep->status_block); 25921369Sdduvall 25931369Sdduvall return (DDI_SUCCESS); 25941369Sdduvall } 25951369Sdduvall 25961369Sdduvall /* 25971369Sdduvall * This routine frees the transmit and receive buffers and descriptors. 25981369Sdduvall * Make sure the chip is stopped before calling it! 25991369Sdduvall */ 26001865Sdilpreet void 26011369Sdduvall bge_free_bufs(bge_t *bgep) 26021369Sdduvall { 26031369Sdduvall int split; 26041369Sdduvall 26051369Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 26064588Sml149210 (void *)bgep)); 26071369Sdduvall 26081369Sdduvall bge_free_dma_mem(&bgep->tx_desc); 26091369Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 26101369Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 26111369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 26121369Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 26131369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 26141369Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 26151369Sdduvall } 26161369Sdduvall 26171369Sdduvall /* 26181369Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 26191369Sdduvall */ 26201369Sdduvall 26211369Sdduvall static void 26221369Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 26231369Sdduvall { 26241369Sdduvall struct ether_addr sysaddr; 26251369Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 26261369Sdduvall uchar_t *bytes; 26271369Sdduvall int *ints; 26281369Sdduvall uint_t nelts; 26291369Sdduvall int err; 26301369Sdduvall 26311369Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 26324588Sml149210 (void *)bgep)); 26331369Sdduvall 26341369Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 26354588Sml149210 cidp->hw_mac_addr, 26364588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 26374588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 26381369Sdduvall 26391369Sdduvall /* 26401369Sdduvall * The "vendor's factory-set address" may already have 26411369Sdduvall * been extracted from the chip, but if the property 26421369Sdduvall * "local-mac-address" is set we use that instead. It 26431369Sdduvall * will normally be set by OBP, but it could also be 26441369Sdduvall * specified in a .conf file(!) 26451369Sdduvall * 26461369Sdduvall * There doesn't seem to be a way to define byte-array 26471369Sdduvall * properties in a .conf, so we check whether it looks 26481369Sdduvall * like an array of 6 ints instead. 26491369Sdduvall * 26501369Sdduvall * Then, we check whether it looks like an array of 6 26511369Sdduvall * bytes (which it should, if OBP set it). If we can't 26521369Sdduvall * make sense of it either way, we'll ignore it. 26531369Sdduvall */ 26541369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 26554588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 26561369Sdduvall if (err == DDI_PROP_SUCCESS) { 26571369Sdduvall if (nelts == ETHERADDRL) { 26581369Sdduvall while (nelts--) 26591369Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 26602331Skrgopi cidp->vendor_addr.set = B_TRUE; 26611369Sdduvall } 26621369Sdduvall ddi_prop_free(ints); 26631369Sdduvall } 26641369Sdduvall 26651369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 26664588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 26671369Sdduvall if (err == DDI_PROP_SUCCESS) { 26681369Sdduvall if (nelts == ETHERADDRL) { 26691369Sdduvall while (nelts--) 26701369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 26712331Skrgopi cidp->vendor_addr.set = B_TRUE; 26721369Sdduvall } 26731369Sdduvall ddi_prop_free(bytes); 26741369Sdduvall } 26751369Sdduvall 26761369Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 26774588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 26784588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 26791369Sdduvall 26801369Sdduvall /* 26811369Sdduvall * Look up the OBP property "local-mac-address?". Note that even 26821369Sdduvall * though its value is a string (which should be "true" or "false"), 26831369Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 26841369Sdduvall * the buffer first and then fetch the property as an untyped array; 26851369Sdduvall * this may or may not include a final NUL, but since there will 26861369Sdduvall * always be one left at the end of the buffer we can now treat it 26871369Sdduvall * as a string anyway. 26881369Sdduvall */ 26891369Sdduvall nelts = sizeof (propbuf); 26901369Sdduvall bzero(propbuf, nelts--); 26911369Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 26924588Sml149210 DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 26931369Sdduvall 26941369Sdduvall /* 26951369Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 26961369Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 26971369Sdduvall * 'local-mac-address? = false', use "the system address" instead 26981369Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 26991369Sdduvall */ 27002331Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0) 27011369Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 27021369Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 27032331Skrgopi cidp->vendor_addr.set = B_TRUE; 27041369Sdduvall } 27051369Sdduvall 27061369Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 27074588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27084588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27091369Sdduvall 27101369Sdduvall /* 27111369Sdduvall * Finally(!), if there's a valid "mac-address" property (created 27121369Sdduvall * if we netbooted from this interface), we must use this instead 27131369Sdduvall * of any of the above to ensure that the NFS/install server doesn't 27141369Sdduvall * get confused by the address changing as Solaris takes over! 27151369Sdduvall */ 27161369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 27174588Sml149210 DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 27181369Sdduvall if (err == DDI_PROP_SUCCESS) { 27191369Sdduvall if (nelts == ETHERADDRL) { 27201369Sdduvall while (nelts--) 27211369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 27222331Skrgopi cidp->vendor_addr.set = B_TRUE; 27231369Sdduvall } 27241369Sdduvall ddi_prop_free(bytes); 27251369Sdduvall } 27261369Sdduvall 27271369Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 27284588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27294588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27301369Sdduvall } 27311369Sdduvall 27321865Sdilpreet 27331865Sdilpreet /*ARGSUSED*/ 27341865Sdilpreet int 27351865Sdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 27361865Sdilpreet { 27371865Sdilpreet ddi_fm_error_t de; 27381865Sdilpreet 27391865Sdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 27401865Sdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 27411865Sdilpreet return (de.fme_status); 27421865Sdilpreet } 27431865Sdilpreet 27441865Sdilpreet /*ARGSUSED*/ 27451865Sdilpreet int 27461865Sdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 27471865Sdilpreet { 27481865Sdilpreet ddi_fm_error_t de; 27491865Sdilpreet 27501865Sdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 27511865Sdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 27521865Sdilpreet return (de.fme_status); 27531865Sdilpreet } 27541865Sdilpreet 27551865Sdilpreet /* 27561865Sdilpreet * The IO fault service error handling callback function 27571865Sdilpreet */ 27581865Sdilpreet /*ARGSUSED*/ 27591865Sdilpreet static int 27601865Sdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 27611865Sdilpreet { 27621865Sdilpreet /* 27631865Sdilpreet * as the driver can always deal with an error in any dma or 27641865Sdilpreet * access handle, we can just return the fme_status value. 27651865Sdilpreet */ 27661865Sdilpreet pci_ereport_post(dip, err, NULL); 27671865Sdilpreet return (err->fme_status); 27681865Sdilpreet } 27691865Sdilpreet 27701865Sdilpreet static void 27711865Sdilpreet bge_fm_init(bge_t *bgep) 27721865Sdilpreet { 27731865Sdilpreet ddi_iblock_cookie_t iblk; 27741865Sdilpreet 27751865Sdilpreet /* Only register with IO Fault Services if we have some capability */ 27761865Sdilpreet if (bgep->fm_capabilities) { 27771865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 27781865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 27791865Sdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 27801865Sdilpreet 27811865Sdilpreet /* Register capabilities with IO Fault Services */ 27821865Sdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 27831865Sdilpreet 27841865Sdilpreet /* 27851865Sdilpreet * Initialize pci ereport capabilities if ereport capable 27861865Sdilpreet */ 27871865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 27881865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 27891865Sdilpreet pci_ereport_setup(bgep->devinfo); 27901865Sdilpreet 27911865Sdilpreet /* 27921865Sdilpreet * Register error callback if error callback capable 27931865Sdilpreet */ 27941865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 27951865Sdilpreet ddi_fm_handler_register(bgep->devinfo, 27964588Sml149210 bge_fm_error_cb, (void*) bgep); 27971865Sdilpreet } else { 27981865Sdilpreet /* 27991865Sdilpreet * These fields have to be cleared of FMA if there are no 28001865Sdilpreet * FMA capabilities at runtime. 28011865Sdilpreet */ 28021865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 28031865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 28041865Sdilpreet dma_attr.dma_attr_flags = 0; 28051865Sdilpreet } 28061865Sdilpreet } 28071865Sdilpreet 28081865Sdilpreet static void 28091865Sdilpreet bge_fm_fini(bge_t *bgep) 28101865Sdilpreet { 28111865Sdilpreet /* Only unregister FMA capabilities if we registered some */ 28121865Sdilpreet if (bgep->fm_capabilities) { 28131865Sdilpreet 28141865Sdilpreet /* 28151865Sdilpreet * Release any resources allocated by pci_ereport_setup() 28161865Sdilpreet */ 28171865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 28181865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28191865Sdilpreet pci_ereport_teardown(bgep->devinfo); 28201865Sdilpreet 28211865Sdilpreet /* 28221865Sdilpreet * Un-register error callback if error callback capable 28231865Sdilpreet */ 28241865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28251865Sdilpreet ddi_fm_handler_unregister(bgep->devinfo); 28261865Sdilpreet 28271865Sdilpreet /* Unregister from IO Fault Services */ 28281865Sdilpreet ddi_fm_fini(bgep->devinfo); 28291865Sdilpreet } 28301865Sdilpreet } 28311865Sdilpreet 28321369Sdduvall static void 28331408Srandyf #ifdef BGE_IPMI_ASF 28341408Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 28351408Srandyf #else 28361369Sdduvall bge_unattach(bge_t *bgep) 28371408Srandyf #endif 28381369Sdduvall { 28391369Sdduvall BGE_TRACE(("bge_unattach($%p)", 28401369Sdduvall (void *)bgep)); 28411369Sdduvall 28421369Sdduvall /* 28431369Sdduvall * Flag that no more activity may be initiated 28441369Sdduvall */ 28451369Sdduvall bgep->progress &= ~PROGRESS_READY; 28461369Sdduvall 28471369Sdduvall /* 28481369Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 28491369Sdduvall * Clean up and free all BGE data structures 28501369Sdduvall */ 28515107Seota if (bgep->periodic_id != NULL) { 28525107Seota ddi_periodic_delete(bgep->periodic_id); 28535107Seota bgep->periodic_id = NULL; 28541369Sdduvall } 28551369Sdduvall if (bgep->progress & PROGRESS_KSTATS) 28561369Sdduvall bge_fini_kstats(bgep); 28571369Sdduvall if (bgep->progress & PROGRESS_PHY) 28581369Sdduvall bge_phys_reset(bgep); 28591369Sdduvall if (bgep->progress & PROGRESS_HWINT) { 28601369Sdduvall mutex_enter(bgep->genlock); 28611408Srandyf #ifdef BGE_IPMI_ASF 28621865Sdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 28631865Sdilpreet #else 28641865Sdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 28651865Sdilpreet #endif 28661865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28671865Sdilpreet DDI_SERVICE_UNAFFECTED); 28681865Sdilpreet #ifdef BGE_IPMI_ASF 28691408Srandyf if (bgep->asf_enabled) { 28701408Srandyf /* 28711408Srandyf * This register has been overlaid. We restore its 28721408Srandyf * initial value here. 28731408Srandyf */ 28741408Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 28751408Srandyf BGE_NIC_DATA_SIG); 28761408Srandyf } 28771408Srandyf #endif 28781865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 28791865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28801865Sdilpreet DDI_SERVICE_UNAFFECTED); 28811865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 28821865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28831865Sdilpreet DDI_SERVICE_UNAFFECTED); 28841369Sdduvall mutex_exit(bgep->genlock); 28851369Sdduvall } 28861369Sdduvall if (bgep->progress & PROGRESS_INTR) { 28871865Sdilpreet bge_intr_disable(bgep); 28881369Sdduvall bge_fini_rings(bgep); 28891369Sdduvall } 28901865Sdilpreet if (bgep->progress & PROGRESS_HWINT) { 28911865Sdilpreet bge_rem_intrs(bgep); 28921865Sdilpreet rw_destroy(bgep->errlock); 28931865Sdilpreet mutex_destroy(bgep->softintrlock); 28941865Sdilpreet mutex_destroy(bgep->genlock); 28951865Sdilpreet } 28961369Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 28971369Sdduvall ddi_remove_softintr(bgep->factotum_id); 28981369Sdduvall if (bgep->progress & PROGRESS_RESCHED) 28993334Sgs150176 ddi_remove_softintr(bgep->drain_id); 29001865Sdilpreet if (bgep->progress & PROGRESS_BUFS) 29011865Sdilpreet bge_free_bufs(bgep); 29021369Sdduvall if (bgep->progress & PROGRESS_REGS) 29031369Sdduvall ddi_regs_map_free(&bgep->io_handle); 29041369Sdduvall if (bgep->progress & PROGRESS_CFG) 29051369Sdduvall pci_config_teardown(&bgep->cfg_handle); 29061369Sdduvall 29071865Sdilpreet bge_fm_fini(bgep); 29081865Sdilpreet 29091369Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 29103334Sgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t)); 29111369Sdduvall kmem_free(bgep, sizeof (*bgep)); 29121369Sdduvall } 29131369Sdduvall 29141369Sdduvall static int 29151369Sdduvall bge_resume(dev_info_t *devinfo) 29161369Sdduvall { 29171369Sdduvall bge_t *bgep; /* Our private data */ 29181369Sdduvall chip_id_t *cidp; 29191369Sdduvall chip_id_t chipid; 29201369Sdduvall 29211369Sdduvall bgep = ddi_get_driver_private(devinfo); 29221369Sdduvall if (bgep == NULL) 29231369Sdduvall return (DDI_FAILURE); 29241369Sdduvall 29251369Sdduvall /* 29261369Sdduvall * Refuse to resume if the data structures aren't consistent 29271369Sdduvall */ 29281369Sdduvall if (bgep->devinfo != devinfo) 29291369Sdduvall return (DDI_FAILURE); 29301369Sdduvall 29311408Srandyf #ifdef BGE_IPMI_ASF 29321408Srandyf /* 29331408Srandyf * Power management hasn't been supported in BGE now. If you 29341408Srandyf * want to implement it, please add the ASF/IPMI related 29351408Srandyf * code here. 29361408Srandyf */ 29371408Srandyf 29381408Srandyf #endif 29391408Srandyf 29401369Sdduvall /* 29411369Sdduvall * Read chip ID & set up config space command register(s) 29421369Sdduvall * Refuse to resume if the chip has changed its identity! 29431369Sdduvall */ 29441369Sdduvall cidp = &bgep->chipid; 29451865Sdilpreet mutex_enter(bgep->genlock); 29461369Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 29471865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 29481865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29491865Sdilpreet mutex_exit(bgep->genlock); 29501865Sdilpreet return (DDI_FAILURE); 29511865Sdilpreet } 29521865Sdilpreet mutex_exit(bgep->genlock); 29531369Sdduvall if (chipid.vendor != cidp->vendor) 29541369Sdduvall return (DDI_FAILURE); 29551369Sdduvall if (chipid.device != cidp->device) 29561369Sdduvall return (DDI_FAILURE); 29571369Sdduvall if (chipid.revision != cidp->revision) 29581369Sdduvall return (DDI_FAILURE); 29591369Sdduvall if (chipid.asic_rev != cidp->asic_rev) 29601369Sdduvall return (DDI_FAILURE); 29611369Sdduvall 29621369Sdduvall /* 29631369Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 29641369Sdduvall */ 29651369Sdduvall mutex_enter(bgep->genlock); 29661865Sdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 29671865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 29681865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 29691865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29701865Sdilpreet mutex_exit(bgep->genlock); 29711865Sdilpreet return (DDI_FAILURE); 29721865Sdilpreet } 29731865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 29741865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29751865Sdilpreet mutex_exit(bgep->genlock); 29761865Sdilpreet return (DDI_FAILURE); 29771865Sdilpreet } 29781865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 29791865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29801865Sdilpreet mutex_exit(bgep->genlock); 29811865Sdilpreet return (DDI_FAILURE); 29821865Sdilpreet } 29831369Sdduvall mutex_exit(bgep->genlock); 29841369Sdduvall return (DDI_SUCCESS); 29851369Sdduvall } 29861369Sdduvall 29871369Sdduvall /* 29881369Sdduvall * attach(9E) -- Attach a device to the system 29891369Sdduvall * 29901369Sdduvall * Called once for each board successfully probed. 29911369Sdduvall */ 29921369Sdduvall static int 29931369Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 29941369Sdduvall { 29951369Sdduvall bge_t *bgep; /* Our private data */ 29962311Sseb mac_register_t *macp; 29971369Sdduvall chip_id_t *cidp; 29981369Sdduvall caddr_t regs; 29991369Sdduvall int instance; 30001369Sdduvall int err; 30011369Sdduvall int intr_types; 30021408Srandyf #ifdef BGE_IPMI_ASF 30031408Srandyf uint32_t mhcrValue; 30043918Sml149210 #ifdef __sparc 30053918Sml149210 uint16_t value16; 30063918Sml149210 #endif 30073918Sml149210 #ifdef BGE_NETCONSOLE 30083918Sml149210 int retval; 30093918Sml149210 #endif 30101408Srandyf #endif 30111369Sdduvall 30121369Sdduvall instance = ddi_get_instance(devinfo); 30131369Sdduvall 30141369Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 30154588Sml149210 (void *)devinfo, cmd, instance)); 30161369Sdduvall BGE_BRKPT(NULL, "bge_attach"); 30171369Sdduvall 30181369Sdduvall switch (cmd) { 30191369Sdduvall default: 30201369Sdduvall return (DDI_FAILURE); 30211369Sdduvall 30221369Sdduvall case DDI_RESUME: 30231369Sdduvall return (bge_resume(devinfo)); 30241369Sdduvall 30251369Sdduvall case DDI_ATTACH: 30261369Sdduvall break; 30271369Sdduvall } 30281369Sdduvall 30291369Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 30303334Sgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP); 30311369Sdduvall ddi_set_driver_private(devinfo, bgep); 30321369Sdduvall bgep->bge_guard = BGE_GUARD; 30331369Sdduvall bgep->devinfo = devinfo; 30345903Ssowmini bgep->param_drain_max = 64; 30355903Ssowmini bgep->param_msi_cnt = 0; 30365903Ssowmini bgep->param_loop_mode = 0; 30371369Sdduvall 30381369Sdduvall /* 30391369Sdduvall * Initialize more fields in BGE private data 30401369Sdduvall */ 30411369Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 30424588Sml149210 DDI_PROP_DONTPASS, debug_propname, bge_debug); 30431369Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 30444588Sml149210 BGE_DRIVER_NAME, instance); 30451369Sdduvall 30461369Sdduvall /* 30471865Sdilpreet * Initialize for fma support 30481865Sdilpreet */ 30491865Sdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 30501865Sdilpreet DDI_PROP_DONTPASS, fm_cap, 30511865Sdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 30521865Sdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 30531865Sdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 30541865Sdilpreet bge_fm_init(bgep); 30551865Sdilpreet 30561865Sdilpreet /* 30571369Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 30581369Sdduvall * a power of 2) and convert to a mask. This can be used to 30591369Sdduvall * determine whether a message buffer crosses a page boundary. 30601369Sdduvall * Note: in 2s complement binary notation, if X is a power of 30611369Sdduvall * 2, then -X has the representation "11...1100...00". 30621369Sdduvall */ 30631369Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 30641369Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 30651369Sdduvall bgep->pagemask = -bgep->pagemask; 30661369Sdduvall 30671369Sdduvall /* 30681369Sdduvall * Map config space registers 30691369Sdduvall * Read chip ID & set up config space command register(s) 30701369Sdduvall * 30711369Sdduvall * Note: this leaves the chip accessible by Memory Space 30721369Sdduvall * accesses, but with interrupts and Bus Mastering off. 30731369Sdduvall * This should ensure that nothing untoward will happen 30741369Sdduvall * if it has been left active by the (net-)bootloader. 30751369Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 30761369Sdduvall * and allow interrupts only when everything else is set up. 30771369Sdduvall */ 30781369Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 30791408Srandyf #ifdef BGE_IPMI_ASF 30803918Sml149210 #ifdef __sparc 30813918Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM); 30823918Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME); 30833918Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16); 30843918Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 30854588Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 30864588Sml149210 MHCR_MASK_INTERRUPT_MODE | 30874588Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 30884588Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 30894588Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 30904588Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 30913918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue); 30923918Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG, 30934588Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) | 30944588Sml149210 MEMORY_ARBITER_ENABLE); 30953918Sml149210 #else 30961408Srandyf mhcrValue = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 30973918Sml149210 #endif 30981408Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 30991408Srandyf bgep->asf_wordswapped = B_TRUE; 31001408Srandyf } else { 31011408Srandyf bgep->asf_wordswapped = B_FALSE; 31021408Srandyf } 31031408Srandyf bge_asf_get_config(bgep); 31041408Srandyf #endif 31051369Sdduvall if (err != DDI_SUCCESS) { 31061369Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 31071369Sdduvall goto attach_fail; 31081369Sdduvall } 31091369Sdduvall bgep->progress |= PROGRESS_CFG; 31101369Sdduvall cidp = &bgep->chipid; 31111369Sdduvall bzero(cidp, sizeof (*cidp)); 31121369Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 31131865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 31141865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31151865Sdilpreet goto attach_fail; 31161865Sdilpreet } 31171369Sdduvall 31181408Srandyf #ifdef BGE_IPMI_ASF 31191408Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 31201408Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 31211408Srandyf bgep->asf_newhandshake = B_TRUE; 31221408Srandyf } else { 31231408Srandyf bgep->asf_newhandshake = B_FALSE; 31241408Srandyf } 31251408Srandyf #endif 31261408Srandyf 31271369Sdduvall /* 31281369Sdduvall * Update those parts of the chip ID derived from volatile 31291369Sdduvall * registers with the values seen by OBP (in case the chip 31301369Sdduvall * has been reset externally and therefore lost them). 31311369Sdduvall */ 31321369Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31334588Sml149210 DDI_PROP_DONTPASS, subven_propname, cidp->subven); 31341369Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31354588Sml149210 DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 31361369Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31374588Sml149210 DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 31381369Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31394588Sml149210 DDI_PROP_DONTPASS, latency_propname, cidp->latency); 31401369Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31414588Sml149210 DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 31421369Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31434588Sml149210 DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 31441369Sdduvall 31451369Sdduvall if (bge_jumbo_enable == B_TRUE) { 31461369Sdduvall cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31474588Sml149210 DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 31481369Sdduvall if ((cidp->default_mtu < BGE_DEFAULT_MTU)|| 31494588Sml149210 (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 31501369Sdduvall cidp->default_mtu = BGE_DEFAULT_MTU; 31511369Sdduvall } 31521369Sdduvall } 31531369Sdduvall /* 31541369Sdduvall * Map operating registers 31551369Sdduvall */ 31561369Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 31574588Sml149210 ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 31581369Sdduvall if (err != DDI_SUCCESS) { 31591369Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 31601369Sdduvall goto attach_fail; 31611369Sdduvall } 31621369Sdduvall bgep->io_regs = regs; 31631369Sdduvall bgep->progress |= PROGRESS_REGS; 31641369Sdduvall 31651369Sdduvall /* 31661369Sdduvall * Characterise the device, so we know its requirements. 31671369Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 31681369Sdduvall */ 31691865Sdilpreet if (bge_chip_id_init(bgep) == EIO) { 31701865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31711865Sdilpreet goto attach_fail; 31721865Sdilpreet } 31736512Ssowmini 31746512Ssowmini 31751369Sdduvall err = bge_alloc_bufs(bgep); 31761369Sdduvall if (err != DDI_SUCCESS) { 31771369Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 31781369Sdduvall goto attach_fail; 31791369Sdduvall } 31801865Sdilpreet bgep->progress |= PROGRESS_BUFS; 31811369Sdduvall 31821369Sdduvall /* 31831369Sdduvall * Add the softint handlers: 31841369Sdduvall * 31851369Sdduvall * Both of these handlers are used to avoid restrictions on the 31861369Sdduvall * context and/or mutexes required for some operations. In 31871369Sdduvall * particular, the hardware interrupt handler and its subfunctions 31881369Sdduvall * can detect a number of conditions that we don't want to handle 31891369Sdduvall * in that context or with that set of mutexes held. So, these 31901369Sdduvall * softints are triggered instead: 31911369Sdduvall * 31922135Szh199473 * the <resched> softint is triggered if we have previously 31931369Sdduvall * had to refuse to send a packet because of resource shortage 31941369Sdduvall * (we've run out of transmit buffers), but the send completion 31951369Sdduvall * interrupt handler has now detected that more buffers have 31961369Sdduvall * become available. 31971369Sdduvall * 31981369Sdduvall * the <factotum> is triggered if the h/w interrupt handler 31991369Sdduvall * sees the <link state changed> or <error> bits in the status 32001369Sdduvall * block. It's also triggered periodically to poll the link 32011369Sdduvall * state, just in case we aren't getting link status change 32021369Sdduvall * interrupts ... 32031369Sdduvall */ 32043334Sgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id, 32054588Sml149210 NULL, NULL, bge_send_drain, (caddr_t)bgep); 32061369Sdduvall if (err != DDI_SUCCESS) { 32071369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 32081369Sdduvall goto attach_fail; 32091369Sdduvall } 32101369Sdduvall bgep->progress |= PROGRESS_RESCHED; 32111369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 32124588Sml149210 NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 32131369Sdduvall if (err != DDI_SUCCESS) { 32141369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 32151369Sdduvall goto attach_fail; 32161369Sdduvall } 32171369Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 32181369Sdduvall 32191369Sdduvall /* Get supported interrupt types */ 32201369Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 32211369Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 32221369Sdduvall 32231369Sdduvall goto attach_fail; 32241369Sdduvall } 32251369Sdduvall 32262675Szh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x", 32274588Sml149210 bgep->ifname, intr_types)); 32281369Sdduvall 32291369Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 32301369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 32311369Sdduvall bge_error(bgep, "MSI registration failed, " 32321369Sdduvall "trying FIXED interrupt type\n"); 32331369Sdduvall } else { 32342675Szh199473 BGE_DEBUG(("%s: Using MSI interrupt type", 32354588Sml149210 bgep->ifname)); 32361369Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 32371865Sdilpreet bgep->progress |= PROGRESS_HWINT; 32381369Sdduvall } 32391369Sdduvall } 32401369Sdduvall 32411865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 32421369Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 32431369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 32441369Sdduvall bge_error(bgep, "FIXED interrupt " 32451369Sdduvall "registration failed\n"); 32461369Sdduvall goto attach_fail; 32471369Sdduvall } 32481369Sdduvall 32492675Szh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname)); 32501369Sdduvall 32511369Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 32521865Sdilpreet bgep->progress |= PROGRESS_HWINT; 32531369Sdduvall } 32541369Sdduvall 32551865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 32561369Sdduvall bge_error(bgep, "No interrupts registered\n"); 32571369Sdduvall goto attach_fail; 32581369Sdduvall } 32591369Sdduvall 32601369Sdduvall /* 32611369Sdduvall * Note that interrupts are not enabled yet as 32621865Sdilpreet * mutex locks are not initialized. Initialize mutex locks. 32631865Sdilpreet */ 32641865Sdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 32651865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32661865Sdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 32671865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32681865Sdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 32691865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32701865Sdilpreet 32711865Sdilpreet /* 32721865Sdilpreet * Initialize rings. 32731369Sdduvall */ 32741369Sdduvall bge_init_rings(bgep); 32751369Sdduvall 32761369Sdduvall /* 32771369Sdduvall * Now that mutex locks are initialized, enable interrupts. 32781369Sdduvall */ 32791865Sdilpreet bge_intr_enable(bgep); 32801865Sdilpreet bgep->progress |= PROGRESS_INTR; 32811369Sdduvall 32821369Sdduvall /* 32831369Sdduvall * Initialise link state variables 32841369Sdduvall * Stop, reset & reinitialise the chip. 32851369Sdduvall * Initialise the (internal) PHY. 32861369Sdduvall */ 32871369Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 32881369Sdduvall 32891369Sdduvall mutex_enter(bgep->genlock); 32901369Sdduvall 32911369Sdduvall /* 32921369Sdduvall * Reset chip & rings to initial state; also reset address 32931369Sdduvall * filtering, promiscuity, loopback mode. 32941369Sdduvall */ 32951408Srandyf #ifdef BGE_IPMI_ASF 32963918Sml149210 #ifdef BGE_NETCONSOLE 32973918Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 32983918Sml149210 #else 32991865Sdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 33003918Sml149210 #endif 33011408Srandyf #else 33021865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 33031408Srandyf #endif 33041865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 33051865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 33061865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33071865Sdilpreet mutex_exit(bgep->genlock); 33081865Sdilpreet goto attach_fail; 33091865Sdilpreet } 33101369Sdduvall 33112675Szh199473 #ifdef BGE_IPMI_ASF 33122675Szh199473 if (bgep->asf_enabled) { 33132675Szh199473 bgep->asf_status = ASF_STAT_RUN_INIT; 33142675Szh199473 } 33152675Szh199473 #endif 33162675Szh199473 33171369Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 33181369Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 33191369Sdduvall bgep->promisc = B_FALSE; 33201369Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 33211865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 33221865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33231865Sdilpreet mutex_exit(bgep->genlock); 33241865Sdilpreet goto attach_fail; 33251865Sdilpreet } 33261865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 33271865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33281865Sdilpreet mutex_exit(bgep->genlock); 33291865Sdilpreet goto attach_fail; 33301865Sdilpreet } 33311369Sdduvall 33321369Sdduvall mutex_exit(bgep->genlock); 33331369Sdduvall 33341865Sdilpreet if (bge_phys_init(bgep) == EIO) { 33351865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33361865Sdilpreet goto attach_fail; 33371865Sdilpreet } 33381369Sdduvall bgep->progress |= PROGRESS_PHY; 33391369Sdduvall 33401369Sdduvall /* 33416512Ssowmini * initialize NDD-tweakable parameters 33421369Sdduvall */ 33431369Sdduvall if (bge_nd_init(bgep)) { 33441369Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 33451369Sdduvall goto attach_fail; 33461369Sdduvall } 33471369Sdduvall bgep->progress |= PROGRESS_NDD; 33481369Sdduvall 33491369Sdduvall /* 33501369Sdduvall * Create & initialise named kstats 33511369Sdduvall */ 33521369Sdduvall bge_init_kstats(bgep, instance); 33531369Sdduvall bgep->progress |= PROGRESS_KSTATS; 33541369Sdduvall 33551369Sdduvall /* 33561369Sdduvall * Determine whether to override the chip's own MAC address 33571369Sdduvall */ 33581369Sdduvall bge_find_mac_address(bgep, cidp); 33592331Skrgopi ethaddr_copy(cidp->vendor_addr.addr, bgep->curr_addr[0].addr); 33602331Skrgopi bgep->curr_addr[0].set = B_TRUE; 33612331Skrgopi 33622406Skrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX; 33632406Skrgopi /* 33642406Skrgopi * Address available is one less than MAX 33652406Skrgopi * as primary address is not advertised 33662406Skrgopi * as a multiple MAC address. 33672406Skrgopi */ 33682331Skrgopi bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX - 1; 33691369Sdduvall 33702311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 33712311Sseb goto attach_fail; 33722311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 33732311Sseb macp->m_driver = bgep; 33741369Sdduvall macp->m_dip = devinfo; 33752331Skrgopi macp->m_src_addr = bgep->curr_addr[0].addr; 33762311Sseb macp->m_callbacks = &bge_m_callbacks; 33772311Sseb macp->m_min_sdu = 0; 33782311Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); 33795895Syz147064 macp->m_margin = VLAN_TAGSZ; 33806512Ssowmini macp->m_priv_props = bge_priv_prop; 33816512Ssowmini macp->m_priv_prop_count = BGE_MAX_PRIV_PROPS; 33826512Ssowmini 33831369Sdduvall /* 33841369Sdduvall * Finally, we're ready to register ourselves with the MAC layer 33851369Sdduvall * interface; if this succeeds, we're all ready to start() 33861369Sdduvall */ 33872311Sseb err = mac_register(macp, &bgep->mh); 33882311Sseb mac_free(macp); 33892311Sseb if (err != 0) 33901369Sdduvall goto attach_fail; 33911369Sdduvall 33925107Seota /* 33935107Seota * Register a periodical handler. 33945107Seota * bge_chip_cyclic() is invoked in kernel context. 33955107Seota */ 33965107Seota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep, 33975107Seota BGE_CYCLIC_PERIOD, DDI_IPL_0); 33981369Sdduvall 33991369Sdduvall bgep->progress |= PROGRESS_READY; 34001369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 34013918Sml149210 #ifdef BGE_IPMI_ASF 34023918Sml149210 #ifdef BGE_NETCONSOLE 34033918Sml149210 if (bgep->asf_enabled) { 34043918Sml149210 mutex_enter(bgep->genlock); 34053918Sml149210 retval = bge_chip_start(bgep, B_TRUE); 34063918Sml149210 mutex_exit(bgep->genlock); 34073918Sml149210 if (retval != DDI_SUCCESS) 34083918Sml149210 goto attach_fail; 34093918Sml149210 } 34103918Sml149210 #endif 34113918Sml149210 #endif 34121369Sdduvall return (DDI_SUCCESS); 34131369Sdduvall 34141369Sdduvall attach_fail: 34151408Srandyf #ifdef BGE_IPMI_ASF 34162675Szh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN); 34171408Srandyf #else 34181369Sdduvall bge_unattach(bgep); 34191408Srandyf #endif 34201369Sdduvall return (DDI_FAILURE); 34211369Sdduvall } 34221369Sdduvall 34231369Sdduvall /* 34241369Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 34251369Sdduvall */ 34261369Sdduvall static int 34271369Sdduvall bge_suspend(bge_t *bgep) 34281369Sdduvall { 34291369Sdduvall /* 34301369Sdduvall * Stop processing and idle (powerdown) the PHY ... 34311369Sdduvall */ 34321369Sdduvall mutex_enter(bgep->genlock); 34331408Srandyf #ifdef BGE_IPMI_ASF 34341408Srandyf /* 34351408Srandyf * Power management hasn't been supported in BGE now. If you 34361408Srandyf * want to implement it, please add the ASF/IPMI related 34371408Srandyf * code here. 34381408Srandyf */ 34391408Srandyf #endif 34401369Sdduvall bge_stop(bgep); 34411865Sdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 34421865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 34431865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 34441865Sdilpreet mutex_exit(bgep->genlock); 34451865Sdilpreet return (DDI_FAILURE); 34461865Sdilpreet } 34471865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 34481865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 34491865Sdilpreet mutex_exit(bgep->genlock); 34501865Sdilpreet return (DDI_FAILURE); 34511865Sdilpreet } 34521369Sdduvall mutex_exit(bgep->genlock); 34531369Sdduvall 34541369Sdduvall return (DDI_SUCCESS); 34551369Sdduvall } 34561369Sdduvall 34571369Sdduvall /* 34581369Sdduvall * detach(9E) -- Detach a device from the system 34591369Sdduvall */ 34601369Sdduvall static int 34611369Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 34621369Sdduvall { 34631369Sdduvall bge_t *bgep; 34641408Srandyf #ifdef BGE_IPMI_ASF 34651408Srandyf uint_t asf_mode; 34661408Srandyf asf_mode = ASF_MODE_NONE; 34671408Srandyf #endif 34681369Sdduvall 34691369Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 34701369Sdduvall 34711369Sdduvall bgep = ddi_get_driver_private(devinfo); 34721369Sdduvall 34731369Sdduvall switch (cmd) { 34741369Sdduvall default: 34751369Sdduvall return (DDI_FAILURE); 34761369Sdduvall 34771369Sdduvall case DDI_SUSPEND: 34781369Sdduvall return (bge_suspend(bgep)); 34791369Sdduvall 34801369Sdduvall case DDI_DETACH: 34811369Sdduvall break; 34821369Sdduvall } 34831369Sdduvall 34841408Srandyf #ifdef BGE_IPMI_ASF 34851408Srandyf mutex_enter(bgep->genlock); 34862675Szh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) || 34874588Sml149210 (bgep->asf_status == ASF_STAT_RUN_INIT))) { 34881408Srandyf 34891408Srandyf bge_asf_update_status(bgep); 34902675Szh199473 if (bgep->asf_status == ASF_STAT_RUN) { 34912675Szh199473 bge_asf_stop_timer(bgep); 34922675Szh199473 } 34931408Srandyf bgep->asf_status = ASF_STAT_STOP; 34941408Srandyf 34951408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 34961408Srandyf 34971408Srandyf if (bgep->asf_pseudostop) { 34981408Srandyf bge_chip_stop(bgep, B_FALSE); 34991408Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 35001408Srandyf bgep->asf_pseudostop = B_FALSE; 35011408Srandyf } 35021408Srandyf 35031408Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 35041865Sdilpreet 35051865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 35061865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 35071865Sdilpreet DDI_SERVICE_UNAFFECTED); 35081865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 35091865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 35101865Sdilpreet DDI_SERVICE_UNAFFECTED); 35111408Srandyf } 35121408Srandyf mutex_exit(bgep->genlock); 35131408Srandyf #endif 35141408Srandyf 35151369Sdduvall /* 35161369Sdduvall * Unregister from the GLD subsystem. This can fail, in 35171369Sdduvall * particular if there are DLPI style-2 streams still open - 35181369Sdduvall * in which case we just return failure without shutting 35191369Sdduvall * down chip operations. 35201369Sdduvall */ 35212311Sseb if (mac_unregister(bgep->mh) != 0) 35221369Sdduvall return (DDI_FAILURE); 35231369Sdduvall 35241369Sdduvall /* 35251369Sdduvall * All activity stopped, so we can clean up & exit 35261369Sdduvall */ 35271408Srandyf #ifdef BGE_IPMI_ASF 35281408Srandyf bge_unattach(bgep, asf_mode); 35291408Srandyf #else 35301369Sdduvall bge_unattach(bgep); 35311408Srandyf #endif 35321369Sdduvall return (DDI_SUCCESS); 35331369Sdduvall } 35341369Sdduvall 35351369Sdduvall 35361369Sdduvall /* 35371369Sdduvall * ========== Module Loading Data & Entry Points ========== 35381369Sdduvall */ 35391369Sdduvall 35401369Sdduvall #undef BGE_DBG 35411369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 35421369Sdduvall 35431369Sdduvall DDI_DEFINE_STREAM_OPS(bge_dev_ops, nulldev, nulldev, bge_attach, bge_detach, 35441369Sdduvall nodev, NULL, D_MP, NULL); 35451369Sdduvall 35461369Sdduvall static struct modldrv bge_modldrv = { 35471369Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 35481369Sdduvall bge_ident, /* short description */ 35491369Sdduvall &bge_dev_ops /* driver specific ops */ 35501369Sdduvall }; 35511369Sdduvall 35521369Sdduvall static struct modlinkage modlinkage = { 35531369Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 35541369Sdduvall }; 35551369Sdduvall 35561369Sdduvall 35571369Sdduvall int 35581369Sdduvall _info(struct modinfo *modinfop) 35591369Sdduvall { 35601369Sdduvall return (mod_info(&modlinkage, modinfop)); 35611369Sdduvall } 35621369Sdduvall 35631369Sdduvall int 35641369Sdduvall _init(void) 35651369Sdduvall { 35661369Sdduvall int status; 35671369Sdduvall 35681369Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 35691369Sdduvall status = mod_install(&modlinkage); 35701369Sdduvall if (status == DDI_SUCCESS) 35711369Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 35721369Sdduvall else 35731369Sdduvall mac_fini_ops(&bge_dev_ops); 35741369Sdduvall return (status); 35751369Sdduvall } 35761369Sdduvall 35771369Sdduvall int 35781369Sdduvall _fini(void) 35791369Sdduvall { 35801369Sdduvall int status; 35811369Sdduvall 35821369Sdduvall status = mod_remove(&modlinkage); 35831369Sdduvall if (status == DDI_SUCCESS) { 35841369Sdduvall mac_fini_ops(&bge_dev_ops); 35851369Sdduvall mutex_destroy(bge_log_mutex); 35861369Sdduvall } 35871369Sdduvall return (status); 35881369Sdduvall } 35891369Sdduvall 35901369Sdduvall 35911369Sdduvall /* 35921369Sdduvall * bge_add_intrs: 35931369Sdduvall * 35941369Sdduvall * Register FIXED or MSI interrupts. 35951369Sdduvall */ 35961369Sdduvall static int 35971369Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 35981369Sdduvall { 35991369Sdduvall dev_info_t *dip = bgep->devinfo; 36001369Sdduvall int avail, actual, intr_size, count = 0; 36011369Sdduvall int i, flag, ret; 36021369Sdduvall 36032675Szh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type)); 36041369Sdduvall 36051369Sdduvall /* Get number of interrupts */ 36061369Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 36071369Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 36081369Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 36091369Sdduvall "count: %d", ret, count); 36101369Sdduvall 36111369Sdduvall return (DDI_FAILURE); 36121369Sdduvall } 36131369Sdduvall 36141369Sdduvall /* Get number of available interrupts */ 36151369Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 36161369Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 36171369Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 36181369Sdduvall "ret: %d, avail: %d\n", ret, avail); 36191369Sdduvall 36201369Sdduvall return (DDI_FAILURE); 36211369Sdduvall } 36221369Sdduvall 36231369Sdduvall if (avail < count) { 36242675Szh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d", 36252675Szh199473 bgep->ifname, count, avail)); 36261369Sdduvall } 36271369Sdduvall 36281369Sdduvall /* 36291369Sdduvall * BGE hardware generates only single MSI even though it claims 36301369Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 36311369Sdduvall */ 36321369Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 36331369Sdduvall count = 1; 36341369Sdduvall flag = DDI_INTR_ALLOC_STRICT; 36351369Sdduvall } else { 36361369Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 36371369Sdduvall } 36381369Sdduvall 36391369Sdduvall /* Allocate an array of interrupt handles */ 36401369Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 36411369Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 36421369Sdduvall 36431369Sdduvall /* Call ddi_intr_alloc() */ 36441369Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 36451369Sdduvall count, &actual, flag); 36461369Sdduvall 36471369Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 36481369Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 36491369Sdduvall 36501369Sdduvall kmem_free(bgep->htable, intr_size); 36511369Sdduvall return (DDI_FAILURE); 36521369Sdduvall } 36531369Sdduvall 36541369Sdduvall if (actual < count) { 36552675Szh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d", 36564588Sml149210 bgep->ifname, count, actual)); 36571369Sdduvall } 36581369Sdduvall 36591369Sdduvall bgep->intr_cnt = actual; 36601369Sdduvall 36611369Sdduvall /* 36621369Sdduvall * Get priority for first msi, assume remaining are all the same 36631369Sdduvall */ 36641369Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 36651369Sdduvall DDI_SUCCESS) { 36661369Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 36671369Sdduvall 36681369Sdduvall /* Free already allocated intr */ 36691369Sdduvall for (i = 0; i < actual; i++) { 36701369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 36711369Sdduvall } 36721369Sdduvall 36731369Sdduvall kmem_free(bgep->htable, intr_size); 36741369Sdduvall return (DDI_FAILURE); 36751369Sdduvall } 36761369Sdduvall 36771369Sdduvall /* Call ddi_intr_add_handler() */ 36781369Sdduvall for (i = 0; i < actual; i++) { 36791369Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 36801369Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 36811369Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 36821369Sdduvall "failed %d\n", ret); 36831369Sdduvall 36841369Sdduvall /* Free already allocated intr */ 36851369Sdduvall for (i = 0; i < actual; i++) { 36861369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 36871369Sdduvall } 36881369Sdduvall 36891369Sdduvall kmem_free(bgep->htable, intr_size); 36901369Sdduvall return (DDI_FAILURE); 36911369Sdduvall } 36921369Sdduvall } 36931369Sdduvall 36941369Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 36954588Sml149210 != DDI_SUCCESS) { 36961369Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 36971369Sdduvall 36981369Sdduvall for (i = 0; i < actual; i++) { 36991369Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 37001369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 37011369Sdduvall } 37021369Sdduvall 37031369Sdduvall kmem_free(bgep->htable, intr_size); 37041369Sdduvall return (DDI_FAILURE); 37051369Sdduvall } 37061369Sdduvall 37071369Sdduvall return (DDI_SUCCESS); 37081369Sdduvall } 37091369Sdduvall 37101369Sdduvall /* 37111369Sdduvall * bge_rem_intrs: 37121369Sdduvall * 37131369Sdduvall * Unregister FIXED or MSI interrupts 37141369Sdduvall */ 37151369Sdduvall static void 37161369Sdduvall bge_rem_intrs(bge_t *bgep) 37171369Sdduvall { 37181369Sdduvall int i; 37191369Sdduvall 37202675Szh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep)); 37211369Sdduvall 37221865Sdilpreet /* Call ddi_intr_remove_handler() */ 37231865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 37241865Sdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 37251865Sdilpreet (void) ddi_intr_free(bgep->htable[i]); 37261865Sdilpreet } 37271865Sdilpreet 37281865Sdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 37291865Sdilpreet } 37301865Sdilpreet 37311865Sdilpreet 37321865Sdilpreet void 37331865Sdilpreet bge_intr_enable(bge_t *bgep) 37341865Sdilpreet { 37351865Sdilpreet int i; 37361865Sdilpreet 37371865Sdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 37381865Sdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 37391865Sdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 37401865Sdilpreet } else { 37411865Sdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 37421865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 37431865Sdilpreet (void) ddi_intr_enable(bgep->htable[i]); 37441865Sdilpreet } 37451865Sdilpreet } 37461865Sdilpreet } 37471865Sdilpreet 37481865Sdilpreet 37491865Sdilpreet void 37501865Sdilpreet bge_intr_disable(bge_t *bgep) 37511865Sdilpreet { 37521865Sdilpreet int i; 37531865Sdilpreet 37541369Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 37551369Sdduvall /* Call ddi_intr_block_disable() */ 37561369Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 37571369Sdduvall } else { 37581369Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 37591369Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 37601369Sdduvall } 37611369Sdduvall } 37621369Sdduvall } 37635903Ssowmini 37645903Ssowmini int 37655903Ssowmini bge_reprogram(bge_t *bgep) 37665903Ssowmini { 37675903Ssowmini int status = 0; 37685903Ssowmini 37695903Ssowmini ASSERT(mutex_owned(bgep->genlock)); 37705903Ssowmini 37715903Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) { 37725903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 37735903Ssowmini status = IOC_INVAL; 37745903Ssowmini } 37755903Ssowmini #ifdef BGE_IPMI_ASF 37765903Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 37775903Ssowmini #else 37785903Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) { 37795903Ssowmini #endif 37805903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 37815903Ssowmini status = IOC_INVAL; 37825903Ssowmini } 37835903Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI) 37845903Ssowmini bge_chip_msi_trig(bgep); 37855903Ssowmini return (status); 37865903Ssowmini } 3787