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 /* 238922SYong.Tan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 272675Szh199473 #include "bge_impl.h" 281369Sdduvall #include <sys/sdt.h> 298275SEric Cheng #include <sys/mac_provider.h> 306789Sam223141 #include <sys/mac.h> 318275SEric Cheng #include <sys/mac_flow.h> 321369Sdduvall 331369Sdduvall /* 341369Sdduvall * This is the string displayed by modinfo, etc. 358922SYong.Tan@Sun.COM */ 368922SYong.Tan@Sun.COM static char bge_ident[] = "Broadcom Gb Ethernet"; 378922SYong.Tan@Sun.COM /* 381369Sdduvall * Make sure you keep the version ID up to date! 391369Sdduvall */ 40*9514SGirish.Moodalbail@Sun.COM static char bge_version[] = "Broadcom Gb Ethernet v1.05"; 411369Sdduvall 421369Sdduvall /* 431369Sdduvall * Property names 441369Sdduvall */ 451369Sdduvall static char debug_propname[] = "bge-debug-flags"; 461369Sdduvall static char clsize_propname[] = "cache-line-size"; 471369Sdduvall static char latency_propname[] = "latency-timer"; 481369Sdduvall static char localmac_boolname[] = "local-mac-address?"; 491369Sdduvall static char localmac_propname[] = "local-mac-address"; 501369Sdduvall static char macaddr_propname[] = "mac-address"; 511369Sdduvall static char subdev_propname[] = "subsystem-id"; 521369Sdduvall static char subven_propname[] = "subsystem-vendor-id"; 531369Sdduvall static char rxrings_propname[] = "bge-rx-rings"; 541369Sdduvall static char txrings_propname[] = "bge-tx-rings"; 551865Sdilpreet static char fm_cap[] = "fm-capable"; 561908Sly149593 static char default_mtu[] = "default_mtu"; 571369Sdduvall 581369Sdduvall static int bge_add_intrs(bge_t *, int); 591369Sdduvall static void bge_rem_intrs(bge_t *); 608275SEric Cheng static int bge_unicst_set(void *, const uint8_t *, int); 611369Sdduvall 621369Sdduvall /* 631369Sdduvall * Describes the chip's DMA engine 641369Sdduvall */ 651369Sdduvall static ddi_dma_attr_t dma_attr = { 661369Sdduvall DMA_ATTR_V0, /* dma_attr version */ 671369Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */ 681369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 691369Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 701369Sdduvall 0x0000000000000001ull, /* dma_attr_align */ 711369Sdduvall 0x00000FFF, /* dma_attr_burstsizes */ 721369Sdduvall 0x00000001, /* dma_attr_minxfer */ 731369Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */ 741369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 751369Sdduvall 1, /* dma_attr_sgllen */ 761369Sdduvall 0x00000001, /* dma_attr_granular */ 771865Sdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */ 781369Sdduvall }; 791369Sdduvall 801369Sdduvall /* 811369Sdduvall * PIO access attributes for registers 821369Sdduvall */ 831369Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = { 841369Sdduvall DDI_DEVICE_ATTR_V0, 851369Sdduvall DDI_NEVERSWAP_ACC, 861865Sdilpreet DDI_STRICTORDER_ACC, 871865Sdilpreet DDI_FLAGERR_ACC 881369Sdduvall }; 891369Sdduvall 901369Sdduvall /* 911369Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped. 921369Sdduvall */ 931369Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = { 941369Sdduvall DDI_DEVICE_ATTR_V0, 951369Sdduvall DDI_NEVERSWAP_ACC, 961865Sdilpreet DDI_STRICTORDER_ACC, 971865Sdilpreet DDI_FLAGERR_ACC 981369Sdduvall }; 991369Sdduvall 1001369Sdduvall /* 1011369Sdduvall * DMA access attributes for data: NOT to be byte swapped. 1021369Sdduvall */ 1031369Sdduvall static ddi_device_acc_attr_t bge_data_accattr = { 1041369Sdduvall DDI_DEVICE_ATTR_V0, 1051369Sdduvall DDI_NEVERSWAP_ACC, 1061369Sdduvall DDI_STRICTORDER_ACC 1071369Sdduvall }; 1081369Sdduvall 1092311Sseb static int bge_m_start(void *); 1102311Sseb static void bge_m_stop(void *); 1112311Sseb static int bge_m_promisc(void *, boolean_t); 1122311Sseb static int bge_m_multicst(void *, boolean_t, const uint8_t *); 1132311Sseb static void bge_m_ioctl(void *, queue_t *, mblk_t *); 1142311Sseb static boolean_t bge_m_getcapab(void *, mac_capab_t, void *); 1152331Skrgopi static int bge_unicst_set(void *, const uint8_t *, 1168275SEric Cheng int); 1175903Ssowmini static int bge_m_setprop(void *, const char *, mac_prop_id_t, 1185903Ssowmini uint_t, const void *); 1195903Ssowmini static int bge_m_getprop(void *, const char *, mac_prop_id_t, 1208118SVasumathi.Sundaram@Sun.COM uint_t, uint_t, void *, uint_t *); 1215903Ssowmini static int bge_set_priv_prop(bge_t *, const char *, uint_t, 1225903Ssowmini const void *); 1235903Ssowmini static int bge_get_priv_prop(bge_t *, const char *, uint_t, 1246512Ssowmini uint_t, void *); 1255903Ssowmini 1268275SEric Cheng #define BGE_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1272311Sseb 1282311Sseb static mac_callbacks_t bge_m_callbacks = { 1292311Sseb BGE_M_CALLBACK_FLAGS, 1302311Sseb bge_m_stat, 1312311Sseb bge_m_start, 1322311Sseb bge_m_stop, 1332311Sseb bge_m_promisc, 1342311Sseb bge_m_multicst, 1358275SEric Cheng NULL, 1362311Sseb bge_m_tx, 1372311Sseb bge_m_ioctl, 1385903Ssowmini bge_m_getcapab, 1395903Ssowmini NULL, 1405903Ssowmini NULL, 1415903Ssowmini bge_m_setprop, 1425903Ssowmini bge_m_getprop 1432311Sseb }; 1442311Sseb 1456512Ssowmini mac_priv_prop_t bge_priv_prop[] = { 1466512Ssowmini {"_adv_asym_pause_cap", MAC_PROP_PERM_RW}, 1476512Ssowmini {"_adv_pause_cap", MAC_PROP_PERM_RW} 1486512Ssowmini }; 1496512Ssowmini 1506512Ssowmini #define BGE_MAX_PRIV_PROPS \ 1516512Ssowmini (sizeof (bge_priv_prop) / sizeof (mac_priv_prop_t)) 1526512Ssowmini 1538275SEric Cheng uint8_t zero_addr[6] = {0, 0, 0, 0, 0, 0}; 1541369Sdduvall /* 1551369Sdduvall * ========== Transmit and receive ring reinitialisation ========== 1561369Sdduvall */ 1571369Sdduvall 1581369Sdduvall /* 1591369Sdduvall * These <reinit> routines each reset the specified ring to an initial 1601369Sdduvall * state, assuming that the corresponding <init> routine has already 1611369Sdduvall * been called exactly once. 1621369Sdduvall */ 1631369Sdduvall 1641369Sdduvall static void 1651369Sdduvall bge_reinit_send_ring(send_ring_t *srp) 1661369Sdduvall { 1673334Sgs150176 bge_queue_t *txbuf_queue; 1683334Sgs150176 bge_queue_item_t *txbuf_head; 1693334Sgs150176 sw_txbuf_t *txbuf; 1703334Sgs150176 sw_sbd_t *ssbdp; 1713334Sgs150176 uint32_t slot; 1723334Sgs150176 1731369Sdduvall /* 1741369Sdduvall * Reinitialise control variables ... 1751369Sdduvall */ 1763334Sgs150176 srp->tx_flow = 0; 1771369Sdduvall srp->tx_next = 0; 1783334Sgs150176 srp->txfill_next = 0; 1791369Sdduvall srp->tx_free = srp->desc.nslots; 1801369Sdduvall ASSERT(mutex_owned(srp->tc_lock)); 1811369Sdduvall srp->tc_next = 0; 1823334Sgs150176 srp->txpkt_next = 0; 1833334Sgs150176 srp->tx_block = 0; 1843334Sgs150176 srp->tx_nobd = 0; 1853334Sgs150176 srp->tx_nobuf = 0; 1863334Sgs150176 1873334Sgs150176 /* 1883334Sgs150176 * Initialize the tx buffer push queue 1893334Sgs150176 */ 1903334Sgs150176 mutex_enter(srp->freetxbuf_lock); 1913334Sgs150176 mutex_enter(srp->txbuf_lock); 1923334Sgs150176 txbuf_queue = &srp->freetxbuf_queue; 1933334Sgs150176 txbuf_queue->head = NULL; 1943334Sgs150176 txbuf_queue->count = 0; 1953334Sgs150176 txbuf_queue->lock = srp->freetxbuf_lock; 1963334Sgs150176 srp->txbuf_push_queue = txbuf_queue; 1973334Sgs150176 1983334Sgs150176 /* 1993334Sgs150176 * Initialize the tx buffer pop queue 2003334Sgs150176 */ 2013334Sgs150176 txbuf_queue = &srp->txbuf_queue; 2023334Sgs150176 txbuf_queue->head = NULL; 2033334Sgs150176 txbuf_queue->count = 0; 2043334Sgs150176 txbuf_queue->lock = srp->txbuf_lock; 2053334Sgs150176 srp->txbuf_pop_queue = txbuf_queue; 2063334Sgs150176 txbuf_head = srp->txbuf_head; 2073334Sgs150176 txbuf = srp->txbuf; 2083334Sgs150176 for (slot = 0; slot < srp->tx_buffers; ++slot) { 2093334Sgs150176 txbuf_head->item = txbuf; 2103334Sgs150176 txbuf_head->next = txbuf_queue->head; 2113334Sgs150176 txbuf_queue->head = txbuf_head; 2123334Sgs150176 txbuf_queue->count++; 2133334Sgs150176 txbuf++; 2143334Sgs150176 txbuf_head++; 2153334Sgs150176 } 2163334Sgs150176 mutex_exit(srp->txbuf_lock); 2173334Sgs150176 mutex_exit(srp->freetxbuf_lock); 2181369Sdduvall 2191369Sdduvall /* 2201369Sdduvall * Zero and sync all the h/w Send Buffer Descriptors 2211369Sdduvall */ 2221369Sdduvall DMA_ZERO(srp->desc); 2231369Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 2243334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 2253334Sgs150176 ssbdp = srp->sw_sbds; 2263334Sgs150176 for (slot = 0; slot < srp->desc.nslots; ++ssbdp, ++slot) 2273334Sgs150176 ssbdp->pbuf = NULL; 2281369Sdduvall } 2291369Sdduvall 2301369Sdduvall static void 2311369Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp) 2321369Sdduvall { 2331369Sdduvall /* 2341369Sdduvall * Reinitialise control variables ... 2351369Sdduvall */ 2361369Sdduvall rrp->rx_next = 0; 2371369Sdduvall } 2381369Sdduvall 2391369Sdduvall static void 2403334Sgs150176 bge_reinit_buff_ring(buff_ring_t *brp, uint32_t ring) 2411369Sdduvall { 2421369Sdduvall bge_rbd_t *hw_rbd_p; 2431369Sdduvall sw_rbd_t *srbdp; 2441369Sdduvall uint32_t bufsize; 2451369Sdduvall uint32_t nslots; 2461369Sdduvall uint32_t slot; 2471369Sdduvall 2481369Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = { 2491369Sdduvall RBD_FLAG_STD_RING, 2501369Sdduvall RBD_FLAG_JUMBO_RING, 2511369Sdduvall RBD_FLAG_MINI_RING 2521369Sdduvall }; 2531369Sdduvall 2541369Sdduvall /* 2551369Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors 2561369Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>, 2571369Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>) 2581369Sdduvall * should be zeroed, and so don't need to be set up specifically 2591369Sdduvall * once the whole area has been cleared. 2601369Sdduvall */ 2611369Sdduvall DMA_ZERO(brp->desc); 2621369Sdduvall 2631369Sdduvall hw_rbd_p = DMA_VPTR(brp->desc); 2641369Sdduvall nslots = brp->desc.nslots; 2651369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 2661369Sdduvall bufsize = brp->buf[0].size; 2671369Sdduvall srbdp = brp->sw_rbds; 2681369Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) { 2691369Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress; 2707099Syt223700 hw_rbd_p->index = (uint16_t)slot; 2717099Syt223700 hw_rbd_p->len = (uint16_t)bufsize; 2721369Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token; 2731369Sdduvall hw_rbd_p->flags |= ring_type_flag[ring]; 2741369Sdduvall } 2751369Sdduvall 2761369Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV); 2771369Sdduvall 2781369Sdduvall /* 2791369Sdduvall * Finally, reinitialise the ring control variables ... 2801369Sdduvall */ 2811369Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0; 2821369Sdduvall } 2831369Sdduvall 2841369Sdduvall /* 2851369Sdduvall * Reinitialize all rings 2861369Sdduvall */ 2871369Sdduvall static void 2881369Sdduvall bge_reinit_rings(bge_t *bgep) 2891369Sdduvall { 2903334Sgs150176 uint32_t ring; 2911369Sdduvall 2921369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 2931369Sdduvall 2941369Sdduvall /* 2951369Sdduvall * Send Rings ... 2961369Sdduvall */ 2971369Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) 2981369Sdduvall bge_reinit_send_ring(&bgep->send[ring]); 2991369Sdduvall 3001369Sdduvall /* 3011369Sdduvall * Receive Return Rings ... 3021369Sdduvall */ 3031369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring) 3041369Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]); 3051369Sdduvall 3061369Sdduvall /* 3071369Sdduvall * Receive Producer Rings ... 3081369Sdduvall */ 3091369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 3101369Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring); 3111369Sdduvall } 3121369Sdduvall 3131369Sdduvall /* 3141369Sdduvall * ========== Internal state management entry points ========== 3151369Sdduvall */ 3161369Sdduvall 3171369Sdduvall #undef BGE_DBG 3181369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 3191369Sdduvall 3201369Sdduvall /* 3211369Sdduvall * These routines provide all the functionality required by the 3221369Sdduvall * corresponding GLD entry points, but don't update the GLD state 3231369Sdduvall * so they can be called internally without disturbing our record 3241369Sdduvall * of what GLD thinks we should be doing ... 3251369Sdduvall */ 3261369Sdduvall 3271369Sdduvall /* 3281369Sdduvall * bge_reset() -- reset h/w & rings to initial state 3291369Sdduvall */ 3301865Sdilpreet static int 3311408Srandyf #ifdef BGE_IPMI_ASF 3321408Srandyf bge_reset(bge_t *bgep, uint_t asf_mode) 3331408Srandyf #else 3341369Sdduvall bge_reset(bge_t *bgep) 3351408Srandyf #endif 3361369Sdduvall { 3373334Sgs150176 uint32_t ring; 3381865Sdilpreet int retval; 3391369Sdduvall 3401369Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep)); 3411369Sdduvall 3421369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3431369Sdduvall 3441369Sdduvall /* 3451369Sdduvall * Grab all the other mutexes in the world (this should 3461369Sdduvall * ensure no other threads are manipulating driver state) 3471369Sdduvall */ 3481369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 3491369Sdduvall mutex_enter(bgep->recv[ring].rx_lock); 3501369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 3511369Sdduvall mutex_enter(bgep->buff[ring].rf_lock); 3521369Sdduvall rw_enter(bgep->errlock, RW_WRITER); 3531369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3543334Sgs150176 mutex_enter(bgep->send[ring].tx_lock); 3553334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3561369Sdduvall mutex_enter(bgep->send[ring].tc_lock); 3571369Sdduvall 3581408Srandyf #ifdef BGE_IPMI_ASF 3591865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode); 3601408Srandyf #else 3611865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE); 3621408Srandyf #endif 3631369Sdduvall bge_reinit_rings(bgep); 3641369Sdduvall 3651369Sdduvall /* 3661369Sdduvall * Free the world ... 3671369Sdduvall */ 3681369Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; ) 3691369Sdduvall mutex_exit(bgep->send[ring].tc_lock); 3703334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3713334Sgs150176 mutex_exit(bgep->send[ring].tx_lock); 3721369Sdduvall rw_exit(bgep->errlock); 3731369Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; ) 3741369Sdduvall mutex_exit(bgep->buff[ring].rf_lock); 3751369Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; ) 3761369Sdduvall mutex_exit(bgep->recv[ring].rx_lock); 3771369Sdduvall 3781369Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep)); 3791865Sdilpreet return (retval); 3801369Sdduvall } 3811369Sdduvall 3821369Sdduvall /* 3831369Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings 3841369Sdduvall */ 3851369Sdduvall static void 3861369Sdduvall bge_stop(bge_t *bgep) 3871369Sdduvall { 3881369Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep)); 3891369Sdduvall 3901369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3911369Sdduvall 3921408Srandyf #ifdef BGE_IPMI_ASF 3931408Srandyf if (bgep->asf_enabled) { 3941408Srandyf bgep->asf_pseudostop = B_TRUE; 3951408Srandyf } else { 3961408Srandyf #endif 3971408Srandyf bge_chip_stop(bgep, B_FALSE); 3981408Srandyf #ifdef BGE_IPMI_ASF 3991408Srandyf } 4001408Srandyf #endif 4011369Sdduvall 4021369Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep)); 4031369Sdduvall } 4041369Sdduvall 4051369Sdduvall /* 4061369Sdduvall * bge_start() -- start transmitting/receiving 4071369Sdduvall */ 4081865Sdilpreet static int 4091369Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys) 4101369Sdduvall { 4111865Sdilpreet int retval; 4121865Sdilpreet 4131369Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys)); 4141369Sdduvall 4151369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4161369Sdduvall 4171369Sdduvall /* 4181369Sdduvall * Start chip processing, including enabling interrupts 4191369Sdduvall */ 4201865Sdilpreet retval = bge_chip_start(bgep, reset_phys); 4211369Sdduvall 4221369Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys)); 4231865Sdilpreet return (retval); 4241369Sdduvall } 4251369Sdduvall 4261369Sdduvall /* 4271369Sdduvall * bge_restart - restart transmitting/receiving after error or suspend 4281369Sdduvall */ 4291865Sdilpreet int 4301369Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys) 4311369Sdduvall { 4321865Sdilpreet int retval = DDI_SUCCESS; 4331369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4341369Sdduvall 4351408Srandyf #ifdef BGE_IPMI_ASF 4361408Srandyf if (bgep->asf_enabled) { 4371865Sdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS) 4381865Sdilpreet retval = DDI_FAILURE; 4391408Srandyf } else 4401865Sdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS) 4411865Sdilpreet retval = DDI_FAILURE; 4421408Srandyf #else 4431865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) 4441865Sdilpreet retval = DDI_FAILURE; 4451408Srandyf #endif 4463440Szh199473 if (bgep->bge_mac_state == BGE_MAC_STARTED) { 4471865Sdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS) 4481865Sdilpreet retval = DDI_FAILURE; 4491369Sdduvall bgep->watchdog = 0; 4503334Sgs150176 ddi_trigger_softintr(bgep->drain_id); 4511369Sdduvall } 4521369Sdduvall 4531369Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys)); 4541865Sdilpreet return (retval); 4551369Sdduvall } 4561369Sdduvall 4571369Sdduvall 4581369Sdduvall /* 4591369Sdduvall * ========== Nemo-required management entry points ========== 4601369Sdduvall */ 4611369Sdduvall 4621369Sdduvall #undef BGE_DBG 4631369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 4641369Sdduvall 4651369Sdduvall /* 4661369Sdduvall * bge_m_stop() -- stop transmitting/receiving 4671369Sdduvall */ 4681369Sdduvall static void 4691369Sdduvall bge_m_stop(void *arg) 4701369Sdduvall { 4711369Sdduvall bge_t *bgep = arg; /* private device info */ 4723334Sgs150176 send_ring_t *srp; 4733334Sgs150176 uint32_t ring; 4741369Sdduvall 4751369Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg)); 4761369Sdduvall 4771369Sdduvall /* 4781369Sdduvall * Just stop processing, then record new GLD state 4791369Sdduvall */ 4801369Sdduvall mutex_enter(bgep->genlock); 4811865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 4821865Sdilpreet /* can happen during autorecovery */ 4838922SYong.Tan@Sun.COM bgep->bge_chip_state = BGE_CHIP_STOPPED; 4848922SYong.Tan@Sun.COM } else 4858922SYong.Tan@Sun.COM bge_stop(bgep); 4866546Sgh162552 4876546Sgh162552 bgep->link_update_timer = 0; 4886546Sgh162552 bgep->link_state = LINK_STATE_UNKNOWN; 4896546Sgh162552 mac_link_update(bgep->mh, bgep->link_state); 4906546Sgh162552 4913334Sgs150176 /* 4923334Sgs150176 * Free the possible tx buffers allocated in tx process. 4933334Sgs150176 */ 4943334Sgs150176 #ifdef BGE_IPMI_ASF 4953334Sgs150176 if (!bgep->asf_pseudostop) 4963334Sgs150176 #endif 4973334Sgs150176 { 4983334Sgs150176 rw_enter(bgep->errlock, RW_WRITER); 4993334Sgs150176 for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) { 5003334Sgs150176 srp = &bgep->send[ring]; 5013334Sgs150176 mutex_enter(srp->tx_lock); 5023334Sgs150176 if (srp->tx_array > 1) 5033334Sgs150176 bge_free_txbuf_arrays(srp); 5043334Sgs150176 mutex_exit(srp->tx_lock); 5053334Sgs150176 } 5063334Sgs150176 rw_exit(bgep->errlock); 5073334Sgs150176 } 5081369Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED; 5091369Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg)); 5101865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 5111865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 5121369Sdduvall mutex_exit(bgep->genlock); 5131369Sdduvall } 5141369Sdduvall 5151369Sdduvall /* 5161369Sdduvall * bge_m_start() -- start transmitting/receiving 5171369Sdduvall */ 5181369Sdduvall static int 5191369Sdduvall bge_m_start(void *arg) 5201369Sdduvall { 5211369Sdduvall bge_t *bgep = arg; /* private device info */ 5221369Sdduvall 5231369Sdduvall BGE_TRACE(("bge_m_start($%p)", arg)); 5241369Sdduvall 5251369Sdduvall /* 5261369Sdduvall * Start processing and record new GLD state 5271369Sdduvall */ 5281369Sdduvall mutex_enter(bgep->genlock); 5291865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 5301865Sdilpreet /* can happen during autorecovery */ 5311865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5321865Sdilpreet mutex_exit(bgep->genlock); 5331865Sdilpreet return (EIO); 5341865Sdilpreet } 5351408Srandyf #ifdef BGE_IPMI_ASF 5361408Srandyf if (bgep->asf_enabled) { 5371408Srandyf if ((bgep->asf_status == ASF_STAT_RUN) && 5384588Sml149210 (bgep->asf_pseudostop)) { 5391408Srandyf bgep->bge_mac_state = BGE_MAC_STARTED; 5401408Srandyf mutex_exit(bgep->genlock); 5411408Srandyf return (0); 5421408Srandyf } 5431408Srandyf } 5441865Sdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 5451408Srandyf #else 5461865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 5471408Srandyf #endif 5481865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5491865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5501865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5511865Sdilpreet mutex_exit(bgep->genlock); 5521865Sdilpreet return (EIO); 5531865Sdilpreet } 5541865Sdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) { 5551865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5561865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5571865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5581865Sdilpreet mutex_exit(bgep->genlock); 5591865Sdilpreet return (EIO); 5601865Sdilpreet } 5611369Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 5621369Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 5631408Srandyf 5641865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 5651865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5661865Sdilpreet mutex_exit(bgep->genlock); 5671865Sdilpreet return (EIO); 5681865Sdilpreet } 5691865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 5701865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5711865Sdilpreet mutex_exit(bgep->genlock); 5721865Sdilpreet return (EIO); 5731865Sdilpreet } 5741408Srandyf #ifdef BGE_IPMI_ASF 5751408Srandyf if (bgep->asf_enabled) { 5761408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 5771408Srandyf /* start ASF heart beat */ 5781408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 5794588Sml149210 (void *)bgep, 5804588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 5811408Srandyf bgep->asf_status = ASF_STAT_RUN; 5821408Srandyf } 5831408Srandyf } 5841408Srandyf #endif 5851369Sdduvall mutex_exit(bgep->genlock); 5861369Sdduvall 5871369Sdduvall return (0); 5881369Sdduvall } 5891369Sdduvall 5901369Sdduvall /* 5912331Skrgopi * bge_unicst_set() -- set the physical network address 5922331Skrgopi */ 5932331Skrgopi static int 5948275SEric Cheng bge_unicst_set(void *arg, const uint8_t *macaddr, int slot) 5952331Skrgopi { 5961369Sdduvall bge_t *bgep = arg; /* private device info */ 5971369Sdduvall 5981369Sdduvall BGE_TRACE(("bge_m_unicst_set($%p, %s)", arg, 5994588Sml149210 ether_sprintf((void *)macaddr))); 6001369Sdduvall /* 6011369Sdduvall * Remember the new current address in the driver state 6021369Sdduvall * Sync the chip's idea of the address too ... 6031369Sdduvall */ 6041369Sdduvall mutex_enter(bgep->genlock); 6051865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 6061865Sdilpreet /* can happen during autorecovery */ 6071865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6081865Sdilpreet mutex_exit(bgep->genlock); 6091865Sdilpreet return (EIO); 6101865Sdilpreet } 6112331Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr); 6121408Srandyf #ifdef BGE_IPMI_ASF 6131865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 6141865Sdilpreet #else 6151865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6161865Sdilpreet #endif 6171865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6181865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6191865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6201865Sdilpreet mutex_exit(bgep->genlock); 6211865Sdilpreet return (EIO); 6221865Sdilpreet } 6231865Sdilpreet #ifdef BGE_IPMI_ASF 6241408Srandyf if (bgep->asf_enabled) { 6251408Srandyf /* 6261408Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 6271408Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 6281408Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 6291408Srandyf */ 6301408Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 6311408Srandyf /* 6321408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 6331408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 6341408Srandyf * may crash. 6351408Srandyf */ 6361408Srandyf bge_asf_update_status(bgep); 6371408Srandyf bge_asf_stop_timer(bgep); 6381408Srandyf bgep->asf_status = ASF_STAT_STOP; 6391408Srandyf 6401408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 6411408Srandyf } 6421865Sdilpreet bge_chip_stop(bgep, B_FALSE); 6431408Srandyf 6441865Sdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 6451865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6461865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6471865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 6481865Sdilpreet DDI_SERVICE_DEGRADED); 6491865Sdilpreet mutex_exit(bgep->genlock); 6501865Sdilpreet return (EIO); 6511865Sdilpreet } 6521865Sdilpreet 6531408Srandyf /* 6541408Srandyf * Start our ASF heartbeat counter as soon as possible. 6551408Srandyf */ 6561408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 6571408Srandyf /* start ASF heart beat */ 6581408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 6594588Sml149210 (void *)bgep, 6604588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 6611408Srandyf bgep->asf_status = ASF_STAT_RUN; 6621408Srandyf } 6631408Srandyf } 6641408Srandyf #endif 6651369Sdduvall BGE_DEBUG(("bge_m_unicst_set($%p) done", arg)); 6661865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 6671865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6681865Sdilpreet mutex_exit(bgep->genlock); 6691865Sdilpreet return (EIO); 6701865Sdilpreet } 6711865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 6721865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6731865Sdilpreet mutex_exit(bgep->genlock); 6741865Sdilpreet return (EIO); 6751865Sdilpreet } 6761369Sdduvall mutex_exit(bgep->genlock); 6771369Sdduvall 6781369Sdduvall return (0); 6791369Sdduvall } 6801369Sdduvall 6815903Ssowmini extern void bge_wake_factotum(bge_t *); 6825903Ssowmini 6835903Ssowmini static boolean_t 6845903Ssowmini bge_param_locked(mac_prop_id_t pr_num) 6855903Ssowmini { 6865903Ssowmini /* 6875903Ssowmini * All adv_* parameters are locked (read-only) while 6885903Ssowmini * the device is in any sort of loopback mode ... 6895903Ssowmini */ 6905903Ssowmini switch (pr_num) { 6916789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 6926789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 6936789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 6946789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 6956789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 6966789Sam223141 case MAC_PROP_EN_100FDX_CAP: 6976789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 6986789Sam223141 case MAC_PROP_EN_100HDX_CAP: 6996789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 7006789Sam223141 case MAC_PROP_EN_10FDX_CAP: 7016789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 7026789Sam223141 case MAC_PROP_EN_10HDX_CAP: 7036789Sam223141 case MAC_PROP_AUTONEG: 7046789Sam223141 case MAC_PROP_FLOWCTRL: 7055903Ssowmini return (B_TRUE); 7065903Ssowmini } 7075903Ssowmini return (B_FALSE); 7085903Ssowmini } 7095903Ssowmini /* 7105903Ssowmini * callback functions for set/get of properties 7115903Ssowmini */ 7125903Ssowmini static int 7135903Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 7145903Ssowmini uint_t pr_valsize, const void *pr_val) 7155903Ssowmini { 7165903Ssowmini bge_t *bgep = barg; 7175903Ssowmini int err = 0; 7186512Ssowmini uint32_t cur_mtu, new_mtu; 7195903Ssowmini uint_t maxsdu; 7205903Ssowmini link_flowctrl_t fl; 7215903Ssowmini 7225903Ssowmini mutex_enter(bgep->genlock); 7235903Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE && 7245903Ssowmini bge_param_locked(pr_num)) { 7255903Ssowmini /* 7265903Ssowmini * All adv_* parameters are locked (read-only) 7275903Ssowmini * while the device is in any sort of loopback mode. 7285903Ssowmini */ 7295903Ssowmini mutex_exit(bgep->genlock); 7305903Ssowmini return (EBUSY); 7315903Ssowmini } 7326512Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 7336789Sam223141 ((pr_num == MAC_PROP_EN_100FDX_CAP) || 7348118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_100HDX_CAP) || 7356789Sam223141 (pr_num == MAC_PROP_EN_10FDX_CAP) || 7366789Sam223141 (pr_num == MAC_PROP_EN_10HDX_CAP))) { 7376512Ssowmini /* 7386512Ssowmini * these properties are read/write on copper, 7396512Ssowmini * read-only and 0 on serdes 7406512Ssowmini */ 7416512Ssowmini mutex_exit(bgep->genlock); 7426512Ssowmini return (ENOTSUP); 7436512Ssowmini } 7448922SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep) && 7458922SYong.Tan@Sun.COM ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 7467678SYong.Tan@Sun.COM (pr_num == MAC_PROP_EN_1000HDX_CAP))) { 7477678SYong.Tan@Sun.COM mutex_exit(bgep->genlock); 7487678SYong.Tan@Sun.COM return (ENOTSUP); 7497678SYong.Tan@Sun.COM } 7506512Ssowmini 7515903Ssowmini switch (pr_num) { 7526789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 7535903Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val; 7545903Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val; 7555903Ssowmini goto reprogram; 7566789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 7575903Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val; 7585903Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val; 7595903Ssowmini goto reprogram; 7606789Sam223141 case MAC_PROP_EN_100FDX_CAP: 7615903Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val; 7625903Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val; 7635903Ssowmini goto reprogram; 7646789Sam223141 case MAC_PROP_EN_100HDX_CAP: 7655903Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val; 7665903Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val; 7675903Ssowmini goto reprogram; 7686789Sam223141 case MAC_PROP_EN_10FDX_CAP: 7695903Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val; 7705903Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val; 7715903Ssowmini goto reprogram; 7726789Sam223141 case MAC_PROP_EN_10HDX_CAP: 7735903Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val; 7745903Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val; 7755903Ssowmini reprogram: 7765903Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) 7775903Ssowmini err = EINVAL; 7785903Ssowmini break; 7796789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 7806789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 7816789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 7826789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 7836789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 7846789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 7856789Sam223141 case MAC_PROP_STATUS: 7866789Sam223141 case MAC_PROP_SPEED: 7876789Sam223141 case MAC_PROP_DUPLEX: 7886512Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */ 7895903Ssowmini break; 7906789Sam223141 case MAC_PROP_AUTONEG: 7915903Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val; 7925903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 7935903Ssowmini err = EINVAL; 7945903Ssowmini break; 7956789Sam223141 case MAC_PROP_MTU: 7965903Ssowmini cur_mtu = bgep->chipid.default_mtu; 7975903Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 7986512Ssowmini 7995903Ssowmini if (new_mtu == cur_mtu) { 8005903Ssowmini err = 0; 8015903Ssowmini break; 8025903Ssowmini } 8035903Ssowmini if (new_mtu < BGE_DEFAULT_MTU || 8045903Ssowmini new_mtu > BGE_MAXIMUM_MTU) { 8055903Ssowmini err = EINVAL; 8065903Ssowmini break; 8075903Ssowmini } 8085903Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) && 8095903Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { 8105903Ssowmini err = EINVAL; 8115903Ssowmini break; 8125903Ssowmini } 8135903Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) { 8145903Ssowmini err = EBUSY; 8155903Ssowmini break; 8165903Ssowmini } 8175903Ssowmini bgep->chipid.default_mtu = new_mtu; 8185903Ssowmini if (bge_chip_id_init(bgep)) { 8195903Ssowmini err = EINVAL; 8205903Ssowmini break; 8215903Ssowmini } 8225903Ssowmini maxsdu = bgep->chipid.ethmax_size - 8235903Ssowmini sizeof (struct ether_header); 8245903Ssowmini err = mac_maxsdu_update(bgep->mh, maxsdu); 8255903Ssowmini if (err == 0) { 8265903Ssowmini bgep->bge_dma_error = B_TRUE; 8275903Ssowmini bgep->manual_reset = B_TRUE; 8285903Ssowmini bge_chip_stop(bgep, B_TRUE); 8295903Ssowmini bge_wake_factotum(bgep); 8305903Ssowmini err = 0; 8315903Ssowmini } 8325903Ssowmini break; 8336789Sam223141 case MAC_PROP_FLOWCTRL: 8345903Ssowmini bcopy(pr_val, &fl, sizeof (fl)); 8355903Ssowmini switch (fl) { 8365903Ssowmini default: 8376512Ssowmini err = ENOTSUP; 8385903Ssowmini break; 8395903Ssowmini case LINK_FLOWCTRL_NONE: 8405903Ssowmini bgep->param_adv_pause = 0; 8415903Ssowmini bgep->param_adv_asym_pause = 0; 8425903Ssowmini 8435903Ssowmini bgep->param_link_rx_pause = B_FALSE; 8445903Ssowmini bgep->param_link_tx_pause = B_FALSE; 8455903Ssowmini break; 8465903Ssowmini case LINK_FLOWCTRL_RX: 8475903Ssowmini bgep->param_adv_pause = 1; 8485903Ssowmini bgep->param_adv_asym_pause = 1; 8495903Ssowmini 8505903Ssowmini bgep->param_link_rx_pause = B_TRUE; 8515903Ssowmini bgep->param_link_tx_pause = B_FALSE; 8525903Ssowmini break; 8535903Ssowmini case LINK_FLOWCTRL_TX: 8545903Ssowmini bgep->param_adv_pause = 0; 8555903Ssowmini bgep->param_adv_asym_pause = 1; 8565903Ssowmini 8575903Ssowmini bgep->param_link_rx_pause = B_FALSE; 8585903Ssowmini bgep->param_link_tx_pause = B_TRUE; 8595903Ssowmini break; 8605903Ssowmini case LINK_FLOWCTRL_BI: 8615903Ssowmini bgep->param_adv_pause = 1; 8628922SYong.Tan@Sun.COM bgep->param_adv_asym_pause = 0; 8635903Ssowmini 8645903Ssowmini bgep->param_link_rx_pause = B_TRUE; 8655903Ssowmini bgep->param_link_tx_pause = B_TRUE; 8665903Ssowmini break; 8675903Ssowmini } 8685903Ssowmini 8695903Ssowmini if (err == 0) { 8705903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 8715903Ssowmini err = EINVAL; 8725903Ssowmini } 8735903Ssowmini 8745903Ssowmini break; 8756789Sam223141 case MAC_PROP_PRIVATE: 8765903Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize, 8775903Ssowmini pr_val); 8785903Ssowmini break; 8796512Ssowmini default: 8806512Ssowmini err = ENOTSUP; 8816512Ssowmini break; 8825903Ssowmini } 8835903Ssowmini mutex_exit(bgep->genlock); 8845903Ssowmini return (err); 8855903Ssowmini } 8866512Ssowmini 8878118SVasumathi.Sundaram@Sun.COM /* ARGSUSED */ 8885903Ssowmini static int 8895903Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 8908118SVasumathi.Sundaram@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 8915903Ssowmini { 8925903Ssowmini bge_t *bgep = barg; 8935903Ssowmini int err = 0; 8945903Ssowmini link_flowctrl_t fl; 8956512Ssowmini uint64_t speed; 8966512Ssowmini int flags = bgep->chipid.flags; 8976789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 8986512Ssowmini 8996512Ssowmini if (pr_valsize == 0) 9006512Ssowmini return (EINVAL); 9015903Ssowmini bzero(pr_val, pr_valsize); 9028118SVasumathi.Sundaram@Sun.COM 9038118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 9048118SVasumathi.Sundaram@Sun.COM 9058118SVasumathi.Sundaram@Sun.COM mutex_enter(bgep->genlock); 9068118SVasumathi.Sundaram@Sun.COM if ((bgep->param_loop_mode != BGE_LOOP_NONE && 9078118SVasumathi.Sundaram@Sun.COM bge_param_locked(pr_num)) || 9088118SVasumathi.Sundaram@Sun.COM ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 9098118SVasumathi.Sundaram@Sun.COM ((pr_num == MAC_PROP_EN_100FDX_CAP) || 9108118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_100HDX_CAP) || 9118118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_10FDX_CAP) || 9128118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_10HDX_CAP))) || 9138118SVasumathi.Sundaram@Sun.COM (DEVICE_5906_SERIES_CHIPSETS(bgep) && 9148922SYong.Tan@Sun.COM ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 9158922SYong.Tan@Sun.COM (pr_num == MAC_PROP_EN_1000HDX_CAP)))) 9168118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9178118SVasumathi.Sundaram@Sun.COM mutex_exit(bgep->genlock); 9188118SVasumathi.Sundaram@Sun.COM 9195903Ssowmini switch (pr_num) { 9206789Sam223141 case MAC_PROP_DUPLEX: 9218118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9226512Ssowmini if (pr_valsize < sizeof (link_duplex_t)) 9235903Ssowmini return (EINVAL); 9246512Ssowmini bcopy(&bgep->param_link_duplex, pr_val, 9256512Ssowmini sizeof (link_duplex_t)); 9265903Ssowmini break; 9276789Sam223141 case MAC_PROP_SPEED: 9288118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9296512Ssowmini if (pr_valsize < sizeof (speed)) 9305903Ssowmini return (EINVAL); 9316512Ssowmini speed = bgep->param_link_speed * 1000000ull; 9326512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 9335903Ssowmini break; 9346789Sam223141 case MAC_PROP_STATUS: 9358118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9366512Ssowmini if (pr_valsize < sizeof (link_state_t)) 9375903Ssowmini return (EINVAL); 9386512Ssowmini bcopy(&bgep->link_state, pr_val, 9396512Ssowmini sizeof (link_state_t)); 9405903Ssowmini break; 9416789Sam223141 case MAC_PROP_AUTONEG: 9426512Ssowmini if (is_default) 9436512Ssowmini *(uint8_t *)pr_val = 1; 9446512Ssowmini else 9456512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg; 9465903Ssowmini break; 9476789Sam223141 case MAC_PROP_FLOWCTRL: 9486512Ssowmini if (pr_valsize < sizeof (fl)) 9495903Ssowmini return (EINVAL); 9506512Ssowmini if (is_default) { 9516512Ssowmini fl = LINK_FLOWCTRL_BI; 9526512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 9536512Ssowmini break; 9546512Ssowmini } 9556512Ssowmini 9565903Ssowmini if (bgep->param_link_rx_pause && 9575903Ssowmini !bgep->param_link_tx_pause) 9585903Ssowmini fl = LINK_FLOWCTRL_RX; 9595903Ssowmini 9605903Ssowmini if (!bgep->param_link_rx_pause && 9615903Ssowmini !bgep->param_link_tx_pause) 9625903Ssowmini fl = LINK_FLOWCTRL_NONE; 9635903Ssowmini 9645903Ssowmini if (!bgep->param_link_rx_pause && 9655903Ssowmini bgep->param_link_tx_pause) 9665903Ssowmini fl = LINK_FLOWCTRL_TX; 9675903Ssowmini 9685903Ssowmini if (bgep->param_link_rx_pause && 9695903Ssowmini bgep->param_link_tx_pause) 9705903Ssowmini fl = LINK_FLOWCTRL_BI; 9715903Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 9725903Ssowmini break; 9736789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 9748118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9757678SYong.Tan@Sun.COM if (is_default) { 9767678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9777678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 9787678SYong.Tan@Sun.COM else 9797678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 9807678SYong.Tan@Sun.COM } 9816512Ssowmini else 9826512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx; 9835903Ssowmini break; 9846789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 9857678SYong.Tan@Sun.COM if (is_default) { 9867678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9877678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 9887678SYong.Tan@Sun.COM else 9897678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 9907678SYong.Tan@Sun.COM } 9916512Ssowmini else 9926512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx; 9935903Ssowmini break; 9946789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 9958118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9967678SYong.Tan@Sun.COM if (is_default) { 9977678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9987678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 9997678SYong.Tan@Sun.COM else 10007678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 10017678SYong.Tan@Sun.COM } 10026512Ssowmini else 10036512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx; 10045903Ssowmini break; 10056789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 10067678SYong.Tan@Sun.COM if (is_default) { 10077678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 10087678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 10097678SYong.Tan@Sun.COM else 10107678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 10117678SYong.Tan@Sun.COM } 10126512Ssowmini else 10136512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx; 10145903Ssowmini break; 10156789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 10168118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10176512Ssowmini if (is_default) { 10186512Ssowmini *(uint8_t *)pr_val = 10196512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10206512Ssowmini } else { 10216512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx; 10226512Ssowmini } 10235903Ssowmini break; 10246789Sam223141 case MAC_PROP_EN_100FDX_CAP: 10256512Ssowmini if (is_default) { 10266512Ssowmini *(uint8_t *)pr_val = 10276512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10286512Ssowmini } else { 10296512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx; 10306512Ssowmini } 10315903Ssowmini break; 10326789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 10338118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10346512Ssowmini if (is_default) { 10356512Ssowmini *(uint8_t *)pr_val = 10366512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10376512Ssowmini } else { 10386512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx; 10396512Ssowmini } 10405903Ssowmini break; 10416789Sam223141 case MAC_PROP_EN_100HDX_CAP: 10426512Ssowmini if (is_default) { 10436512Ssowmini *(uint8_t *)pr_val = 10446512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10456512Ssowmini } else { 10466512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx; 10476512Ssowmini } 10485903Ssowmini break; 10496789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 10508118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10516512Ssowmini if (is_default) { 10526512Ssowmini *(uint8_t *)pr_val = 10536512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10546512Ssowmini } else { 10556512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx; 10566512Ssowmini } 10575903Ssowmini break; 10586789Sam223141 case MAC_PROP_EN_10FDX_CAP: 10596512Ssowmini if (is_default) { 10606512Ssowmini *(uint8_t *)pr_val = 10616512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10626512Ssowmini } else { 10636512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx; 10646512Ssowmini } 10655903Ssowmini break; 10666789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 10678118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10686512Ssowmini if (is_default) { 10696512Ssowmini *(uint8_t *)pr_val = 10706512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10716512Ssowmini } else { 10726512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx; 10736512Ssowmini } 10745903Ssowmini break; 10756789Sam223141 case MAC_PROP_EN_10HDX_CAP: 10766512Ssowmini if (is_default) { 10776512Ssowmini *(uint8_t *)pr_val = 10786512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10796512Ssowmini } else { 10806512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx; 10816512Ssowmini } 10825903Ssowmini break; 10836789Sam223141 case MAC_PROP_ADV_100T4_CAP: 10846789Sam223141 case MAC_PROP_EN_100T4_CAP: 10858118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10866512Ssowmini *(uint8_t *)pr_val = 0; 10876512Ssowmini break; 10886789Sam223141 case MAC_PROP_PRIVATE: 10896512Ssowmini err = bge_get_priv_prop(bgep, pr_name, pr_flags, 10906512Ssowmini pr_valsize, pr_val); 10916512Ssowmini return (err); 1092*9514SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: { 1093*9514SGirish.Moodalbail@Sun.COM mac_propval_range_t range; 1094*9514SGirish.Moodalbail@Sun.COM 1095*9514SGirish.Moodalbail@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 1096*9514SGirish.Moodalbail@Sun.COM return (ENOTSUP); 1097*9514SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 1098*9514SGirish.Moodalbail@Sun.COM return (EINVAL); 1099*9514SGirish.Moodalbail@Sun.COM range.mpr_count = 1; 1100*9514SGirish.Moodalbail@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 1101*9514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_min = 1102*9514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = BGE_DEFAULT_MTU; 1103*9514SGirish.Moodalbail@Sun.COM if (bge_jumbo_enable && !(flags & CHIP_FLAG_NO_JUMBO)) 1104*9514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = 1105*9514SGirish.Moodalbail@Sun.COM BGE_MAXIMUM_MTU; 1106*9514SGirish.Moodalbail@Sun.COM bcopy(&range, pr_val, sizeof (range)); 1107*9514SGirish.Moodalbail@Sun.COM break; 1108*9514SGirish.Moodalbail@Sun.COM } 11095903Ssowmini default: 11106512Ssowmini return (ENOTSUP); 11115903Ssowmini } 11125903Ssowmini return (0); 11135903Ssowmini } 11145903Ssowmini 11155903Ssowmini /* ARGSUSED */ 11165903Ssowmini static int 11175903Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, 11185903Ssowmini const void *pr_val) 11195903Ssowmini { 11205903Ssowmini int err = 0; 11215903Ssowmini long result; 11225903Ssowmini 11236512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 11246512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11256512Ssowmini if (result > 1 || result < 0) { 11266512Ssowmini err = EINVAL; 11276512Ssowmini } else { 11287099Syt223700 bgep->param_adv_pause = (uint32_t)result; 11296512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11306512Ssowmini err = EINVAL; 11316512Ssowmini } 11326512Ssowmini return (err); 11336512Ssowmini } 11346512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 11356512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11366512Ssowmini if (result > 1 || result < 0) { 11376512Ssowmini err = EINVAL; 11386512Ssowmini } else { 11397099Syt223700 bgep->param_adv_asym_pause = (uint32_t)result; 11406512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11416512Ssowmini err = EINVAL; 11426512Ssowmini } 11436512Ssowmini return (err); 11446512Ssowmini } 11455903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 11465903Ssowmini 11475903Ssowmini /* 11485903Ssowmini * on the Tx side, we need to update the h/w register for 11495903Ssowmini * real packet transmission per packet. The drain_max parameter 11505903Ssowmini * is used to reduce the register access. This parameter 11515903Ssowmini * controls the max number of packets that we will hold before 11525903Ssowmini * updating the bge h/w to trigger h/w transmit. The bge 11535903Ssowmini * chipset usually has a max of 512 Tx descriptors, thus 11545903Ssowmini * the upper bound on drain_max is 512. 11555903Ssowmini */ 11565903Ssowmini if (pr_val == NULL) { 11575903Ssowmini err = EINVAL; 11585903Ssowmini return (err); 11595903Ssowmini } 11605903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11615903Ssowmini if (result > 512 || result < 1) 11625903Ssowmini err = EINVAL; 11635903Ssowmini else { 11645903Ssowmini bgep->param_drain_max = (uint32_t)result; 11655903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11665903Ssowmini err = EINVAL; 11675903Ssowmini } 11685903Ssowmini return (err); 11695903Ssowmini } 11705903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 11715903Ssowmini 11725903Ssowmini if (pr_val == NULL) { 11735903Ssowmini err = EINVAL; 11745903Ssowmini return (err); 11755903Ssowmini } 11765903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11775903Ssowmini if (result > 7 || result < 0) 11785903Ssowmini err = EINVAL; 11795903Ssowmini else { 11805903Ssowmini bgep->param_msi_cnt = (uint32_t)result; 11815903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11825903Ssowmini err = EINVAL; 11835903Ssowmini } 11845903Ssowmini return (err); 11855903Ssowmini } 11865903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 11876512Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 11885903Ssowmini return (EINVAL); 11895903Ssowmini 11907099Syt223700 bgep->chipid.rx_ticks_norm = (uint32_t)result; 11915903Ssowmini return (0); 11925903Ssowmini } 11935903Ssowmini 11945903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 11955903Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 11965903Ssowmini return (EINVAL); 11975903Ssowmini 11987099Syt223700 bgep->chipid.rx_count_norm = (uint32_t)result; 11995903Ssowmini return (0); 12005903Ssowmini } 12016512Ssowmini return (ENOTSUP); 12025903Ssowmini } 12035903Ssowmini 12045903Ssowmini static int 12056512Ssowmini bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_flags, 12066512Ssowmini uint_t pr_valsize, void *pr_val) 12075903Ssowmini { 12086512Ssowmini int err = ENOTSUP; 12096789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 12106512Ssowmini int value; 12116512Ssowmini 12126512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 12136512Ssowmini value = (is_default? 1 : bge->param_adv_pause); 12146512Ssowmini err = 0; 12156512Ssowmini goto done; 12166512Ssowmini } 12176512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 12186512Ssowmini value = (is_default? 1 : bge->param_adv_asym_pause); 12196512Ssowmini err = 0; 12206512Ssowmini goto done; 12216512Ssowmini } 12225903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 12236512Ssowmini value = (is_default? 64 : bge->param_drain_max); 12245903Ssowmini err = 0; 12255903Ssowmini goto done; 12265903Ssowmini } 12275903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 12286512Ssowmini value = (is_default? 0 : bge->param_msi_cnt); 12295903Ssowmini err = 0; 12305903Ssowmini goto done; 12315903Ssowmini } 12325903Ssowmini 12335903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 12346512Ssowmini value = (is_default? bge_rx_ticks_norm : 12356512Ssowmini bge->chipid.rx_ticks_norm); 12365903Ssowmini err = 0; 12375903Ssowmini goto done; 12385903Ssowmini } 12395903Ssowmini 12405903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 12416512Ssowmini value = (is_default? bge_rx_count_norm : 12426512Ssowmini bge->chipid.rx_count_norm); 12435903Ssowmini err = 0; 12445903Ssowmini goto done; 12455903Ssowmini } 12465903Ssowmini 12475903Ssowmini done: 12486512Ssowmini if (err == 0) { 12496512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 12505903Ssowmini } 12515903Ssowmini return (err); 12525903Ssowmini } 12535903Ssowmini 12542331Skrgopi /* 12551369Sdduvall * Compute the index of the required bit in the multicast hash map. 12561369Sdduvall * This must mirror the way the hardware actually does it! 12571369Sdduvall * See Broadcom document 570X-PG102-R page 125. 12581369Sdduvall */ 12591369Sdduvall static uint32_t 12601369Sdduvall bge_hash_index(const uint8_t *mca) 12611369Sdduvall { 12621369Sdduvall uint32_t hash; 12631369Sdduvall 12641369Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 12651369Sdduvall 12661369Sdduvall return (hash); 12671369Sdduvall } 12681369Sdduvall 12691369Sdduvall /* 12701369Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 12711369Sdduvall */ 12721369Sdduvall static int 12731369Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12741369Sdduvall { 12751369Sdduvall bge_t *bgep = arg; /* private device info */ 12761369Sdduvall uint32_t hash; 12771369Sdduvall uint32_t index; 12781369Sdduvall uint32_t word; 12791369Sdduvall uint32_t bit; 12801369Sdduvall uint8_t *refp; 12811369Sdduvall 12821369Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 12834588Sml149210 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12841369Sdduvall 12851369Sdduvall /* 12861369Sdduvall * Precalculate all required masks, pointers etc ... 12871369Sdduvall */ 12881369Sdduvall hash = bge_hash_index(mca); 12891369Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 12901369Sdduvall word = index/32u; 12911369Sdduvall bit = 1 << (index % 32u); 12921369Sdduvall refp = &bgep->mcast_refs[index]; 12931369Sdduvall 12941369Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 12954588Sml149210 hash, index, word, bit, *refp)); 12961369Sdduvall 12971369Sdduvall /* 12981369Sdduvall * We must set the appropriate bit in the hash map (and the 12991369Sdduvall * corresponding h/w register) when the refcount goes from 0 13001369Sdduvall * to >0, and clear it when the last ref goes away (refcount 13011369Sdduvall * goes from >0 back to 0). If we change the hash map, we 13021369Sdduvall * must also update the chip's hardware map registers. 13031369Sdduvall */ 13041369Sdduvall mutex_enter(bgep->genlock); 13051865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 13061865Sdilpreet /* can happen during autorecovery */ 13071865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13081865Sdilpreet mutex_exit(bgep->genlock); 13091865Sdilpreet return (EIO); 13101865Sdilpreet } 13111369Sdduvall if (add) { 13121369Sdduvall if ((*refp)++ == 0) { 13131369Sdduvall bgep->mcast_hash[word] |= bit; 13141408Srandyf #ifdef BGE_IPMI_ASF 13151865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 13161408Srandyf #else 13171865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 13181408Srandyf #endif 13191865Sdilpreet (void) bge_check_acc_handle(bgep, 13201865Sdilpreet bgep->cfg_handle); 13211865Sdilpreet (void) bge_check_acc_handle(bgep, 13221865Sdilpreet bgep->io_handle); 13231865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 13241865Sdilpreet DDI_SERVICE_DEGRADED); 13251865Sdilpreet mutex_exit(bgep->genlock); 13261865Sdilpreet return (EIO); 13271865Sdilpreet } 13281369Sdduvall } 13291369Sdduvall } else { 13301369Sdduvall if (--(*refp) == 0) { 13311369Sdduvall bgep->mcast_hash[word] &= ~bit; 13321408Srandyf #ifdef BGE_IPMI_ASF 13331865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 13341408Srandyf #else 13351865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 13361408Srandyf #endif 13371865Sdilpreet (void) bge_check_acc_handle(bgep, 13381865Sdilpreet bgep->cfg_handle); 13391865Sdilpreet (void) bge_check_acc_handle(bgep, 13401865Sdilpreet bgep->io_handle); 13411865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 13421865Sdilpreet DDI_SERVICE_DEGRADED); 13431865Sdilpreet mutex_exit(bgep->genlock); 13441865Sdilpreet return (EIO); 13451865Sdilpreet } 13461369Sdduvall } 13471369Sdduvall } 13481369Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 13491865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 13501865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13511865Sdilpreet mutex_exit(bgep->genlock); 13521865Sdilpreet return (EIO); 13531865Sdilpreet } 13541865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 13551865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13561865Sdilpreet mutex_exit(bgep->genlock); 13571865Sdilpreet return (EIO); 13581865Sdilpreet } 13591369Sdduvall mutex_exit(bgep->genlock); 13601369Sdduvall 13611369Sdduvall return (0); 13621369Sdduvall } 13631369Sdduvall 13641369Sdduvall /* 13651369Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 13661369Sdduvall * 13671369Sdduvall * Program the hardware to enable/disable promiscuous and/or 13681369Sdduvall * receive-all-multicast modes. 13691369Sdduvall */ 13701369Sdduvall static int 13711369Sdduvall bge_m_promisc(void *arg, boolean_t on) 13721369Sdduvall { 13731369Sdduvall bge_t *bgep = arg; 13741369Sdduvall 13751369Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 13761369Sdduvall 13771369Sdduvall /* 13781369Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 13791369Sdduvall */ 13801369Sdduvall mutex_enter(bgep->genlock); 13811865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 13821865Sdilpreet /* can happen during autorecovery */ 13831865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13841865Sdilpreet mutex_exit(bgep->genlock); 13851865Sdilpreet return (EIO); 13861865Sdilpreet } 13871369Sdduvall bgep->promisc = on; 13881408Srandyf #ifdef BGE_IPMI_ASF 13891865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 13901408Srandyf #else 13911865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 13921408Srandyf #endif 13931865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 13941865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 13951865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13961865Sdilpreet mutex_exit(bgep->genlock); 13971865Sdilpreet return (EIO); 13981865Sdilpreet } 13991369Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 14001865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 14011865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14021865Sdilpreet mutex_exit(bgep->genlock); 14031865Sdilpreet return (EIO); 14041865Sdilpreet } 14051865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 14061865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14071865Sdilpreet mutex_exit(bgep->genlock); 14081865Sdilpreet return (EIO); 14091865Sdilpreet } 14101369Sdduvall mutex_exit(bgep->genlock); 14111369Sdduvall return (0); 14121369Sdduvall } 14131369Sdduvall 14148275SEric Cheng /* 14158275SEric Cheng * Find the slot for the specified unicast address 14168275SEric Cheng */ 14178275SEric Cheng int 14188275SEric Cheng bge_unicst_find(bge_t *bgep, const uint8_t *mac_addr) 14198275SEric Cheng { 14208275SEric Cheng int slot; 14218275SEric Cheng 14228275SEric Cheng ASSERT(mutex_owned(bgep->genlock)); 14238275SEric Cheng 14248275SEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 14258275SEric Cheng if (bcmp(bgep->curr_addr[slot].addr, mac_addr, ETHERADDRL) == 0) 14268275SEric Cheng return (slot); 14278275SEric Cheng } 14288275SEric Cheng 14298275SEric Cheng return (-1); 14308275SEric Cheng } 14318275SEric Cheng 14328275SEric Cheng /* 14338275SEric Cheng * Programs the classifier to start steering packets matching 'mac_addr' to the 14348275SEric Cheng * specified ring 'arg'. 14358275SEric Cheng */ 14368275SEric Cheng static int 14378275SEric Cheng bge_addmac(void *arg, const uint8_t *mac_addr) 14388275SEric Cheng { 14398275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 14408275SEric Cheng bge_t *bgep = rrp->bgep; 14418275SEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 14428275SEric Cheng bge_rule_info_t *rinfop = NULL; 14438275SEric Cheng uint8_t ring = (uint8_t)(rrp - bgep->recv) + 1; 14448275SEric Cheng int i; 14458275SEric Cheng uint16_t tmp16; 14468275SEric Cheng uint32_t tmp32; 14478275SEric Cheng int slot; 14488275SEric Cheng int err; 14498275SEric Cheng 14508275SEric Cheng mutex_enter(bgep->genlock); 14518275SEric Cheng if (bgep->unicst_addr_avail == 0) { 14528275SEric Cheng mutex_exit(bgep->genlock); 14538275SEric Cheng return (ENOSPC); 14548275SEric Cheng } 14558275SEric Cheng 14568275SEric Cheng /* 14578275SEric Cheng * First add the unicast address to a available slot. 14588275SEric Cheng */ 14598275SEric Cheng slot = bge_unicst_find(bgep, mac_addr); 14608275SEric Cheng ASSERT(slot == -1); 14618275SEric Cheng 14628275SEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 14638275SEric Cheng if (!bgep->curr_addr[slot].set) { 14648275SEric Cheng bgep->curr_addr[slot].set = B_TRUE; 14658275SEric Cheng break; 14668275SEric Cheng } 14678275SEric Cheng } 14688275SEric Cheng 14698275SEric Cheng ASSERT(slot < bgep->unicst_addr_total); 14708275SEric Cheng bgep->unicst_addr_avail--; 14718275SEric Cheng mutex_exit(bgep->genlock); 14728275SEric Cheng 14738275SEric Cheng if ((err = bge_unicst_set(bgep, mac_addr, slot)) != 0) 14748275SEric Cheng goto fail; 14758275SEric Cheng 14768275SEric Cheng /* A rule is already here. Deny this. */ 14778275SEric Cheng if (rrp->mac_addr_rule != NULL) { 14788275SEric Cheng err = ether_cmp(mac_addr, rrp->mac_addr_val) ? EEXIST : EBUSY; 14798275SEric Cheng goto fail; 14808275SEric Cheng } 14818275SEric Cheng 14828275SEric Cheng /* 14838275SEric Cheng * Allocate a bge_rule_info_t to keep track of which rule slots 14848275SEric Cheng * are being used. 14858275SEric Cheng */ 14868275SEric Cheng rinfop = kmem_zalloc(sizeof (bge_rule_info_t), KM_NOSLEEP); 14878275SEric Cheng if (rinfop == NULL) { 14888275SEric Cheng err = ENOMEM; 14898275SEric Cheng goto fail; 14908275SEric Cheng } 14918275SEric Cheng 14928275SEric Cheng /* 14938275SEric Cheng * Look for the starting slot to place the rules. 14948275SEric Cheng * The two slots we reserve must be contiguous. 14958275SEric Cheng */ 14968275SEric Cheng for (i = 0; i + 1 < RECV_RULES_NUM_MAX; i++) 14978275SEric Cheng if ((rulep[i].control & RECV_RULE_CTL_ENABLE) == 0 && 14988275SEric Cheng (rulep[i+1].control & RECV_RULE_CTL_ENABLE) == 0) 14998275SEric Cheng break; 15008275SEric Cheng 15018275SEric Cheng ASSERT(i + 1 < RECV_RULES_NUM_MAX); 15028275SEric Cheng 15038275SEric Cheng bcopy(mac_addr, &tmp32, sizeof (tmp32)); 15048275SEric Cheng rulep[i].mask_value = ntohl(tmp32); 15058275SEric Cheng rulep[i].control = RULE_DEST_MAC_1(ring) | RECV_RULE_CTL_AND; 15068275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep[i].mask_value); 15078275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep[i].control); 15088275SEric Cheng 15098275SEric Cheng bcopy(mac_addr + 4, &tmp16, sizeof (tmp16)); 15108275SEric Cheng rulep[i+1].mask_value = 0xffff0000 | ntohs(tmp16); 15118275SEric Cheng rulep[i+1].control = RULE_DEST_MAC_2(ring); 15128275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i+1), rulep[i+1].mask_value); 15138275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i+1), rulep[i+1].control); 15148275SEric Cheng rinfop->start = i; 15158275SEric Cheng rinfop->count = 2; 15168275SEric Cheng 15178275SEric Cheng rrp->mac_addr_rule = rinfop; 15188275SEric Cheng bcopy(mac_addr, rrp->mac_addr_val, ETHERADDRL); 15198275SEric Cheng 15208275SEric Cheng return (0); 15218275SEric Cheng 15228275SEric Cheng fail: 15238275SEric Cheng /* Clear the address just set */ 15248275SEric Cheng (void) bge_unicst_set(bgep, zero_addr, slot); 15258275SEric Cheng mutex_enter(bgep->genlock); 15268275SEric Cheng bgep->curr_addr[slot].set = B_FALSE; 15278275SEric Cheng bgep->unicst_addr_avail++; 15288275SEric Cheng mutex_exit(bgep->genlock); 15298275SEric Cheng 15308275SEric Cheng return (err); 15318275SEric Cheng } 15328275SEric Cheng 15338275SEric Cheng /* 15348275SEric Cheng * Stop classifying packets matching the MAC address to the specified ring. 15358275SEric Cheng */ 15368275SEric Cheng static int 15378275SEric Cheng bge_remmac(void *arg, const uint8_t *mac_addr) 15388275SEric Cheng { 15398275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 15408275SEric Cheng bge_t *bgep = rrp->bgep; 15418275SEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 15428275SEric Cheng bge_rule_info_t *rinfop = rrp->mac_addr_rule; 15438275SEric Cheng int start; 15448275SEric Cheng int slot; 15458275SEric Cheng int err; 15468275SEric Cheng 15478275SEric Cheng /* 15488275SEric Cheng * Remove the MAC address from its slot. 15498275SEric Cheng */ 15508275SEric Cheng mutex_enter(bgep->genlock); 15518275SEric Cheng slot = bge_unicst_find(bgep, mac_addr); 15528275SEric Cheng if (slot == -1) { 15538275SEric Cheng mutex_exit(bgep->genlock); 15548275SEric Cheng return (EINVAL); 15558275SEric Cheng } 15568275SEric Cheng 15578275SEric Cheng ASSERT(bgep->curr_addr[slot].set); 15588275SEric Cheng mutex_exit(bgep->genlock); 15598275SEric Cheng 15608275SEric Cheng if ((err = bge_unicst_set(bgep, zero_addr, slot)) != 0) 15618275SEric Cheng return (err); 15628275SEric Cheng 15638275SEric Cheng if (rinfop == NULL || ether_cmp(mac_addr, rrp->mac_addr_val) != 0) 15648275SEric Cheng return (EINVAL); 15658275SEric Cheng 15668275SEric Cheng start = rinfop->start; 15678275SEric Cheng rulep[start].mask_value = 0; 15688275SEric Cheng rulep[start].control = 0; 15698275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 15708275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 15718275SEric Cheng start++; 15728275SEric Cheng rulep[start].mask_value = 0; 15738275SEric Cheng rulep[start].control = 0; 15748275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 15758275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 15768275SEric Cheng 15778275SEric Cheng kmem_free(rinfop, sizeof (bge_rule_info_t)); 15788275SEric Cheng rrp->mac_addr_rule = NULL; 15798275SEric Cheng bzero(rrp->mac_addr_val, ETHERADDRL); 15808275SEric Cheng 15818275SEric Cheng mutex_enter(bgep->genlock); 15828275SEric Cheng bgep->curr_addr[slot].set = B_FALSE; 15838275SEric Cheng bgep->unicst_addr_avail++; 15848275SEric Cheng mutex_exit(bgep->genlock); 15858275SEric Cheng 15868275SEric Cheng return (0); 15878275SEric Cheng } 15888275SEric Cheng 15898275SEric Cheng static int 15908275SEric Cheng bge_flag_intr_enable(mac_intr_handle_t ih) 15918275SEric Cheng { 15928275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 15938275SEric Cheng bge_t *bgep = rrp->bgep; 15948275SEric Cheng 15958275SEric Cheng mutex_enter(bgep->genlock); 15968275SEric Cheng rrp->poll_flag = 0; 15978275SEric Cheng mutex_exit(bgep->genlock); 15988275SEric Cheng 15998275SEric Cheng return (0); 16008275SEric Cheng } 16018275SEric Cheng 16028275SEric Cheng static int 16038275SEric Cheng bge_flag_intr_disable(mac_intr_handle_t ih) 16048275SEric Cheng { 16058275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 16068275SEric Cheng bge_t *bgep = rrp->bgep; 16078275SEric Cheng 16088275SEric Cheng mutex_enter(bgep->genlock); 16098275SEric Cheng rrp->poll_flag = 1; 16108275SEric Cheng mutex_exit(bgep->genlock); 16118275SEric Cheng 16128275SEric Cheng return (0); 16138275SEric Cheng } 16148275SEric Cheng 16158275SEric Cheng static int 16168275SEric Cheng bge_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 16178275SEric Cheng { 16188275SEric Cheng recv_ring_t *rx_ring; 16198275SEric Cheng 16208275SEric Cheng rx_ring = (recv_ring_t *)rh; 16218275SEric Cheng mutex_enter(rx_ring->rx_lock); 16228275SEric Cheng rx_ring->ring_gen_num = mr_gen_num; 16238275SEric Cheng mutex_exit(rx_ring->rx_lock); 16248275SEric Cheng return (0); 16258275SEric Cheng } 16268275SEric Cheng 16278275SEric Cheng 16288275SEric Cheng /* 16298275SEric Cheng * Callback funtion for MAC layer to register all rings 16308275SEric Cheng * for given ring_group, noted by rg_index. 16318275SEric Cheng */ 16328275SEric Cheng void 16338275SEric Cheng bge_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, 16348275SEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh) 16358275SEric Cheng { 16368275SEric Cheng bge_t *bgep = arg; 16378275SEric Cheng mac_intr_t *mintr; 16388275SEric Cheng 16398275SEric Cheng switch (rtype) { 16408275SEric Cheng case MAC_RING_TYPE_RX: { 16418275SEric Cheng recv_ring_t *rx_ring; 16428275SEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 16438275SEric Cheng MAC_ADDRESS_REGS_MAX) && index == 0); 16448275SEric Cheng 16458275SEric Cheng rx_ring = &bgep->recv[rg_index]; 16468275SEric Cheng rx_ring->ring_handle = rh; 16478275SEric Cheng 16488275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 16498275SEric Cheng infop->mri_start = bge_ring_start; 16508275SEric Cheng infop->mri_stop = NULL; 16518275SEric Cheng infop->mri_poll = bge_poll_ring; 16528275SEric Cheng 16538275SEric Cheng mintr = &infop->mri_intr; 16548275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 16558275SEric Cheng mintr->mi_enable = bge_flag_intr_enable; 16568275SEric Cheng mintr->mi_disable = bge_flag_intr_disable; 16578275SEric Cheng 16588275SEric Cheng break; 16598275SEric Cheng } 16608275SEric Cheng case MAC_RING_TYPE_TX: 16618275SEric Cheng default: 16628275SEric Cheng ASSERT(0); 16638275SEric Cheng break; 16648275SEric Cheng } 16658275SEric Cheng } 16668275SEric Cheng 16678275SEric Cheng /* 16688275SEric Cheng * Fill infop passed as argument 16698275SEric Cheng * fill in respective ring_group info 16708275SEric Cheng * Each group has a single ring in it. We keep it simple 16718275SEric Cheng * and use the same internal handle for rings and groups. 16728275SEric Cheng */ 16738275SEric Cheng void 16748275SEric Cheng bge_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index, 16758275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 16768275SEric Cheng { 16778275SEric Cheng bge_t *bgep = arg; 16788275SEric Cheng 16798275SEric Cheng switch (rtype) { 16808275SEric Cheng case MAC_RING_TYPE_RX: { 16818275SEric Cheng recv_ring_t *rx_ring; 16828275SEric Cheng 16838275SEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 16848275SEric Cheng MAC_ADDRESS_REGS_MAX)); 16858275SEric Cheng rx_ring = &bgep->recv[rg_index]; 16868275SEric Cheng rx_ring->ring_group_handle = gh; 16878275SEric Cheng 16888275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring; 16898275SEric Cheng infop->mgi_start = NULL; 16908275SEric Cheng infop->mgi_stop = NULL; 16918275SEric Cheng infop->mgi_addmac = bge_addmac; 16928275SEric Cheng infop->mgi_remmac = bge_remmac; 16938275SEric Cheng infop->mgi_count = 1; 16948275SEric Cheng break; 16958275SEric Cheng } 16968275SEric Cheng case MAC_RING_TYPE_TX: 16978275SEric Cheng default: 16988275SEric Cheng ASSERT(0); 16998275SEric Cheng break; 17008275SEric Cheng } 17018275SEric Cheng } 17028275SEric Cheng 17032311Sseb /*ARGSUSED*/ 17042311Sseb static boolean_t 17052311Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 17062311Sseb { 17072331Skrgopi bge_t *bgep = arg; 17082331Skrgopi 17092311Sseb switch (cap) { 17102311Sseb case MAC_CAPAB_HCKSUM: { 17112311Sseb uint32_t *txflags = cap_data; 17122311Sseb 17132311Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 17142311Sseb break; 17152311Sseb } 17168275SEric Cheng case MAC_CAPAB_RINGS: { 17178275SEric Cheng mac_capab_rings_t *cap_rings = cap_data; 17188275SEric Cheng 17198275SEric Cheng /* Temporarily disable multiple tx rings. */ 17208275SEric Cheng if (cap_rings->mr_type != MAC_RING_TYPE_RX) 17218275SEric Cheng return (B_FALSE); 17228275SEric Cheng 17238275SEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 17248275SEric Cheng cap_rings->mr_rnum = cap_rings->mr_gnum = 17258275SEric Cheng MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX); 17268275SEric Cheng cap_rings->mr_rget = bge_fill_ring; 17278275SEric Cheng cap_rings->mr_gget = bge_fill_group; 17282331Skrgopi break; 17292331Skrgopi } 17302311Sseb default: 17312311Sseb return (B_FALSE); 17322311Sseb } 17332311Sseb return (B_TRUE); 17342311Sseb } 17352311Sseb 17361369Sdduvall /* 17371369Sdduvall * Loopback ioctl code 17381369Sdduvall */ 17391369Sdduvall 17401369Sdduvall static lb_property_t loopmodes[] = { 17411369Sdduvall { normal, "normal", BGE_LOOP_NONE }, 17421369Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 17431369Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 17441369Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 17451369Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 17461369Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 17471369Sdduvall }; 17481369Sdduvall 17491369Sdduvall static enum ioc_reply 17501369Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 17511369Sdduvall { 17521369Sdduvall /* 17531369Sdduvall * If the mode isn't being changed, there's nothing to do ... 17541369Sdduvall */ 17551369Sdduvall if (mode == bgep->param_loop_mode) 17561369Sdduvall return (IOC_ACK); 17571369Sdduvall 17581369Sdduvall /* 17591369Sdduvall * Validate the requested mode and prepare a suitable message 17601369Sdduvall * to explain the link down/up cycle that the change will 17611369Sdduvall * probably induce ... 17621369Sdduvall */ 17631369Sdduvall switch (mode) { 17641369Sdduvall default: 17651369Sdduvall return (IOC_INVAL); 17661369Sdduvall 17671369Sdduvall case BGE_LOOP_NONE: 17681369Sdduvall case BGE_LOOP_EXTERNAL_1000: 17691369Sdduvall case BGE_LOOP_EXTERNAL_100: 17701369Sdduvall case BGE_LOOP_EXTERNAL_10: 17711369Sdduvall case BGE_LOOP_INTERNAL_PHY: 17721369Sdduvall case BGE_LOOP_INTERNAL_MAC: 17731369Sdduvall break; 17741369Sdduvall } 17751369Sdduvall 17761369Sdduvall /* 17771369Sdduvall * All OK; tell the caller to reprogram 17781369Sdduvall * the PHY and/or MAC for the new mode ... 17791369Sdduvall */ 17801369Sdduvall bgep->param_loop_mode = mode; 17811369Sdduvall return (IOC_RESTART_ACK); 17821369Sdduvall } 17831369Sdduvall 17841369Sdduvall static enum ioc_reply 17851369Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 17861369Sdduvall { 17871369Sdduvall lb_info_sz_t *lbsp; 17881369Sdduvall lb_property_t *lbpp; 17891369Sdduvall uint32_t *lbmp; 17901369Sdduvall int cmd; 17911369Sdduvall 17921369Sdduvall _NOTE(ARGUNUSED(wq)) 17931369Sdduvall 17941369Sdduvall /* 17951369Sdduvall * Validate format of ioctl 17961369Sdduvall */ 17971369Sdduvall if (mp->b_cont == NULL) 17981369Sdduvall return (IOC_INVAL); 17991369Sdduvall 18001369Sdduvall cmd = iocp->ioc_cmd; 18011369Sdduvall switch (cmd) { 18021369Sdduvall default: 18031369Sdduvall /* NOTREACHED */ 18041369Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 18051369Sdduvall return (IOC_INVAL); 18061369Sdduvall 18071369Sdduvall case LB_GET_INFO_SIZE: 18081369Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 18091369Sdduvall return (IOC_INVAL); 18107099Syt223700 lbsp = (void *)mp->b_cont->b_rptr; 18111369Sdduvall *lbsp = sizeof (loopmodes); 18121369Sdduvall return (IOC_REPLY); 18131369Sdduvall 18141369Sdduvall case LB_GET_INFO: 18151369Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 18161369Sdduvall return (IOC_INVAL); 18177099Syt223700 lbpp = (void *)mp->b_cont->b_rptr; 18181369Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 18191369Sdduvall return (IOC_REPLY); 18201369Sdduvall 18211369Sdduvall case LB_GET_MODE: 18221369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 18231369Sdduvall return (IOC_INVAL); 18247099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 18251369Sdduvall *lbmp = bgep->param_loop_mode; 18261369Sdduvall return (IOC_REPLY); 18271369Sdduvall 18281369Sdduvall case LB_SET_MODE: 18291369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 18301369Sdduvall return (IOC_INVAL); 18317099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 18321369Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 18331369Sdduvall } 18341369Sdduvall } 18351369Sdduvall 18361369Sdduvall /* 18371369Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 18381369Sdduvall */ 18391369Sdduvall static void 18401369Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 18411369Sdduvall { 18421369Sdduvall bge_t *bgep = arg; 18431369Sdduvall struct iocblk *iocp; 18441369Sdduvall enum ioc_reply status; 18451369Sdduvall boolean_t need_privilege; 18461369Sdduvall int err; 18471369Sdduvall int cmd; 18481369Sdduvall 18491369Sdduvall /* 18501369Sdduvall * Validate the command before bothering with the mutex ... 18511369Sdduvall */ 18527099Syt223700 iocp = (void *)mp->b_rptr; 18531369Sdduvall iocp->ioc_error = 0; 18541369Sdduvall need_privilege = B_TRUE; 18551369Sdduvall cmd = iocp->ioc_cmd; 18561369Sdduvall switch (cmd) { 18571369Sdduvall default: 18581369Sdduvall miocnak(wq, mp, 0, EINVAL); 18591369Sdduvall return; 18601369Sdduvall 18611369Sdduvall case BGE_MII_READ: 18621369Sdduvall case BGE_MII_WRITE: 18631369Sdduvall case BGE_SEE_READ: 18641369Sdduvall case BGE_SEE_WRITE: 18652675Szh199473 case BGE_FLASH_READ: 18662675Szh199473 case BGE_FLASH_WRITE: 18671369Sdduvall case BGE_DIAG: 18681369Sdduvall case BGE_PEEK: 18691369Sdduvall case BGE_POKE: 18701369Sdduvall case BGE_PHY_RESET: 18711369Sdduvall case BGE_SOFT_RESET: 18721369Sdduvall case BGE_HARD_RESET: 18731369Sdduvall break; 18741369Sdduvall 18751369Sdduvall case LB_GET_INFO_SIZE: 18761369Sdduvall case LB_GET_INFO: 18771369Sdduvall case LB_GET_MODE: 18781369Sdduvall need_privilege = B_FALSE; 18791369Sdduvall /* FALLTHRU */ 18801369Sdduvall case LB_SET_MODE: 18811369Sdduvall break; 18821369Sdduvall 18831369Sdduvall } 18841369Sdduvall 18851369Sdduvall if (need_privilege) { 18861369Sdduvall /* 18871369Sdduvall * Check for specific net_config privilege on Solaris 10+. 18881369Sdduvall */ 18892681Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 18901369Sdduvall if (err != 0) { 18911369Sdduvall miocnak(wq, mp, 0, err); 18921369Sdduvall return; 18931369Sdduvall } 18941369Sdduvall } 18951369Sdduvall 18961369Sdduvall mutex_enter(bgep->genlock); 18971865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 18981865Sdilpreet /* can happen during autorecovery */ 18991865Sdilpreet mutex_exit(bgep->genlock); 19001865Sdilpreet miocnak(wq, mp, 0, EIO); 19011865Sdilpreet return; 19021865Sdilpreet } 19031369Sdduvall 19041369Sdduvall switch (cmd) { 19051369Sdduvall default: 19061369Sdduvall _NOTE(NOTREACHED) 19071369Sdduvall status = IOC_INVAL; 19081369Sdduvall break; 19091369Sdduvall 19101369Sdduvall case BGE_MII_READ: 19111369Sdduvall case BGE_MII_WRITE: 19121369Sdduvall case BGE_SEE_READ: 19131369Sdduvall case BGE_SEE_WRITE: 19142675Szh199473 case BGE_FLASH_READ: 19152675Szh199473 case BGE_FLASH_WRITE: 19161369Sdduvall case BGE_DIAG: 19171369Sdduvall case BGE_PEEK: 19181369Sdduvall case BGE_POKE: 19191369Sdduvall case BGE_PHY_RESET: 19201369Sdduvall case BGE_SOFT_RESET: 19211369Sdduvall case BGE_HARD_RESET: 19221369Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 19231369Sdduvall break; 19241369Sdduvall 19251369Sdduvall case LB_GET_INFO_SIZE: 19261369Sdduvall case LB_GET_INFO: 19271369Sdduvall case LB_GET_MODE: 19281369Sdduvall case LB_SET_MODE: 19291369Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 19301369Sdduvall break; 19311369Sdduvall 19321369Sdduvall } 19331369Sdduvall 19341369Sdduvall /* 19351369Sdduvall * Do we need to reprogram the PHY and/or the MAC? 19361369Sdduvall * Do it now, while we still have the mutex. 19371369Sdduvall * 19381369Sdduvall * Note: update the PHY first, 'cos it controls the 19391369Sdduvall * speed/duplex parameters that the MAC code uses. 19401369Sdduvall */ 19411369Sdduvall switch (status) { 19421369Sdduvall case IOC_RESTART_REPLY: 19431369Sdduvall case IOC_RESTART_ACK: 19445903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 19451865Sdilpreet status = IOC_INVAL; 19461369Sdduvall break; 19471369Sdduvall } 19481369Sdduvall 19491865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 19501865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 19511865Sdilpreet status = IOC_INVAL; 19521865Sdilpreet } 19531865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 19541865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 19551865Sdilpreet status = IOC_INVAL; 19561865Sdilpreet } 19571369Sdduvall mutex_exit(bgep->genlock); 19581369Sdduvall 19591369Sdduvall /* 19601369Sdduvall * Finally, decide how to reply 19611369Sdduvall */ 19621369Sdduvall switch (status) { 19631369Sdduvall default: 19641369Sdduvall case IOC_INVAL: 19651369Sdduvall /* 19661369Sdduvall * Error, reply with a NAK and EINVAL or the specified error 19671369Sdduvall */ 19681369Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 19694588Sml149210 EINVAL : iocp->ioc_error); 19701369Sdduvall break; 19711369Sdduvall 19721369Sdduvall case IOC_DONE: 19731369Sdduvall /* 19741369Sdduvall * OK, reply already sent 19751369Sdduvall */ 19761369Sdduvall break; 19771369Sdduvall 19781369Sdduvall case IOC_RESTART_ACK: 19791369Sdduvall case IOC_ACK: 19801369Sdduvall /* 19811369Sdduvall * OK, reply with an ACK 19821369Sdduvall */ 19831369Sdduvall miocack(wq, mp, 0, 0); 19841369Sdduvall break; 19851369Sdduvall 19861369Sdduvall case IOC_RESTART_REPLY: 19871369Sdduvall case IOC_REPLY: 19881369Sdduvall /* 19891369Sdduvall * OK, send prepared reply as ACK or NAK 19901369Sdduvall */ 19911369Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 19924588Sml149210 M_IOCACK : M_IOCNAK; 19931369Sdduvall qreply(wq, mp); 19941369Sdduvall break; 19951369Sdduvall } 19961369Sdduvall } 19971369Sdduvall 19981369Sdduvall /* 19991369Sdduvall * ========== Per-instance setup/teardown code ========== 20001369Sdduvall */ 20011369Sdduvall 20021369Sdduvall #undef BGE_DBG 20031369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 20043334Sgs150176 /* 20053334Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 20063334Sgs150176 */ 20073334Sgs150176 static int 20083334Sgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 20093334Sgs150176 uint_t dma_flags, dma_area_t *dma_p) 20103334Sgs150176 { 20113334Sgs150176 caddr_t va; 20123334Sgs150176 int err; 20133334Sgs150176 20143334Sgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 20154588Sml149210 (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 20163334Sgs150176 20173334Sgs150176 /* 20183334Sgs150176 * Allocate handle 20193334Sgs150176 */ 20203334Sgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 20214588Sml149210 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 20223334Sgs150176 if (err != DDI_SUCCESS) 20233334Sgs150176 return (DDI_FAILURE); 20243334Sgs150176 20253334Sgs150176 /* 20263334Sgs150176 * Allocate memory 20273334Sgs150176 */ 20283334Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 20294588Sml149210 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, 20304588Sml149210 &dma_p->acc_hdl); 20313334Sgs150176 if (err != DDI_SUCCESS) 20323334Sgs150176 return (DDI_FAILURE); 20333334Sgs150176 20343334Sgs150176 /* 20353334Sgs150176 * Bind the two together 20363334Sgs150176 */ 20373334Sgs150176 dma_p->mem_va = va; 20383334Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 20394588Sml149210 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 20404588Sml149210 &dma_p->cookie, &dma_p->ncookies); 20413334Sgs150176 20423334Sgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 20434588Sml149210 dma_p->alength, err, dma_p->ncookies)); 20443334Sgs150176 20453334Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 20463334Sgs150176 return (DDI_FAILURE); 20473334Sgs150176 20483334Sgs150176 dma_p->nslots = ~0U; 20493334Sgs150176 dma_p->size = ~0U; 20503334Sgs150176 dma_p->token = ~0U; 20513334Sgs150176 dma_p->offset = 0; 20523334Sgs150176 return (DDI_SUCCESS); 20533334Sgs150176 } 20543334Sgs150176 20553334Sgs150176 /* 20563334Sgs150176 * Free one allocated area of DMAable memory 20573334Sgs150176 */ 20583334Sgs150176 static void 20593334Sgs150176 bge_free_dma_mem(dma_area_t *dma_p) 20603334Sgs150176 { 20613334Sgs150176 if (dma_p->dma_hdl != NULL) { 20623334Sgs150176 if (dma_p->ncookies) { 20633334Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 20643334Sgs150176 dma_p->ncookies = 0; 20653334Sgs150176 } 20663334Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 20673334Sgs150176 dma_p->dma_hdl = NULL; 20683334Sgs150176 } 20693334Sgs150176 20703334Sgs150176 if (dma_p->acc_hdl != NULL) { 20713334Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 20723334Sgs150176 dma_p->acc_hdl = NULL; 20733334Sgs150176 } 20743334Sgs150176 } 20751369Sdduvall /* 20761369Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 20771369Sdduvall * updating the chunk descriptor accordingly. The size of the slice 20781369Sdduvall * is given by the product of the <qty> and <size> parameters. 20791369Sdduvall */ 20801369Sdduvall static void 20811369Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 20821369Sdduvall uint32_t qty, uint32_t size) 20831369Sdduvall { 20841369Sdduvall static uint32_t sequence = 0xbcd5704a; 20851369Sdduvall size_t totsize; 20861369Sdduvall 20871369Sdduvall totsize = qty*size; 20881369Sdduvall ASSERT(totsize <= chunk->alength); 20891369Sdduvall 20901369Sdduvall *slice = *chunk; 20911369Sdduvall slice->nslots = qty; 20921369Sdduvall slice->size = size; 20931369Sdduvall slice->alength = totsize; 20941369Sdduvall slice->token = ++sequence; 20951369Sdduvall 20961369Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 20971369Sdduvall chunk->alength -= totsize; 20981369Sdduvall chunk->offset += totsize; 20991369Sdduvall chunk->cookie.dmac_laddress += totsize; 21001369Sdduvall chunk->cookie.dmac_size -= totsize; 21011369Sdduvall } 21021369Sdduvall 21031369Sdduvall /* 21041369Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 21051369Sdduvall * the information in the <dma_area> descriptors that it contains 21061369Sdduvall * to set up all the other fields. This routine should be called 21071369Sdduvall * only once for each ring. 21081369Sdduvall */ 21091369Sdduvall static void 21101369Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 21111369Sdduvall { 21121369Sdduvall buff_ring_t *brp; 21131369Sdduvall bge_status_t *bsp; 21141369Sdduvall sw_rbd_t *srbdp; 21151369Sdduvall dma_area_t pbuf; 21161369Sdduvall uint32_t bufsize; 21171369Sdduvall uint32_t nslots; 21181369Sdduvall uint32_t slot; 21191369Sdduvall uint32_t split; 21201369Sdduvall 21211369Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 21221369Sdduvall NIC_MEM_SHADOW_BUFF_STD, 21231369Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 21241369Sdduvall NIC_MEM_SHADOW_BUFF_MINI 21251369Sdduvall }; 21261369Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 21271369Sdduvall RECV_STD_PROD_INDEX_REG, 21281369Sdduvall RECV_JUMBO_PROD_INDEX_REG, 21291369Sdduvall RECV_MINI_PROD_INDEX_REG 21301369Sdduvall }; 21311369Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 21321369Sdduvall STATUS_STD_BUFF_CONS_INDEX, 21331369Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 21341369Sdduvall STATUS_MINI_BUFF_CONS_INDEX 21351369Sdduvall }; 21361369Sdduvall 21371369Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 21384588Sml149210 (void *)bgep, ring)); 21391369Sdduvall 21401369Sdduvall brp = &bgep->buff[ring]; 21411369Sdduvall nslots = brp->desc.nslots; 21421369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 21431369Sdduvall bufsize = brp->buf[0].size; 21441369Sdduvall 21451369Sdduvall /* 21461369Sdduvall * Set up the copy of the h/w RCB 21471369Sdduvall * 21481369Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 21491369Sdduvall * field holds the number of slots), in a Receive Buffer Ring 21501369Sdduvall * this field indicates the size of each buffer in the ring. 21511369Sdduvall */ 21521369Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 21537099Syt223700 brp->hw_rcb.max_len = (uint16_t)bufsize; 21541369Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21551369Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 21561369Sdduvall 21571369Sdduvall /* 21581369Sdduvall * Other one-off initialisation of per-ring data 21591369Sdduvall */ 21601369Sdduvall brp->bgep = bgep; 21611369Sdduvall bsp = DMA_VPTR(bgep->status_block); 21621369Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 21631369Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 21641369Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 21651369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 21661369Sdduvall 21671369Sdduvall /* 21681369Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 21691369Sdduvall */ 21701369Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 21711369Sdduvall brp->sw_rbds = srbdp; 21721369Sdduvall 21731369Sdduvall /* 21741369Sdduvall * Now initialise each array element once and for all 21751369Sdduvall */ 21761369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 21771369Sdduvall pbuf = brp->buf[split]; 21781369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 21791369Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 21801369Sdduvall ASSERT(pbuf.alength == 0); 21811369Sdduvall } 21821369Sdduvall } 21831369Sdduvall 21841369Sdduvall /* 21851369Sdduvall * Clean up initialisation done above before the memory is freed 21861369Sdduvall */ 21871369Sdduvall static void 21881369Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 21891369Sdduvall { 21901369Sdduvall buff_ring_t *brp; 21911369Sdduvall sw_rbd_t *srbdp; 21921369Sdduvall 21931369Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 21944588Sml149210 (void *)bgep, ring)); 21951369Sdduvall 21961369Sdduvall brp = &bgep->buff[ring]; 21971369Sdduvall srbdp = brp->sw_rbds; 21981369Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 21991369Sdduvall 22001369Sdduvall mutex_destroy(brp->rf_lock); 22011369Sdduvall } 22021369Sdduvall 22031369Sdduvall /* 22041369Sdduvall * Initialise the specified Receive (Return) Ring, using the 22051369Sdduvall * information in the <dma_area> descriptors that it contains 22061369Sdduvall * to set up all the other fields. This routine should be called 22071369Sdduvall * only once for each ring. 22081369Sdduvall */ 22091369Sdduvall static void 22101369Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 22111369Sdduvall { 22121369Sdduvall recv_ring_t *rrp; 22131369Sdduvall bge_status_t *bsp; 22141369Sdduvall uint32_t nslots; 22151369Sdduvall 22161369Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 22174588Sml149210 (void *)bgep, ring)); 22181369Sdduvall 22191369Sdduvall /* 22201369Sdduvall * The chip architecture requires that receive return rings have 22211369Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 22221369Sdduvall */ 22231369Sdduvall rrp = &bgep->recv[ring]; 22241369Sdduvall nslots = rrp->desc.nslots; 22251369Sdduvall ASSERT(nslots == 0 || nslots == 512 || 22264588Sml149210 nslots == 1024 || nslots == 2048); 22271369Sdduvall 22281369Sdduvall /* 22291369Sdduvall * Set up the copy of the h/w RCB 22301369Sdduvall */ 22311369Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 22327099Syt223700 rrp->hw_rcb.max_len = (uint16_t)nslots; 22331369Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 22341369Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 22351369Sdduvall 22361369Sdduvall /* 22371369Sdduvall * Other one-off initialisation of per-ring data 22381369Sdduvall */ 22391369Sdduvall rrp->bgep = bgep; 22401369Sdduvall bsp = DMA_VPTR(bgep->status_block); 22411369Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 22421369Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 22431369Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 22441369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22451369Sdduvall } 22461369Sdduvall 22471369Sdduvall 22481369Sdduvall /* 22491369Sdduvall * Clean up initialisation done above before the memory is freed 22501369Sdduvall */ 22511369Sdduvall static void 22521369Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 22531369Sdduvall { 22541369Sdduvall recv_ring_t *rrp; 22551369Sdduvall 22561369Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 22574588Sml149210 (void *)bgep, ring)); 22581369Sdduvall 22591369Sdduvall rrp = &bgep->recv[ring]; 22601369Sdduvall if (rrp->rx_softint) 22611369Sdduvall ddi_remove_softintr(rrp->rx_softint); 22621369Sdduvall mutex_destroy(rrp->rx_lock); 22631369Sdduvall } 22641369Sdduvall 22651369Sdduvall /* 22661369Sdduvall * Initialise the specified Send Ring, using the information in the 22671369Sdduvall * <dma_area> descriptors that it contains to set up all the other 22681369Sdduvall * fields. This routine should be called only once for each ring. 22691369Sdduvall */ 22701369Sdduvall static void 22711369Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 22721369Sdduvall { 22731369Sdduvall send_ring_t *srp; 22741369Sdduvall bge_status_t *bsp; 22751369Sdduvall sw_sbd_t *ssbdp; 22761369Sdduvall dma_area_t desc; 22771369Sdduvall dma_area_t pbuf; 22781369Sdduvall uint32_t nslots; 22791369Sdduvall uint32_t slot; 22801369Sdduvall uint32_t split; 22813334Sgs150176 sw_txbuf_t *txbuf; 22821369Sdduvall 22831369Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 22844588Sml149210 (void *)bgep, ring)); 22851369Sdduvall 22861369Sdduvall /* 22871369Sdduvall * The chip architecture requires that host-based send rings 22881369Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 22891369Sdduvall */ 22901369Sdduvall srp = &bgep->send[ring]; 22911369Sdduvall nslots = srp->desc.nslots; 22921369Sdduvall ASSERT(nslots == 0 || nslots == 512); 22931369Sdduvall 22941369Sdduvall /* 22951369Sdduvall * Set up the copy of the h/w RCB 22961369Sdduvall */ 22971369Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 22987099Syt223700 srp->hw_rcb.max_len = (uint16_t)nslots; 22991369Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 23001369Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 23011369Sdduvall 23021369Sdduvall /* 23031369Sdduvall * Other one-off initialisation of per-ring data 23041369Sdduvall */ 23051369Sdduvall srp->bgep = bgep; 23061369Sdduvall bsp = DMA_VPTR(bgep->status_block); 23071369Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 23081369Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 23091369Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 23101369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 23113334Sgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER, 23123334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 23133334Sgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER, 23143334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 23151369Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 23161369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 23173334Sgs150176 if (nslots == 0) 23183334Sgs150176 return; 23191369Sdduvall 23201369Sdduvall /* 23211369Sdduvall * Allocate the array of s/w Send Buffer Descriptors 23221369Sdduvall */ 23231369Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 23243334Sgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP); 23253334Sgs150176 srp->txbuf_head = 23263334Sgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP); 23273334Sgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP); 23281369Sdduvall srp->sw_sbds = ssbdp; 23293334Sgs150176 srp->txbuf = txbuf; 23303334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 23313334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 23323334Sgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT) 23333334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO; 23343334Sgs150176 else 23353334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY; 23363334Sgs150176 srp->tx_array = 1; 23371369Sdduvall 23381369Sdduvall /* 23393334Sgs150176 * Chunk tx desc area 23401369Sdduvall */ 23411369Sdduvall desc = srp->desc; 23423334Sgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) { 23433334Sgs150176 bge_slice_chunk(&ssbdp->desc, &desc, 1, 23443334Sgs150176 sizeof (bge_sbd_t)); 23453334Sgs150176 } 23463334Sgs150176 ASSERT(desc.alength == 0); 23473334Sgs150176 23483334Sgs150176 /* 23493334Sgs150176 * Chunk tx buffer area 23503334Sgs150176 */ 23511369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 23523334Sgs150176 pbuf = srp->buf[0][split]; 23533334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 23543334Sgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1, 23553334Sgs150176 bgep->chipid.snd_buff_size); 23563334Sgs150176 txbuf++; 23571369Sdduvall } 23581369Sdduvall ASSERT(pbuf.alength == 0); 23591369Sdduvall } 23601369Sdduvall } 23611369Sdduvall 23621369Sdduvall /* 23631369Sdduvall * Clean up initialisation done above before the memory is freed 23641369Sdduvall */ 23651369Sdduvall static void 23661369Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 23671369Sdduvall { 23681369Sdduvall send_ring_t *srp; 23693334Sgs150176 uint32_t array; 23703334Sgs150176 uint32_t split; 23713334Sgs150176 uint32_t nslots; 23721369Sdduvall 23731369Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 23744588Sml149210 (void *)bgep, ring)); 23751369Sdduvall 23761369Sdduvall srp = &bgep->send[ring]; 23773334Sgs150176 mutex_destroy(srp->tc_lock); 23783334Sgs150176 mutex_destroy(srp->freetxbuf_lock); 23793334Sgs150176 mutex_destroy(srp->txbuf_lock); 23801369Sdduvall mutex_destroy(srp->tx_lock); 23813334Sgs150176 nslots = srp->desc.nslots; 23823334Sgs150176 if (nslots == 0) 23833334Sgs150176 return; 23843334Sgs150176 23853334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 23863334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 23873334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 23883334Sgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds)); 23893334Sgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head)); 23903334Sgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf)); 23913334Sgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp)); 23923334Sgs150176 srp->sw_sbds = NULL; 23933334Sgs150176 srp->txbuf_head = NULL; 23943334Sgs150176 srp->txbuf = NULL; 23953334Sgs150176 srp->pktp = NULL; 23961369Sdduvall } 23971369Sdduvall 23981369Sdduvall /* 23991369Sdduvall * Initialise all transmit, receive, and buffer rings. 24001369Sdduvall */ 24011865Sdilpreet void 24021369Sdduvall bge_init_rings(bge_t *bgep) 24031369Sdduvall { 24043334Sgs150176 uint32_t ring; 24051369Sdduvall 24061369Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 24071369Sdduvall 24081369Sdduvall /* 24091369Sdduvall * Perform one-off initialisation of each ring ... 24101369Sdduvall */ 24111369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 24121369Sdduvall bge_init_send_ring(bgep, ring); 24131369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 24141369Sdduvall bge_init_recv_ring(bgep, ring); 24151369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 24161369Sdduvall bge_init_buff_ring(bgep, ring); 24171369Sdduvall } 24181369Sdduvall 24191369Sdduvall /* 24201369Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 24211369Sdduvall */ 24221865Sdilpreet void 24231369Sdduvall bge_fini_rings(bge_t *bgep) 24241369Sdduvall { 24253334Sgs150176 uint32_t ring; 24261369Sdduvall 24271369Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 24281369Sdduvall 24291369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 24301369Sdduvall bge_fini_buff_ring(bgep, ring); 24311369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 24321369Sdduvall bge_fini_recv_ring(bgep, ring); 24331369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 24341369Sdduvall bge_fini_send_ring(bgep, ring); 24351369Sdduvall } 24361369Sdduvall 24371369Sdduvall /* 24383334Sgs150176 * Called from the bge_m_stop() to free the tx buffers which are 24393334Sgs150176 * allocated from the tx process. 24401369Sdduvall */ 24413334Sgs150176 void 24423334Sgs150176 bge_free_txbuf_arrays(send_ring_t *srp) 24431369Sdduvall { 24443334Sgs150176 uint32_t array; 24453334Sgs150176 uint32_t split; 24463334Sgs150176 24473334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 24481369Sdduvall 24491369Sdduvall /* 24503334Sgs150176 * Free the extra tx buffer DMA area 24511369Sdduvall */ 24523334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 24533334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 24543334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 24551369Sdduvall 24561369Sdduvall /* 24573334Sgs150176 * Restore initial tx buffer numbers 24581369Sdduvall */ 24593334Sgs150176 srp->tx_array = 1; 24603334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 24613334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 24623334Sgs150176 srp->tx_flow = 0; 24633334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 24641369Sdduvall } 24651369Sdduvall 24661369Sdduvall /* 24673334Sgs150176 * Called from tx process to allocate more tx buffers 24681369Sdduvall */ 24693334Sgs150176 bge_queue_item_t * 24703334Sgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp) 24711369Sdduvall { 24723334Sgs150176 bge_queue_t *txbuf_queue; 24733334Sgs150176 bge_queue_item_t *txbuf_item_last; 24743334Sgs150176 bge_queue_item_t *txbuf_item; 24753334Sgs150176 bge_queue_item_t *txbuf_item_rtn; 24763334Sgs150176 sw_txbuf_t *txbuf; 24773334Sgs150176 dma_area_t area; 24783334Sgs150176 size_t txbuffsize; 24793334Sgs150176 uint32_t slot; 24803334Sgs150176 uint32_t array; 24813334Sgs150176 uint32_t split; 24823334Sgs150176 uint32_t err; 24833334Sgs150176 24843334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 24853334Sgs150176 24863334Sgs150176 array = srp->tx_array; 24873334Sgs150176 if (array >= srp->tx_array_max) 24883334Sgs150176 return (NULL); 24893334Sgs150176 24903334Sgs150176 /* 24913334Sgs150176 * Allocate memory & handles for TX buffers 24923334Sgs150176 */ 24933334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 24943334Sgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0); 24953334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 24963334Sgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 24974588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 24984588Sml149210 &srp->buf[array][split]); 24993334Sgs150176 if (err != DDI_SUCCESS) { 25003334Sgs150176 /* Free the last already allocated OK chunks */ 25013334Sgs150176 for (slot = 0; slot <= split; ++slot) 25023334Sgs150176 bge_free_dma_mem(&srp->buf[array][slot]); 25033334Sgs150176 srp->tx_alloc_fail++; 25043334Sgs150176 return (NULL); 25051369Sdduvall } 25063334Sgs150176 } 25073334Sgs150176 25083334Sgs150176 /* 25093334Sgs150176 * Chunk tx buffer area 25103334Sgs150176 */ 25113334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 25123334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 25133334Sgs150176 area = srp->buf[array][split]; 25143334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 25153334Sgs150176 bge_slice_chunk(&txbuf->buf, &area, 1, 25163334Sgs150176 bgep->chipid.snd_buff_size); 25173334Sgs150176 txbuf++; 25183334Sgs150176 } 25191369Sdduvall } 25201369Sdduvall 25213334Sgs150176 /* 25223334Sgs150176 * Add above buffers to the tx buffer pop queue 25233334Sgs150176 */ 25243334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 25253334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 25263334Sgs150176 txbuf_item_last = NULL; 25273334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) { 25283334Sgs150176 txbuf_item->item = txbuf; 25293334Sgs150176 txbuf_item->next = txbuf_item_last; 25303334Sgs150176 txbuf_item_last = txbuf_item; 25313334Sgs150176 txbuf++; 25323334Sgs150176 txbuf_item++; 25331369Sdduvall } 25343334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 25353334Sgs150176 txbuf_item_rtn = txbuf_item; 25363334Sgs150176 txbuf_item++; 25373334Sgs150176 txbuf_queue = srp->txbuf_pop_queue; 25383334Sgs150176 mutex_enter(txbuf_queue->lock); 25393334Sgs150176 txbuf_item->next = txbuf_queue->head; 25403334Sgs150176 txbuf_queue->head = txbuf_item_last; 25413334Sgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1; 25423334Sgs150176 mutex_exit(txbuf_queue->lock); 25433334Sgs150176 25443334Sgs150176 srp->tx_array++; 25453334Sgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM; 25463334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 25473334Sgs150176 25483334Sgs150176 return (txbuf_item_rtn); 25491369Sdduvall } 25501369Sdduvall 25511369Sdduvall /* 25521369Sdduvall * This function allocates all the transmit and receive buffers 25533334Sgs150176 * and descriptors, in four chunks. 25541369Sdduvall */ 25551865Sdilpreet int 25561369Sdduvall bge_alloc_bufs(bge_t *bgep) 25571369Sdduvall { 25581369Sdduvall dma_area_t area; 25591369Sdduvall size_t rxbuffsize; 25601369Sdduvall size_t txbuffsize; 25611369Sdduvall size_t rxbuffdescsize; 25621369Sdduvall size_t rxdescsize; 25631369Sdduvall size_t txdescsize; 25643334Sgs150176 uint32_t ring; 25653334Sgs150176 uint32_t rx_rings = bgep->chipid.rx_rings; 25663334Sgs150176 uint32_t tx_rings = bgep->chipid.tx_rings; 25671369Sdduvall int split; 25681369Sdduvall int err; 25691369Sdduvall 25701369Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 25714588Sml149210 (void *)bgep)); 25721369Sdduvall 25731908Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size; 25741369Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 25751369Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 25761369Sdduvall 25773334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 25781369Sdduvall txbuffsize *= tx_rings; 25791369Sdduvall 25801369Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 25811369Sdduvall rxdescsize *= sizeof (bge_rbd_t); 25821369Sdduvall 25831369Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 25841369Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 25851369Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 25861369Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 25871369Sdduvall 25881369Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 25891369Sdduvall txdescsize *= sizeof (bge_sbd_t); 25901369Sdduvall txdescsize += sizeof (bge_statistics_t); 25911369Sdduvall txdescsize += sizeof (bge_status_t); 25921369Sdduvall txdescsize += BGE_STATUS_PADDING; 25931369Sdduvall 25941369Sdduvall /* 25953907Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers 25963907Szh199473 */ 25973907Szh199473 if (bge_relaxed_ordering) 25983907Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING; 25993907Szh199473 26003907Szh199473 /* 26011369Sdduvall * Allocate memory & handles for RX buffers 26021369Sdduvall */ 26031369Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 26041369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26051369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 26064588Sml149210 &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 26074588Sml149210 &bgep->rx_buff[split]); 26081369Sdduvall if (err != DDI_SUCCESS) 26091369Sdduvall return (DDI_FAILURE); 26101369Sdduvall } 26111369Sdduvall 26121369Sdduvall /* 26131369Sdduvall * Allocate memory & handles for TX buffers 26141369Sdduvall */ 26151369Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 26161369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26171369Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 26184588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 26194588Sml149210 &bgep->tx_buff[split]); 26201369Sdduvall if (err != DDI_SUCCESS) 26211369Sdduvall return (DDI_FAILURE); 26221369Sdduvall } 26231369Sdduvall 26243907Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING; 26253907Szh199473 26261369Sdduvall /* 26271369Sdduvall * Allocate memory & handles for receive return rings 26281369Sdduvall */ 26291369Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 26301369Sdduvall for (split = 0; split < rx_rings; ++split) { 26311369Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 26324588Sml149210 &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 26334588Sml149210 &bgep->rx_desc[split]); 26341369Sdduvall if (err != DDI_SUCCESS) 26351369Sdduvall return (DDI_FAILURE); 26361369Sdduvall } 26371369Sdduvall 26381369Sdduvall /* 26391369Sdduvall * Allocate memory & handles for buffer (producer) descriptor rings 26401369Sdduvall */ 26411369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 26424588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 26431369Sdduvall if (err != DDI_SUCCESS) 26441369Sdduvall return (DDI_FAILURE); 26451369Sdduvall 26461369Sdduvall /* 26471369Sdduvall * Allocate memory & handles for TX descriptor rings, 26481369Sdduvall * status block, and statistics area 26491369Sdduvall */ 26501369Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 26514588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 26521369Sdduvall if (err != DDI_SUCCESS) 26531369Sdduvall return (DDI_FAILURE); 26541369Sdduvall 26551369Sdduvall /* 26561369Sdduvall * Now carve up each of the allocated areas ... 26571369Sdduvall */ 26581369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26591369Sdduvall area = bgep->rx_buff[split]; 26601369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 26614588Sml149210 &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 26624588Sml149210 bgep->chipid.std_buf_size); 26631369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 26644588Sml149210 &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 26654588Sml149210 bgep->chipid.recv_jumbo_size); 26661369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 26674588Sml149210 &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 26684588Sml149210 BGE_MINI_BUFF_SIZE); 26691369Sdduvall } 26701369Sdduvall 26711369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26721369Sdduvall area = bgep->tx_buff[split]; 26731369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 26743334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 26754588Sml149210 &area, BGE_SEND_BUF_NUM/BGE_SPLIT, 26764588Sml149210 bgep->chipid.snd_buff_size); 26771369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 26783334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 26794588Sml149210 &area, 0, bgep->chipid.snd_buff_size); 26801369Sdduvall } 26811369Sdduvall 26821369Sdduvall for (ring = 0; ring < rx_rings; ++ring) 26831369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 26844588Sml149210 bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 26851369Sdduvall 26861369Sdduvall area = bgep->rx_desc[rx_rings]; 26871369Sdduvall for (; ring < BGE_RECV_RINGS_MAX; ++ring) 26881369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 26894588Sml149210 0, sizeof (bge_rbd_t)); 26901369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 26914588Sml149210 BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 26921369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 26934588Sml149210 bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 26941369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 26954588Sml149210 BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 26961369Sdduvall ASSERT(area.alength == 0); 26971369Sdduvall 26981369Sdduvall area = bgep->tx_desc; 26991369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 27001369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 27014588Sml149210 BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 27021369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 27031369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 27044588Sml149210 0, sizeof (bge_sbd_t)); 27051369Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 27061369Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 27071369Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 27081369Sdduvall DMA_ZERO(bgep->status_block); 27091369Sdduvall 27101369Sdduvall return (DDI_SUCCESS); 27111369Sdduvall } 27121369Sdduvall 27131369Sdduvall /* 27141369Sdduvall * This routine frees the transmit and receive buffers and descriptors. 27151369Sdduvall * Make sure the chip is stopped before calling it! 27161369Sdduvall */ 27171865Sdilpreet void 27181369Sdduvall bge_free_bufs(bge_t *bgep) 27191369Sdduvall { 27201369Sdduvall int split; 27211369Sdduvall 27221369Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 27234588Sml149210 (void *)bgep)); 27241369Sdduvall 27251369Sdduvall bge_free_dma_mem(&bgep->tx_desc); 27261369Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 27271369Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 27281369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 27291369Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 27301369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 27311369Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 27321369Sdduvall } 27331369Sdduvall 27341369Sdduvall /* 27351369Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 27361369Sdduvall */ 27371369Sdduvall 27381369Sdduvall static void 27391369Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 27401369Sdduvall { 27411369Sdduvall struct ether_addr sysaddr; 27421369Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 27431369Sdduvall uchar_t *bytes; 27441369Sdduvall int *ints; 27451369Sdduvall uint_t nelts; 27461369Sdduvall int err; 27471369Sdduvall 27481369Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 27494588Sml149210 (void *)bgep)); 27501369Sdduvall 27511369Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 27524588Sml149210 cidp->hw_mac_addr, 27534588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27544588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27551369Sdduvall 27561369Sdduvall /* 27571369Sdduvall * The "vendor's factory-set address" may already have 27581369Sdduvall * been extracted from the chip, but if the property 27591369Sdduvall * "local-mac-address" is set we use that instead. It 27601369Sdduvall * will normally be set by OBP, but it could also be 27611369Sdduvall * specified in a .conf file(!) 27621369Sdduvall * 27631369Sdduvall * There doesn't seem to be a way to define byte-array 27641369Sdduvall * properties in a .conf, so we check whether it looks 27651369Sdduvall * like an array of 6 ints instead. 27661369Sdduvall * 27671369Sdduvall * Then, we check whether it looks like an array of 6 27681369Sdduvall * bytes (which it should, if OBP set it). If we can't 27691369Sdduvall * make sense of it either way, we'll ignore it. 27701369Sdduvall */ 27711369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 27724588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 27731369Sdduvall if (err == DDI_PROP_SUCCESS) { 27741369Sdduvall if (nelts == ETHERADDRL) { 27751369Sdduvall while (nelts--) 27761369Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 27772331Skrgopi cidp->vendor_addr.set = B_TRUE; 27781369Sdduvall } 27791369Sdduvall ddi_prop_free(ints); 27801369Sdduvall } 27811369Sdduvall 27821369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 27834588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 27841369Sdduvall if (err == DDI_PROP_SUCCESS) { 27851369Sdduvall if (nelts == ETHERADDRL) { 27861369Sdduvall while (nelts--) 27871369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 27882331Skrgopi cidp->vendor_addr.set = B_TRUE; 27891369Sdduvall } 27901369Sdduvall ddi_prop_free(bytes); 27911369Sdduvall } 27921369Sdduvall 27931369Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 27944588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27954588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27961369Sdduvall 27971369Sdduvall /* 27981369Sdduvall * Look up the OBP property "local-mac-address?". Note that even 27991369Sdduvall * though its value is a string (which should be "true" or "false"), 28001369Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 28011369Sdduvall * the buffer first and then fetch the property as an untyped array; 28021369Sdduvall * this may or may not include a final NUL, but since there will 28031369Sdduvall * always be one left at the end of the buffer we can now treat it 28041369Sdduvall * as a string anyway. 28051369Sdduvall */ 28061369Sdduvall nelts = sizeof (propbuf); 28071369Sdduvall bzero(propbuf, nelts--); 28081369Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 28094588Sml149210 DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 28101369Sdduvall 28111369Sdduvall /* 28121369Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 28131369Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 28141369Sdduvall * 'local-mac-address? = false', use "the system address" instead 28151369Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 28161369Sdduvall */ 28172331Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0) 28181369Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 28191369Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 28202331Skrgopi cidp->vendor_addr.set = B_TRUE; 28211369Sdduvall } 28221369Sdduvall 28231369Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 28244588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 28254588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 28261369Sdduvall 28271369Sdduvall /* 28281369Sdduvall * Finally(!), if there's a valid "mac-address" property (created 28291369Sdduvall * if we netbooted from this interface), we must use this instead 28301369Sdduvall * of any of the above to ensure that the NFS/install server doesn't 28311369Sdduvall * get confused by the address changing as Solaris takes over! 28321369Sdduvall */ 28331369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 28344588Sml149210 DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 28351369Sdduvall if (err == DDI_PROP_SUCCESS) { 28361369Sdduvall if (nelts == ETHERADDRL) { 28371369Sdduvall while (nelts--) 28381369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 28392331Skrgopi cidp->vendor_addr.set = B_TRUE; 28401369Sdduvall } 28411369Sdduvall ddi_prop_free(bytes); 28421369Sdduvall } 28431369Sdduvall 28441369Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 28454588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 28464588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 28471369Sdduvall } 28481369Sdduvall 28491865Sdilpreet 28501865Sdilpreet /*ARGSUSED*/ 28511865Sdilpreet int 28521865Sdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 28531865Sdilpreet { 28541865Sdilpreet ddi_fm_error_t de; 28551865Sdilpreet 28561865Sdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 28571865Sdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 28581865Sdilpreet return (de.fme_status); 28591865Sdilpreet } 28601865Sdilpreet 28611865Sdilpreet /*ARGSUSED*/ 28621865Sdilpreet int 28631865Sdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 28641865Sdilpreet { 28651865Sdilpreet ddi_fm_error_t de; 28661865Sdilpreet 28671865Sdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 28681865Sdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 28691865Sdilpreet return (de.fme_status); 28701865Sdilpreet } 28711865Sdilpreet 28721865Sdilpreet /* 28731865Sdilpreet * The IO fault service error handling callback function 28741865Sdilpreet */ 28751865Sdilpreet /*ARGSUSED*/ 28761865Sdilpreet static int 28771865Sdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 28781865Sdilpreet { 28791865Sdilpreet /* 28801865Sdilpreet * as the driver can always deal with an error in any dma or 28811865Sdilpreet * access handle, we can just return the fme_status value. 28821865Sdilpreet */ 28831865Sdilpreet pci_ereport_post(dip, err, NULL); 28841865Sdilpreet return (err->fme_status); 28851865Sdilpreet } 28861865Sdilpreet 28871865Sdilpreet static void 28881865Sdilpreet bge_fm_init(bge_t *bgep) 28891865Sdilpreet { 28901865Sdilpreet ddi_iblock_cookie_t iblk; 28911865Sdilpreet 28921865Sdilpreet /* Only register with IO Fault Services if we have some capability */ 28931865Sdilpreet if (bgep->fm_capabilities) { 28941865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 28951865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 28961865Sdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 28971865Sdilpreet 28981865Sdilpreet /* Register capabilities with IO Fault Services */ 28991865Sdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 29001865Sdilpreet 29011865Sdilpreet /* 29021865Sdilpreet * Initialize pci ereport capabilities if ereport capable 29031865Sdilpreet */ 29041865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 29051865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29061865Sdilpreet pci_ereport_setup(bgep->devinfo); 29071865Sdilpreet 29081865Sdilpreet /* 29091865Sdilpreet * Register error callback if error callback capable 29101865Sdilpreet */ 29111865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29121865Sdilpreet ddi_fm_handler_register(bgep->devinfo, 29134588Sml149210 bge_fm_error_cb, (void*) bgep); 29141865Sdilpreet } else { 29151865Sdilpreet /* 29161865Sdilpreet * These fields have to be cleared of FMA if there are no 29171865Sdilpreet * FMA capabilities at runtime. 29181865Sdilpreet */ 29191865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 29201865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 29211865Sdilpreet dma_attr.dma_attr_flags = 0; 29221865Sdilpreet } 29231865Sdilpreet } 29241865Sdilpreet 29251865Sdilpreet static void 29261865Sdilpreet bge_fm_fini(bge_t *bgep) 29271865Sdilpreet { 29281865Sdilpreet /* Only unregister FMA capabilities if we registered some */ 29291865Sdilpreet if (bgep->fm_capabilities) { 29301865Sdilpreet 29311865Sdilpreet /* 29321865Sdilpreet * Release any resources allocated by pci_ereport_setup() 29331865Sdilpreet */ 29341865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 29351865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29361865Sdilpreet pci_ereport_teardown(bgep->devinfo); 29371865Sdilpreet 29381865Sdilpreet /* 29391865Sdilpreet * Un-register error callback if error callback capable 29401865Sdilpreet */ 29411865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29421865Sdilpreet ddi_fm_handler_unregister(bgep->devinfo); 29431865Sdilpreet 29441865Sdilpreet /* Unregister from IO Fault Services */ 29451865Sdilpreet ddi_fm_fini(bgep->devinfo); 29461865Sdilpreet } 29471865Sdilpreet } 29481865Sdilpreet 29491369Sdduvall static void 29501408Srandyf #ifdef BGE_IPMI_ASF 29511408Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 29521408Srandyf #else 29531369Sdduvall bge_unattach(bge_t *bgep) 29541408Srandyf #endif 29551369Sdduvall { 29561369Sdduvall BGE_TRACE(("bge_unattach($%p)", 29571369Sdduvall (void *)bgep)); 29581369Sdduvall 29591369Sdduvall /* 29601369Sdduvall * Flag that no more activity may be initiated 29611369Sdduvall */ 29621369Sdduvall bgep->progress &= ~PROGRESS_READY; 29631369Sdduvall 29641369Sdduvall /* 29651369Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 29661369Sdduvall * Clean up and free all BGE data structures 29671369Sdduvall */ 29685107Seota if (bgep->periodic_id != NULL) { 29695107Seota ddi_periodic_delete(bgep->periodic_id); 29705107Seota bgep->periodic_id = NULL; 29711369Sdduvall } 29721369Sdduvall if (bgep->progress & PROGRESS_KSTATS) 29731369Sdduvall bge_fini_kstats(bgep); 29741369Sdduvall if (bgep->progress & PROGRESS_PHY) 29751369Sdduvall bge_phys_reset(bgep); 29761369Sdduvall if (bgep->progress & PROGRESS_HWINT) { 29771369Sdduvall mutex_enter(bgep->genlock); 29781408Srandyf #ifdef BGE_IPMI_ASF 29791865Sdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 29801865Sdilpreet #else 29811865Sdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 29821865Sdilpreet #endif 29831865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 29841865Sdilpreet DDI_SERVICE_UNAFFECTED); 29851865Sdilpreet #ifdef BGE_IPMI_ASF 29861408Srandyf if (bgep->asf_enabled) { 29871408Srandyf /* 29881408Srandyf * This register has been overlaid. We restore its 29891408Srandyf * initial value here. 29901408Srandyf */ 29911408Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 29921408Srandyf BGE_NIC_DATA_SIG); 29931408Srandyf } 29941408Srandyf #endif 29951865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 29961865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 29971865Sdilpreet DDI_SERVICE_UNAFFECTED); 29981865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 29991865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 30001865Sdilpreet DDI_SERVICE_UNAFFECTED); 30011369Sdduvall mutex_exit(bgep->genlock); 30021369Sdduvall } 30031369Sdduvall if (bgep->progress & PROGRESS_INTR) { 30041865Sdilpreet bge_intr_disable(bgep); 30051369Sdduvall bge_fini_rings(bgep); 30061369Sdduvall } 30071865Sdilpreet if (bgep->progress & PROGRESS_HWINT) { 30081865Sdilpreet bge_rem_intrs(bgep); 30091865Sdilpreet rw_destroy(bgep->errlock); 30101865Sdilpreet mutex_destroy(bgep->softintrlock); 30111865Sdilpreet mutex_destroy(bgep->genlock); 30121865Sdilpreet } 30131369Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 30141369Sdduvall ddi_remove_softintr(bgep->factotum_id); 30151369Sdduvall if (bgep->progress & PROGRESS_RESCHED) 30163334Sgs150176 ddi_remove_softintr(bgep->drain_id); 30171865Sdilpreet if (bgep->progress & PROGRESS_BUFS) 30181865Sdilpreet bge_free_bufs(bgep); 30191369Sdduvall if (bgep->progress & PROGRESS_REGS) 30201369Sdduvall ddi_regs_map_free(&bgep->io_handle); 30211369Sdduvall if (bgep->progress & PROGRESS_CFG) 30221369Sdduvall pci_config_teardown(&bgep->cfg_handle); 30231369Sdduvall 30241865Sdilpreet bge_fm_fini(bgep); 30251865Sdilpreet 30261369Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 30273334Sgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t)); 30281369Sdduvall kmem_free(bgep, sizeof (*bgep)); 30291369Sdduvall } 30301369Sdduvall 30311369Sdduvall static int 30321369Sdduvall bge_resume(dev_info_t *devinfo) 30331369Sdduvall { 30341369Sdduvall bge_t *bgep; /* Our private data */ 30351369Sdduvall chip_id_t *cidp; 30361369Sdduvall chip_id_t chipid; 30371369Sdduvall 30381369Sdduvall bgep = ddi_get_driver_private(devinfo); 30391369Sdduvall if (bgep == NULL) 30401369Sdduvall return (DDI_FAILURE); 30411369Sdduvall 30421369Sdduvall /* 30431369Sdduvall * Refuse to resume if the data structures aren't consistent 30441369Sdduvall */ 30451369Sdduvall if (bgep->devinfo != devinfo) 30461369Sdduvall return (DDI_FAILURE); 30471369Sdduvall 30481408Srandyf #ifdef BGE_IPMI_ASF 30491408Srandyf /* 30501408Srandyf * Power management hasn't been supported in BGE now. If you 30511408Srandyf * want to implement it, please add the ASF/IPMI related 30521408Srandyf * code here. 30531408Srandyf */ 30541408Srandyf 30551408Srandyf #endif 30561408Srandyf 30571369Sdduvall /* 30581369Sdduvall * Read chip ID & set up config space command register(s) 30591369Sdduvall * Refuse to resume if the chip has changed its identity! 30601369Sdduvall */ 30611369Sdduvall cidp = &bgep->chipid; 30621865Sdilpreet mutex_enter(bgep->genlock); 30631369Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 30641865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 30651865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 30661865Sdilpreet mutex_exit(bgep->genlock); 30671865Sdilpreet return (DDI_FAILURE); 30681865Sdilpreet } 30691865Sdilpreet mutex_exit(bgep->genlock); 30701369Sdduvall if (chipid.vendor != cidp->vendor) 30711369Sdduvall return (DDI_FAILURE); 30721369Sdduvall if (chipid.device != cidp->device) 30731369Sdduvall return (DDI_FAILURE); 30741369Sdduvall if (chipid.revision != cidp->revision) 30751369Sdduvall return (DDI_FAILURE); 30761369Sdduvall if (chipid.asic_rev != cidp->asic_rev) 30771369Sdduvall return (DDI_FAILURE); 30781369Sdduvall 30791369Sdduvall /* 30801369Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 30811369Sdduvall */ 30821369Sdduvall mutex_enter(bgep->genlock); 30831865Sdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 30841865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 30851865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 30861865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 30871865Sdilpreet mutex_exit(bgep->genlock); 30881865Sdilpreet return (DDI_FAILURE); 30891865Sdilpreet } 30901865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 30911865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 30921865Sdilpreet mutex_exit(bgep->genlock); 30931865Sdilpreet return (DDI_FAILURE); 30941865Sdilpreet } 30951865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 30961865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 30971865Sdilpreet mutex_exit(bgep->genlock); 30981865Sdilpreet return (DDI_FAILURE); 30991865Sdilpreet } 31001369Sdduvall mutex_exit(bgep->genlock); 31011369Sdduvall return (DDI_SUCCESS); 31021369Sdduvall } 31031369Sdduvall 31041369Sdduvall /* 31051369Sdduvall * attach(9E) -- Attach a device to the system 31061369Sdduvall * 31071369Sdduvall * Called once for each board successfully probed. 31081369Sdduvall */ 31091369Sdduvall static int 31101369Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 31111369Sdduvall { 31121369Sdduvall bge_t *bgep; /* Our private data */ 31132311Sseb mac_register_t *macp; 31141369Sdduvall chip_id_t *cidp; 31151369Sdduvall caddr_t regs; 31161369Sdduvall int instance; 31171369Sdduvall int err; 31181369Sdduvall int intr_types; 31191408Srandyf #ifdef BGE_IPMI_ASF 31201408Srandyf uint32_t mhcrValue; 31213918Sml149210 #ifdef __sparc 31223918Sml149210 uint16_t value16; 31233918Sml149210 #endif 31243918Sml149210 #ifdef BGE_NETCONSOLE 31253918Sml149210 int retval; 31263918Sml149210 #endif 31271408Srandyf #endif 31281369Sdduvall 31291369Sdduvall instance = ddi_get_instance(devinfo); 31301369Sdduvall 31311369Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 31324588Sml149210 (void *)devinfo, cmd, instance)); 31331369Sdduvall BGE_BRKPT(NULL, "bge_attach"); 31341369Sdduvall 31351369Sdduvall switch (cmd) { 31361369Sdduvall default: 31371369Sdduvall return (DDI_FAILURE); 31381369Sdduvall 31391369Sdduvall case DDI_RESUME: 31401369Sdduvall return (bge_resume(devinfo)); 31411369Sdduvall 31421369Sdduvall case DDI_ATTACH: 31431369Sdduvall break; 31441369Sdduvall } 31451369Sdduvall 31461369Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 31473334Sgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP); 31481369Sdduvall ddi_set_driver_private(devinfo, bgep); 31491369Sdduvall bgep->bge_guard = BGE_GUARD; 31501369Sdduvall bgep->devinfo = devinfo; 31515903Ssowmini bgep->param_drain_max = 64; 31525903Ssowmini bgep->param_msi_cnt = 0; 31535903Ssowmini bgep->param_loop_mode = 0; 31541369Sdduvall 31551369Sdduvall /* 31561369Sdduvall * Initialize more fields in BGE private data 31571369Sdduvall */ 31581369Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31594588Sml149210 DDI_PROP_DONTPASS, debug_propname, bge_debug); 31601369Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 31614588Sml149210 BGE_DRIVER_NAME, instance); 31621369Sdduvall 31631369Sdduvall /* 31641865Sdilpreet * Initialize for fma support 31651865Sdilpreet */ 31661865Sdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31671865Sdilpreet DDI_PROP_DONTPASS, fm_cap, 31681865Sdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 31691865Sdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 31701865Sdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 31711865Sdilpreet bge_fm_init(bgep); 31721865Sdilpreet 31731865Sdilpreet /* 31741369Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 31751369Sdduvall * a power of 2) and convert to a mask. This can be used to 31761369Sdduvall * determine whether a message buffer crosses a page boundary. 31771369Sdduvall * Note: in 2s complement binary notation, if X is a power of 31781369Sdduvall * 2, then -X has the representation "11...1100...00". 31791369Sdduvall */ 31801369Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 31811369Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 31821369Sdduvall bgep->pagemask = -bgep->pagemask; 31831369Sdduvall 31841369Sdduvall /* 31851369Sdduvall * Map config space registers 31861369Sdduvall * Read chip ID & set up config space command register(s) 31871369Sdduvall * 31881369Sdduvall * Note: this leaves the chip accessible by Memory Space 31891369Sdduvall * accesses, but with interrupts and Bus Mastering off. 31901369Sdduvall * This should ensure that nothing untoward will happen 31911369Sdduvall * if it has been left active by the (net-)bootloader. 31921369Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 31931369Sdduvall * and allow interrupts only when everything else is set up. 31941369Sdduvall */ 31951369Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 31961408Srandyf #ifdef BGE_IPMI_ASF 31973918Sml149210 #ifdef __sparc 31983918Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM); 31993918Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME); 32003918Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16); 32013918Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 32024588Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 32034588Sml149210 MHCR_MASK_INTERRUPT_MODE | 32044588Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 32054588Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 32064588Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 32074588Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 32083918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue); 32093918Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG, 32104588Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) | 32114588Sml149210 MEMORY_ARBITER_ENABLE); 32123918Sml149210 #else 32131408Srandyf mhcrValue = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 32143918Sml149210 #endif 32151408Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 32161408Srandyf bgep->asf_wordswapped = B_TRUE; 32171408Srandyf } else { 32181408Srandyf bgep->asf_wordswapped = B_FALSE; 32191408Srandyf } 32201408Srandyf bge_asf_get_config(bgep); 32211408Srandyf #endif 32221369Sdduvall if (err != DDI_SUCCESS) { 32231369Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 32241369Sdduvall goto attach_fail; 32251369Sdduvall } 32261369Sdduvall bgep->progress |= PROGRESS_CFG; 32271369Sdduvall cidp = &bgep->chipid; 32281369Sdduvall bzero(cidp, sizeof (*cidp)); 32291369Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 32301865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 32311865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 32321865Sdilpreet goto attach_fail; 32331865Sdilpreet } 32341369Sdduvall 32351408Srandyf #ifdef BGE_IPMI_ASF 32361408Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 32371408Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 32381408Srandyf bgep->asf_newhandshake = B_TRUE; 32391408Srandyf } else { 32401408Srandyf bgep->asf_newhandshake = B_FALSE; 32411408Srandyf } 32421408Srandyf #endif 32431408Srandyf 32441369Sdduvall /* 32451369Sdduvall * Update those parts of the chip ID derived from volatile 32461369Sdduvall * registers with the values seen by OBP (in case the chip 32471369Sdduvall * has been reset externally and therefore lost them). 32481369Sdduvall */ 32491369Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32504588Sml149210 DDI_PROP_DONTPASS, subven_propname, cidp->subven); 32511369Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32524588Sml149210 DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 32531369Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32544588Sml149210 DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 32551369Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32564588Sml149210 DDI_PROP_DONTPASS, latency_propname, cidp->latency); 32571369Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32584588Sml149210 DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 32591369Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32604588Sml149210 DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 32611369Sdduvall 32621369Sdduvall if (bge_jumbo_enable == B_TRUE) { 32631369Sdduvall cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32644588Sml149210 DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 32651369Sdduvall if ((cidp->default_mtu < BGE_DEFAULT_MTU)|| 32664588Sml149210 (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 32671369Sdduvall cidp->default_mtu = BGE_DEFAULT_MTU; 32681369Sdduvall } 32691369Sdduvall } 32701369Sdduvall /* 32711369Sdduvall * Map operating registers 32721369Sdduvall */ 32731369Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 32744588Sml149210 ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 32751369Sdduvall if (err != DDI_SUCCESS) { 32761369Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 32771369Sdduvall goto attach_fail; 32781369Sdduvall } 32791369Sdduvall bgep->io_regs = regs; 32801369Sdduvall bgep->progress |= PROGRESS_REGS; 32811369Sdduvall 32821369Sdduvall /* 32831369Sdduvall * Characterise the device, so we know its requirements. 32841369Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 32851369Sdduvall */ 32861865Sdilpreet if (bge_chip_id_init(bgep) == EIO) { 32871865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 32881865Sdilpreet goto attach_fail; 32891865Sdilpreet } 32906512Ssowmini 32916512Ssowmini 32921369Sdduvall err = bge_alloc_bufs(bgep); 32931369Sdduvall if (err != DDI_SUCCESS) { 32941369Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 32951369Sdduvall goto attach_fail; 32961369Sdduvall } 32971865Sdilpreet bgep->progress |= PROGRESS_BUFS; 32981369Sdduvall 32991369Sdduvall /* 33001369Sdduvall * Add the softint handlers: 33011369Sdduvall * 33021369Sdduvall * Both of these handlers are used to avoid restrictions on the 33031369Sdduvall * context and/or mutexes required for some operations. In 33041369Sdduvall * particular, the hardware interrupt handler and its subfunctions 33051369Sdduvall * can detect a number of conditions that we don't want to handle 33061369Sdduvall * in that context or with that set of mutexes held. So, these 33071369Sdduvall * softints are triggered instead: 33081369Sdduvall * 33092135Szh199473 * the <resched> softint is triggered if we have previously 33101369Sdduvall * had to refuse to send a packet because of resource shortage 33111369Sdduvall * (we've run out of transmit buffers), but the send completion 33121369Sdduvall * interrupt handler has now detected that more buffers have 33131369Sdduvall * become available. 33141369Sdduvall * 33151369Sdduvall * the <factotum> is triggered if the h/w interrupt handler 33161369Sdduvall * sees the <link state changed> or <error> bits in the status 33171369Sdduvall * block. It's also triggered periodically to poll the link 33181369Sdduvall * state, just in case we aren't getting link status change 33191369Sdduvall * interrupts ... 33201369Sdduvall */ 33213334Sgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id, 33224588Sml149210 NULL, NULL, bge_send_drain, (caddr_t)bgep); 33231369Sdduvall if (err != DDI_SUCCESS) { 33241369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 33251369Sdduvall goto attach_fail; 33261369Sdduvall } 33271369Sdduvall bgep->progress |= PROGRESS_RESCHED; 33281369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 33294588Sml149210 NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 33301369Sdduvall if (err != DDI_SUCCESS) { 33311369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 33321369Sdduvall goto attach_fail; 33331369Sdduvall } 33341369Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 33351369Sdduvall 33361369Sdduvall /* Get supported interrupt types */ 33371369Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 33381369Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 33391369Sdduvall 33401369Sdduvall goto attach_fail; 33411369Sdduvall } 33421369Sdduvall 33432675Szh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x", 33444588Sml149210 bgep->ifname, intr_types)); 33451369Sdduvall 33461369Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 33471369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 33481369Sdduvall bge_error(bgep, "MSI registration failed, " 33491369Sdduvall "trying FIXED interrupt type\n"); 33501369Sdduvall } else { 33512675Szh199473 BGE_DEBUG(("%s: Using MSI interrupt type", 33524588Sml149210 bgep->ifname)); 33531369Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 33541865Sdilpreet bgep->progress |= PROGRESS_HWINT; 33551369Sdduvall } 33561369Sdduvall } 33571369Sdduvall 33581865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 33591369Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 33601369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 33611369Sdduvall bge_error(bgep, "FIXED interrupt " 33621369Sdduvall "registration failed\n"); 33631369Sdduvall goto attach_fail; 33641369Sdduvall } 33651369Sdduvall 33662675Szh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname)); 33671369Sdduvall 33681369Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 33691865Sdilpreet bgep->progress |= PROGRESS_HWINT; 33701369Sdduvall } 33711369Sdduvall 33721865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 33731369Sdduvall bge_error(bgep, "No interrupts registered\n"); 33741369Sdduvall goto attach_fail; 33751369Sdduvall } 33761369Sdduvall 33771369Sdduvall /* 33781369Sdduvall * Note that interrupts are not enabled yet as 33791865Sdilpreet * mutex locks are not initialized. Initialize mutex locks. 33801865Sdilpreet */ 33811865Sdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 33821865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 33831865Sdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 33841865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 33851865Sdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 33861865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 33871865Sdilpreet 33881865Sdilpreet /* 33891865Sdilpreet * Initialize rings. 33901369Sdduvall */ 33911369Sdduvall bge_init_rings(bgep); 33921369Sdduvall 33931369Sdduvall /* 33941369Sdduvall * Now that mutex locks are initialized, enable interrupts. 33951369Sdduvall */ 33961865Sdilpreet bge_intr_enable(bgep); 33971865Sdilpreet bgep->progress |= PROGRESS_INTR; 33981369Sdduvall 33991369Sdduvall /* 34001369Sdduvall * Initialise link state variables 34011369Sdduvall * Stop, reset & reinitialise the chip. 34021369Sdduvall * Initialise the (internal) PHY. 34031369Sdduvall */ 34041369Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 34051369Sdduvall 34061369Sdduvall mutex_enter(bgep->genlock); 34071369Sdduvall 34081369Sdduvall /* 34091369Sdduvall * Reset chip & rings to initial state; also reset address 34101369Sdduvall * filtering, promiscuity, loopback mode. 34111369Sdduvall */ 34121408Srandyf #ifdef BGE_IPMI_ASF 34133918Sml149210 #ifdef BGE_NETCONSOLE 34143918Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 34153918Sml149210 #else 34161865Sdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 34173918Sml149210 #endif 34181408Srandyf #else 34191865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 34201408Srandyf #endif 34211865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 34221865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 34231865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34241865Sdilpreet mutex_exit(bgep->genlock); 34251865Sdilpreet goto attach_fail; 34261865Sdilpreet } 34271369Sdduvall 34282675Szh199473 #ifdef BGE_IPMI_ASF 34292675Szh199473 if (bgep->asf_enabled) { 34302675Szh199473 bgep->asf_status = ASF_STAT_RUN_INIT; 34312675Szh199473 } 34322675Szh199473 #endif 34332675Szh199473 34341369Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 34351369Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 34361369Sdduvall bgep->promisc = B_FALSE; 34371369Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 34381865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 34391865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34401865Sdilpreet mutex_exit(bgep->genlock); 34411865Sdilpreet goto attach_fail; 34421865Sdilpreet } 34431865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 34441865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34451865Sdilpreet mutex_exit(bgep->genlock); 34461865Sdilpreet goto attach_fail; 34471865Sdilpreet } 34481369Sdduvall 34491369Sdduvall mutex_exit(bgep->genlock); 34501369Sdduvall 34511865Sdilpreet if (bge_phys_init(bgep) == EIO) { 34521865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34531865Sdilpreet goto attach_fail; 34541865Sdilpreet } 34551369Sdduvall bgep->progress |= PROGRESS_PHY; 34561369Sdduvall 34571369Sdduvall /* 34586512Ssowmini * initialize NDD-tweakable parameters 34591369Sdduvall */ 34601369Sdduvall if (bge_nd_init(bgep)) { 34611369Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 34621369Sdduvall goto attach_fail; 34631369Sdduvall } 34641369Sdduvall bgep->progress |= PROGRESS_NDD; 34651369Sdduvall 34661369Sdduvall /* 34671369Sdduvall * Create & initialise named kstats 34681369Sdduvall */ 34691369Sdduvall bge_init_kstats(bgep, instance); 34701369Sdduvall bgep->progress |= PROGRESS_KSTATS; 34711369Sdduvall 34721369Sdduvall /* 34731369Sdduvall * Determine whether to override the chip's own MAC address 34741369Sdduvall */ 34751369Sdduvall bge_find_mac_address(bgep, cidp); 34762331Skrgopi 34772406Skrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX; 34788275SEric Cheng bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX; 34791369Sdduvall 34802311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 34812311Sseb goto attach_fail; 34822311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 34832311Sseb macp->m_driver = bgep; 34841369Sdduvall macp->m_dip = devinfo; 34858275SEric Cheng macp->m_src_addr = cidp->vendor_addr.addr; 34862311Sseb macp->m_callbacks = &bge_m_callbacks; 34872311Sseb macp->m_min_sdu = 0; 34882311Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); 34895895Syz147064 macp->m_margin = VLAN_TAGSZ; 34906512Ssowmini macp->m_priv_props = bge_priv_prop; 34916512Ssowmini macp->m_priv_prop_count = BGE_MAX_PRIV_PROPS; 34928275SEric Cheng macp->m_v12n = MAC_VIRT_LEVEL1; 34936512Ssowmini 34941369Sdduvall /* 34951369Sdduvall * Finally, we're ready to register ourselves with the MAC layer 34961369Sdduvall * interface; if this succeeds, we're all ready to start() 34971369Sdduvall */ 34982311Sseb err = mac_register(macp, &bgep->mh); 34992311Sseb mac_free(macp); 35002311Sseb if (err != 0) 35011369Sdduvall goto attach_fail; 35021369Sdduvall 35035107Seota /* 35045107Seota * Register a periodical handler. 35055107Seota * bge_chip_cyclic() is invoked in kernel context. 35065107Seota */ 35075107Seota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep, 35085107Seota BGE_CYCLIC_PERIOD, DDI_IPL_0); 35091369Sdduvall 35101369Sdduvall bgep->progress |= PROGRESS_READY; 35111369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 35123918Sml149210 #ifdef BGE_IPMI_ASF 35133918Sml149210 #ifdef BGE_NETCONSOLE 35143918Sml149210 if (bgep->asf_enabled) { 35153918Sml149210 mutex_enter(bgep->genlock); 35163918Sml149210 retval = bge_chip_start(bgep, B_TRUE); 35173918Sml149210 mutex_exit(bgep->genlock); 35183918Sml149210 if (retval != DDI_SUCCESS) 35193918Sml149210 goto attach_fail; 35203918Sml149210 } 35213918Sml149210 #endif 35223918Sml149210 #endif 35237656SSherry.Moore@Sun.COM 35247656SSherry.Moore@Sun.COM ddi_report_dev(devinfo); 35258993SYong.Tan@Sun.COM BGE_REPORT((bgep, "bge version: %s", bge_version)); 35268922SYong.Tan@Sun.COM 35271369Sdduvall return (DDI_SUCCESS); 35281369Sdduvall 35291369Sdduvall attach_fail: 35301408Srandyf #ifdef BGE_IPMI_ASF 35312675Szh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN); 35321408Srandyf #else 35331369Sdduvall bge_unattach(bgep); 35341408Srandyf #endif 35351369Sdduvall return (DDI_FAILURE); 35361369Sdduvall } 35371369Sdduvall 35381369Sdduvall /* 35391369Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 35401369Sdduvall */ 35411369Sdduvall static int 35421369Sdduvall bge_suspend(bge_t *bgep) 35431369Sdduvall { 35441369Sdduvall /* 35451369Sdduvall * Stop processing and idle (powerdown) the PHY ... 35461369Sdduvall */ 35471369Sdduvall mutex_enter(bgep->genlock); 35481408Srandyf #ifdef BGE_IPMI_ASF 35491408Srandyf /* 35501408Srandyf * Power management hasn't been supported in BGE now. If you 35511408Srandyf * want to implement it, please add the ASF/IPMI related 35521408Srandyf * code here. 35531408Srandyf */ 35541408Srandyf #endif 35551369Sdduvall bge_stop(bgep); 35561865Sdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 35571865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 35581865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 35591865Sdilpreet mutex_exit(bgep->genlock); 35601865Sdilpreet return (DDI_FAILURE); 35611865Sdilpreet } 35621865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 35631865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 35641865Sdilpreet mutex_exit(bgep->genlock); 35651865Sdilpreet return (DDI_FAILURE); 35661865Sdilpreet } 35671369Sdduvall mutex_exit(bgep->genlock); 35681369Sdduvall 35691369Sdduvall return (DDI_SUCCESS); 35701369Sdduvall } 35711369Sdduvall 35721369Sdduvall /* 35737656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 35747656SSherry.Moore@Sun.COM * 35757656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 35767656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 35777656SSherry.Moore@Sun.COM * blocked. 35787656SSherry.Moore@Sun.COM * 35797656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 35807656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 35817656SSherry.Moore@Sun.COM */ 35827656SSherry.Moore@Sun.COM #ifdef __sparc 35837656SSherry.Moore@Sun.COM #define bge_quiesce ddi_quiesce_not_supported 35847656SSherry.Moore@Sun.COM #else 35857656SSherry.Moore@Sun.COM static int 35867656SSherry.Moore@Sun.COM bge_quiesce(dev_info_t *devinfo) 35877656SSherry.Moore@Sun.COM { 35887656SSherry.Moore@Sun.COM bge_t *bgep = ddi_get_driver_private(devinfo); 35897656SSherry.Moore@Sun.COM 35907656SSherry.Moore@Sun.COM if (bgep == NULL) 35917656SSherry.Moore@Sun.COM return (DDI_FAILURE); 35927656SSherry.Moore@Sun.COM 35937656SSherry.Moore@Sun.COM if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 35947656SSherry.Moore@Sun.COM bge_reg_set32(bgep, PCI_CONF_BGE_MHCR, 35957656SSherry.Moore@Sun.COM MHCR_MASK_PCI_INT_OUTPUT); 35967656SSherry.Moore@Sun.COM } else { 35977656SSherry.Moore@Sun.COM bge_reg_clr32(bgep, MSI_MODE_REG, MSI_MSI_ENABLE); 35987656SSherry.Moore@Sun.COM } 35997656SSherry.Moore@Sun.COM 36007656SSherry.Moore@Sun.COM /* Stop the chip */ 36017656SSherry.Moore@Sun.COM bge_chip_stop_nonblocking(bgep); 36027656SSherry.Moore@Sun.COM 36037656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 36047656SSherry.Moore@Sun.COM } 36057656SSherry.Moore@Sun.COM #endif 36067656SSherry.Moore@Sun.COM 36077656SSherry.Moore@Sun.COM /* 36081369Sdduvall * detach(9E) -- Detach a device from the system 36091369Sdduvall */ 36101369Sdduvall static int 36111369Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 36121369Sdduvall { 36131369Sdduvall bge_t *bgep; 36141408Srandyf #ifdef BGE_IPMI_ASF 36151408Srandyf uint_t asf_mode; 36161408Srandyf asf_mode = ASF_MODE_NONE; 36171408Srandyf #endif 36181369Sdduvall 36191369Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 36201369Sdduvall 36211369Sdduvall bgep = ddi_get_driver_private(devinfo); 36221369Sdduvall 36231369Sdduvall switch (cmd) { 36241369Sdduvall default: 36251369Sdduvall return (DDI_FAILURE); 36261369Sdduvall 36271369Sdduvall case DDI_SUSPEND: 36281369Sdduvall return (bge_suspend(bgep)); 36291369Sdduvall 36301369Sdduvall case DDI_DETACH: 36311369Sdduvall break; 36321369Sdduvall } 36331369Sdduvall 36341408Srandyf #ifdef BGE_IPMI_ASF 36351408Srandyf mutex_enter(bgep->genlock); 36362675Szh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) || 36374588Sml149210 (bgep->asf_status == ASF_STAT_RUN_INIT))) { 36381408Srandyf 36391408Srandyf bge_asf_update_status(bgep); 36402675Szh199473 if (bgep->asf_status == ASF_STAT_RUN) { 36412675Szh199473 bge_asf_stop_timer(bgep); 36422675Szh199473 } 36431408Srandyf bgep->asf_status = ASF_STAT_STOP; 36441408Srandyf 36451408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 36461408Srandyf 36471408Srandyf if (bgep->asf_pseudostop) { 36481408Srandyf bge_chip_stop(bgep, B_FALSE); 36491408Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 36501408Srandyf bgep->asf_pseudostop = B_FALSE; 36511408Srandyf } 36521408Srandyf 36531408Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 36541865Sdilpreet 36551865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 36561865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 36571865Sdilpreet DDI_SERVICE_UNAFFECTED); 36581865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 36591865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 36601865Sdilpreet DDI_SERVICE_UNAFFECTED); 36611408Srandyf } 36621408Srandyf mutex_exit(bgep->genlock); 36631408Srandyf #endif 36641408Srandyf 36651369Sdduvall /* 36661369Sdduvall * Unregister from the GLD subsystem. This can fail, in 36671369Sdduvall * particular if there are DLPI style-2 streams still open - 36681369Sdduvall * in which case we just return failure without shutting 36691369Sdduvall * down chip operations. 36701369Sdduvall */ 36712311Sseb if (mac_unregister(bgep->mh) != 0) 36721369Sdduvall return (DDI_FAILURE); 36731369Sdduvall 36741369Sdduvall /* 36751369Sdduvall * All activity stopped, so we can clean up & exit 36761369Sdduvall */ 36771408Srandyf #ifdef BGE_IPMI_ASF 36781408Srandyf bge_unattach(bgep, asf_mode); 36791408Srandyf #else 36801369Sdduvall bge_unattach(bgep); 36811408Srandyf #endif 36821369Sdduvall return (DDI_SUCCESS); 36831369Sdduvall } 36841369Sdduvall 36851369Sdduvall 36861369Sdduvall /* 36871369Sdduvall * ========== Module Loading Data & Entry Points ========== 36881369Sdduvall */ 36891369Sdduvall 36901369Sdduvall #undef BGE_DBG 36911369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 36921369Sdduvall 36937656SSherry.Moore@Sun.COM DDI_DEFINE_STREAM_OPS(bge_dev_ops, 36947656SSherry.Moore@Sun.COM nulldev, /* identify */ 36957656SSherry.Moore@Sun.COM nulldev, /* probe */ 36967656SSherry.Moore@Sun.COM bge_attach, /* attach */ 36977656SSherry.Moore@Sun.COM bge_detach, /* detach */ 36987656SSherry.Moore@Sun.COM nodev, /* reset */ 36997656SSherry.Moore@Sun.COM NULL, /* cb_ops */ 37007656SSherry.Moore@Sun.COM D_MP, /* bus_ops */ 37017656SSherry.Moore@Sun.COM NULL, /* power */ 37027656SSherry.Moore@Sun.COM bge_quiesce /* quiesce */ 37037656SSherry.Moore@Sun.COM ); 37041369Sdduvall 37051369Sdduvall static struct modldrv bge_modldrv = { 37061369Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 37071369Sdduvall bge_ident, /* short description */ 37081369Sdduvall &bge_dev_ops /* driver specific ops */ 37091369Sdduvall }; 37101369Sdduvall 37111369Sdduvall static struct modlinkage modlinkage = { 37121369Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 37131369Sdduvall }; 37141369Sdduvall 37151369Sdduvall 37161369Sdduvall int 37171369Sdduvall _info(struct modinfo *modinfop) 37181369Sdduvall { 37191369Sdduvall return (mod_info(&modlinkage, modinfop)); 37201369Sdduvall } 37211369Sdduvall 37221369Sdduvall int 37231369Sdduvall _init(void) 37241369Sdduvall { 37251369Sdduvall int status; 37261369Sdduvall 37271369Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 37281369Sdduvall status = mod_install(&modlinkage); 37291369Sdduvall if (status == DDI_SUCCESS) 37301369Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 37311369Sdduvall else 37321369Sdduvall mac_fini_ops(&bge_dev_ops); 37331369Sdduvall return (status); 37341369Sdduvall } 37351369Sdduvall 37361369Sdduvall int 37371369Sdduvall _fini(void) 37381369Sdduvall { 37391369Sdduvall int status; 37401369Sdduvall 37411369Sdduvall status = mod_remove(&modlinkage); 37421369Sdduvall if (status == DDI_SUCCESS) { 37431369Sdduvall mac_fini_ops(&bge_dev_ops); 37441369Sdduvall mutex_destroy(bge_log_mutex); 37451369Sdduvall } 37461369Sdduvall return (status); 37471369Sdduvall } 37481369Sdduvall 37491369Sdduvall 37501369Sdduvall /* 37511369Sdduvall * bge_add_intrs: 37521369Sdduvall * 37531369Sdduvall * Register FIXED or MSI interrupts. 37541369Sdduvall */ 37551369Sdduvall static int 37561369Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 37571369Sdduvall { 37581369Sdduvall dev_info_t *dip = bgep->devinfo; 37591369Sdduvall int avail, actual, intr_size, count = 0; 37601369Sdduvall int i, flag, ret; 37611369Sdduvall 37622675Szh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type)); 37631369Sdduvall 37641369Sdduvall /* Get number of interrupts */ 37651369Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 37661369Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 37671369Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 37681369Sdduvall "count: %d", ret, count); 37691369Sdduvall 37701369Sdduvall return (DDI_FAILURE); 37711369Sdduvall } 37721369Sdduvall 37731369Sdduvall /* Get number of available interrupts */ 37741369Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 37751369Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 37761369Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 37771369Sdduvall "ret: %d, avail: %d\n", ret, avail); 37781369Sdduvall 37791369Sdduvall return (DDI_FAILURE); 37801369Sdduvall } 37811369Sdduvall 37821369Sdduvall if (avail < count) { 37832675Szh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d", 37842675Szh199473 bgep->ifname, count, avail)); 37851369Sdduvall } 37861369Sdduvall 37871369Sdduvall /* 37881369Sdduvall * BGE hardware generates only single MSI even though it claims 37891369Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 37901369Sdduvall */ 37911369Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 37921369Sdduvall count = 1; 37931369Sdduvall flag = DDI_INTR_ALLOC_STRICT; 37941369Sdduvall } else { 37951369Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 37961369Sdduvall } 37971369Sdduvall 37981369Sdduvall /* Allocate an array of interrupt handles */ 37991369Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 38001369Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 38011369Sdduvall 38021369Sdduvall /* Call ddi_intr_alloc() */ 38031369Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 38041369Sdduvall count, &actual, flag); 38051369Sdduvall 38061369Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 38071369Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 38081369Sdduvall 38091369Sdduvall kmem_free(bgep->htable, intr_size); 38101369Sdduvall return (DDI_FAILURE); 38111369Sdduvall } 38121369Sdduvall 38131369Sdduvall if (actual < count) { 38142675Szh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d", 38154588Sml149210 bgep->ifname, count, actual)); 38161369Sdduvall } 38171369Sdduvall 38181369Sdduvall bgep->intr_cnt = actual; 38191369Sdduvall 38201369Sdduvall /* 38211369Sdduvall * Get priority for first msi, assume remaining are all the same 38221369Sdduvall */ 38231369Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 38241369Sdduvall DDI_SUCCESS) { 38251369Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 38261369Sdduvall 38271369Sdduvall /* Free already allocated intr */ 38281369Sdduvall for (i = 0; i < actual; i++) { 38291369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38301369Sdduvall } 38311369Sdduvall 38321369Sdduvall kmem_free(bgep->htable, intr_size); 38331369Sdduvall return (DDI_FAILURE); 38341369Sdduvall } 38351369Sdduvall 38361369Sdduvall /* Call ddi_intr_add_handler() */ 38371369Sdduvall for (i = 0; i < actual; i++) { 38381369Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 38391369Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 38401369Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 38411369Sdduvall "failed %d\n", ret); 38421369Sdduvall 38431369Sdduvall /* Free already allocated intr */ 38441369Sdduvall for (i = 0; i < actual; i++) { 38451369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38461369Sdduvall } 38471369Sdduvall 38481369Sdduvall kmem_free(bgep->htable, intr_size); 38491369Sdduvall return (DDI_FAILURE); 38501369Sdduvall } 38511369Sdduvall } 38521369Sdduvall 38531369Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 38544588Sml149210 != DDI_SUCCESS) { 38551369Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 38561369Sdduvall 38571369Sdduvall for (i = 0; i < actual; i++) { 38581369Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 38591369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38601369Sdduvall } 38611369Sdduvall 38621369Sdduvall kmem_free(bgep->htable, intr_size); 38631369Sdduvall return (DDI_FAILURE); 38641369Sdduvall } 38651369Sdduvall 38661369Sdduvall return (DDI_SUCCESS); 38671369Sdduvall } 38681369Sdduvall 38691369Sdduvall /* 38701369Sdduvall * bge_rem_intrs: 38711369Sdduvall * 38721369Sdduvall * Unregister FIXED or MSI interrupts 38731369Sdduvall */ 38741369Sdduvall static void 38751369Sdduvall bge_rem_intrs(bge_t *bgep) 38761369Sdduvall { 38771369Sdduvall int i; 38781369Sdduvall 38792675Szh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep)); 38801369Sdduvall 38811865Sdilpreet /* Call ddi_intr_remove_handler() */ 38821865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 38831865Sdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 38841865Sdilpreet (void) ddi_intr_free(bgep->htable[i]); 38851865Sdilpreet } 38861865Sdilpreet 38871865Sdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 38881865Sdilpreet } 38891865Sdilpreet 38901865Sdilpreet 38911865Sdilpreet void 38921865Sdilpreet bge_intr_enable(bge_t *bgep) 38931865Sdilpreet { 38941865Sdilpreet int i; 38951865Sdilpreet 38961865Sdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 38971865Sdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 38981865Sdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 38991865Sdilpreet } else { 39001865Sdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 39011865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 39021865Sdilpreet (void) ddi_intr_enable(bgep->htable[i]); 39031865Sdilpreet } 39041865Sdilpreet } 39051865Sdilpreet } 39061865Sdilpreet 39071865Sdilpreet 39081865Sdilpreet void 39091865Sdilpreet bge_intr_disable(bge_t *bgep) 39101865Sdilpreet { 39111865Sdilpreet int i; 39121865Sdilpreet 39131369Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 39141369Sdduvall /* Call ddi_intr_block_disable() */ 39151369Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 39161369Sdduvall } else { 39171369Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 39181369Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 39191369Sdduvall } 39201369Sdduvall } 39211369Sdduvall } 39225903Ssowmini 39235903Ssowmini int 39245903Ssowmini bge_reprogram(bge_t *bgep) 39255903Ssowmini { 39265903Ssowmini int status = 0; 39275903Ssowmini 39285903Ssowmini ASSERT(mutex_owned(bgep->genlock)); 39295903Ssowmini 39305903Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) { 39315903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 39325903Ssowmini status = IOC_INVAL; 39335903Ssowmini } 39345903Ssowmini #ifdef BGE_IPMI_ASF 39355903Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 39365903Ssowmini #else 39375903Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) { 39385903Ssowmini #endif 39395903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 39405903Ssowmini status = IOC_INVAL; 39415903Ssowmini } 39425903Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI) 39435903Ssowmini bge_chip_msi_trig(bgep); 39445903Ssowmini return (status); 39455903Ssowmini } 3946