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*9918SYong.Tan@Sun.COM static char bge_version[] = "Broadcom Gb Ethernet v1.08"; 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 } 561*9918SYong.Tan@Sun.COM bgep->watchdog = 0; 5621369Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 5631369Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 5641408Srandyf 5651865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 5661865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5671865Sdilpreet mutex_exit(bgep->genlock); 5681865Sdilpreet return (EIO); 5691865Sdilpreet } 5701865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 5711865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5721865Sdilpreet mutex_exit(bgep->genlock); 5731865Sdilpreet return (EIO); 5741865Sdilpreet } 5751408Srandyf #ifdef BGE_IPMI_ASF 5761408Srandyf if (bgep->asf_enabled) { 5771408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 5781408Srandyf /* start ASF heart beat */ 5791408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 5804588Sml149210 (void *)bgep, 5814588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 5821408Srandyf bgep->asf_status = ASF_STAT_RUN; 5831408Srandyf } 5841408Srandyf } 5851408Srandyf #endif 5861369Sdduvall mutex_exit(bgep->genlock); 5871369Sdduvall 5881369Sdduvall return (0); 5891369Sdduvall } 5901369Sdduvall 5911369Sdduvall /* 5922331Skrgopi * bge_unicst_set() -- set the physical network address 5932331Skrgopi */ 5942331Skrgopi static int 5958275SEric Cheng bge_unicst_set(void *arg, const uint8_t *macaddr, int slot) 5962331Skrgopi { 5971369Sdduvall bge_t *bgep = arg; /* private device info */ 5981369Sdduvall 5991369Sdduvall BGE_TRACE(("bge_m_unicst_set($%p, %s)", arg, 6004588Sml149210 ether_sprintf((void *)macaddr))); 6011369Sdduvall /* 6021369Sdduvall * Remember the new current address in the driver state 6031369Sdduvall * Sync the chip's idea of the address too ... 6041369Sdduvall */ 6051369Sdduvall mutex_enter(bgep->genlock); 6061865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 6071865Sdilpreet /* can happen during autorecovery */ 6081865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6091865Sdilpreet mutex_exit(bgep->genlock); 6101865Sdilpreet return (EIO); 6111865Sdilpreet } 6122331Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr); 6131408Srandyf #ifdef BGE_IPMI_ASF 6141865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 6151865Sdilpreet #else 6161865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6171865Sdilpreet #endif 6181865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6191865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6201865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6211865Sdilpreet mutex_exit(bgep->genlock); 6221865Sdilpreet return (EIO); 6231865Sdilpreet } 6241865Sdilpreet #ifdef BGE_IPMI_ASF 6251408Srandyf if (bgep->asf_enabled) { 6261408Srandyf /* 6271408Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 6281408Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 6291408Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 6301408Srandyf */ 6311408Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 6321408Srandyf /* 6331408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 6341408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 6351408Srandyf * may crash. 6361408Srandyf */ 6371408Srandyf bge_asf_update_status(bgep); 6381408Srandyf bge_asf_stop_timer(bgep); 6391408Srandyf bgep->asf_status = ASF_STAT_STOP; 6401408Srandyf 6411408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 6421408Srandyf } 6431865Sdilpreet bge_chip_stop(bgep, B_FALSE); 6441408Srandyf 6451865Sdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 6461865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6471865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6481865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 6491865Sdilpreet DDI_SERVICE_DEGRADED); 6501865Sdilpreet mutex_exit(bgep->genlock); 6511865Sdilpreet return (EIO); 6521865Sdilpreet } 6531865Sdilpreet 6541408Srandyf /* 6551408Srandyf * Start our ASF heartbeat counter as soon as possible. 6561408Srandyf */ 6571408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 6581408Srandyf /* start ASF heart beat */ 6591408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 6604588Sml149210 (void *)bgep, 6614588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 6621408Srandyf bgep->asf_status = ASF_STAT_RUN; 6631408Srandyf } 6641408Srandyf } 6651408Srandyf #endif 6661369Sdduvall BGE_DEBUG(("bge_m_unicst_set($%p) done", arg)); 6671865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 6681865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6691865Sdilpreet mutex_exit(bgep->genlock); 6701865Sdilpreet return (EIO); 6711865Sdilpreet } 6721865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 6731865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6741865Sdilpreet mutex_exit(bgep->genlock); 6751865Sdilpreet return (EIO); 6761865Sdilpreet } 6771369Sdduvall mutex_exit(bgep->genlock); 6781369Sdduvall 6791369Sdduvall return (0); 6801369Sdduvall } 6811369Sdduvall 6825903Ssowmini extern void bge_wake_factotum(bge_t *); 6835903Ssowmini 6845903Ssowmini static boolean_t 6855903Ssowmini bge_param_locked(mac_prop_id_t pr_num) 6865903Ssowmini { 6875903Ssowmini /* 6885903Ssowmini * All adv_* parameters are locked (read-only) while 6895903Ssowmini * the device is in any sort of loopback mode ... 6905903Ssowmini */ 6915903Ssowmini switch (pr_num) { 6926789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 6936789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 6946789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 6956789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 6966789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 6976789Sam223141 case MAC_PROP_EN_100FDX_CAP: 6986789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 6996789Sam223141 case MAC_PROP_EN_100HDX_CAP: 7006789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 7016789Sam223141 case MAC_PROP_EN_10FDX_CAP: 7026789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 7036789Sam223141 case MAC_PROP_EN_10HDX_CAP: 7046789Sam223141 case MAC_PROP_AUTONEG: 7056789Sam223141 case MAC_PROP_FLOWCTRL: 7065903Ssowmini return (B_TRUE); 7075903Ssowmini } 7085903Ssowmini return (B_FALSE); 7095903Ssowmini } 7105903Ssowmini /* 7115903Ssowmini * callback functions for set/get of properties 7125903Ssowmini */ 7135903Ssowmini static int 7145903Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 7155903Ssowmini uint_t pr_valsize, const void *pr_val) 7165903Ssowmini { 7175903Ssowmini bge_t *bgep = barg; 7185903Ssowmini int err = 0; 7196512Ssowmini uint32_t cur_mtu, new_mtu; 7205903Ssowmini uint_t maxsdu; 7215903Ssowmini link_flowctrl_t fl; 7225903Ssowmini 7235903Ssowmini mutex_enter(bgep->genlock); 7245903Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE && 7255903Ssowmini bge_param_locked(pr_num)) { 7265903Ssowmini /* 7275903Ssowmini * All adv_* parameters are locked (read-only) 7285903Ssowmini * while the device is in any sort of loopback mode. 7295903Ssowmini */ 7305903Ssowmini mutex_exit(bgep->genlock); 7315903Ssowmini return (EBUSY); 7325903Ssowmini } 7336512Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 7346789Sam223141 ((pr_num == MAC_PROP_EN_100FDX_CAP) || 7358118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_100HDX_CAP) || 7366789Sam223141 (pr_num == MAC_PROP_EN_10FDX_CAP) || 7376789Sam223141 (pr_num == MAC_PROP_EN_10HDX_CAP))) { 7386512Ssowmini /* 7396512Ssowmini * these properties are read/write on copper, 7406512Ssowmini * read-only and 0 on serdes 7416512Ssowmini */ 7426512Ssowmini mutex_exit(bgep->genlock); 7436512Ssowmini return (ENOTSUP); 7446512Ssowmini } 7458922SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep) && 7468922SYong.Tan@Sun.COM ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 7477678SYong.Tan@Sun.COM (pr_num == MAC_PROP_EN_1000HDX_CAP))) { 7487678SYong.Tan@Sun.COM mutex_exit(bgep->genlock); 7497678SYong.Tan@Sun.COM return (ENOTSUP); 7507678SYong.Tan@Sun.COM } 7516512Ssowmini 7525903Ssowmini switch (pr_num) { 7536789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 7545903Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val; 7555903Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val; 7565903Ssowmini goto reprogram; 7576789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 7585903Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val; 7595903Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val; 7605903Ssowmini goto reprogram; 7616789Sam223141 case MAC_PROP_EN_100FDX_CAP: 7625903Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val; 7635903Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val; 7645903Ssowmini goto reprogram; 7656789Sam223141 case MAC_PROP_EN_100HDX_CAP: 7665903Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val; 7675903Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val; 7685903Ssowmini goto reprogram; 7696789Sam223141 case MAC_PROP_EN_10FDX_CAP: 7705903Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val; 7715903Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val; 7725903Ssowmini goto reprogram; 7736789Sam223141 case MAC_PROP_EN_10HDX_CAP: 7745903Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val; 7755903Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val; 7765903Ssowmini reprogram: 7775903Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) 7785903Ssowmini err = EINVAL; 7795903Ssowmini break; 7806789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 7816789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 7826789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 7836789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 7846789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 7856789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 7866789Sam223141 case MAC_PROP_STATUS: 7876789Sam223141 case MAC_PROP_SPEED: 7886789Sam223141 case MAC_PROP_DUPLEX: 7896512Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */ 7905903Ssowmini break; 7916789Sam223141 case MAC_PROP_AUTONEG: 7925903Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val; 7935903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 7945903Ssowmini err = EINVAL; 7955903Ssowmini break; 7966789Sam223141 case MAC_PROP_MTU: 7975903Ssowmini cur_mtu = bgep->chipid.default_mtu; 7985903Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 7996512Ssowmini 8005903Ssowmini if (new_mtu == cur_mtu) { 8015903Ssowmini err = 0; 8025903Ssowmini break; 8035903Ssowmini } 8045903Ssowmini if (new_mtu < BGE_DEFAULT_MTU || 8055903Ssowmini new_mtu > BGE_MAXIMUM_MTU) { 8065903Ssowmini err = EINVAL; 8075903Ssowmini break; 8085903Ssowmini } 8095903Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) && 8105903Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { 8115903Ssowmini err = EINVAL; 8125903Ssowmini break; 8135903Ssowmini } 8145903Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) { 8155903Ssowmini err = EBUSY; 8165903Ssowmini break; 8175903Ssowmini } 8185903Ssowmini bgep->chipid.default_mtu = new_mtu; 8195903Ssowmini if (bge_chip_id_init(bgep)) { 8205903Ssowmini err = EINVAL; 8215903Ssowmini break; 8225903Ssowmini } 8235903Ssowmini maxsdu = bgep->chipid.ethmax_size - 8245903Ssowmini sizeof (struct ether_header); 8255903Ssowmini err = mac_maxsdu_update(bgep->mh, maxsdu); 8265903Ssowmini if (err == 0) { 8275903Ssowmini bgep->bge_dma_error = B_TRUE; 8285903Ssowmini bgep->manual_reset = B_TRUE; 8295903Ssowmini bge_chip_stop(bgep, B_TRUE); 8305903Ssowmini bge_wake_factotum(bgep); 8315903Ssowmini err = 0; 8325903Ssowmini } 8335903Ssowmini break; 8346789Sam223141 case MAC_PROP_FLOWCTRL: 8355903Ssowmini bcopy(pr_val, &fl, sizeof (fl)); 8365903Ssowmini switch (fl) { 8375903Ssowmini default: 8386512Ssowmini err = ENOTSUP; 8395903Ssowmini break; 8405903Ssowmini case LINK_FLOWCTRL_NONE: 8415903Ssowmini bgep->param_adv_pause = 0; 8425903Ssowmini bgep->param_adv_asym_pause = 0; 8435903Ssowmini 8445903Ssowmini bgep->param_link_rx_pause = B_FALSE; 8455903Ssowmini bgep->param_link_tx_pause = B_FALSE; 8465903Ssowmini break; 8475903Ssowmini case LINK_FLOWCTRL_RX: 8485903Ssowmini bgep->param_adv_pause = 1; 8495903Ssowmini bgep->param_adv_asym_pause = 1; 8505903Ssowmini 8515903Ssowmini bgep->param_link_rx_pause = B_TRUE; 8525903Ssowmini bgep->param_link_tx_pause = B_FALSE; 8535903Ssowmini break; 8545903Ssowmini case LINK_FLOWCTRL_TX: 8555903Ssowmini bgep->param_adv_pause = 0; 8565903Ssowmini bgep->param_adv_asym_pause = 1; 8575903Ssowmini 8585903Ssowmini bgep->param_link_rx_pause = B_FALSE; 8595903Ssowmini bgep->param_link_tx_pause = B_TRUE; 8605903Ssowmini break; 8615903Ssowmini case LINK_FLOWCTRL_BI: 8625903Ssowmini bgep->param_adv_pause = 1; 8638922SYong.Tan@Sun.COM bgep->param_adv_asym_pause = 0; 8645903Ssowmini 8655903Ssowmini bgep->param_link_rx_pause = B_TRUE; 8665903Ssowmini bgep->param_link_tx_pause = B_TRUE; 8675903Ssowmini break; 8685903Ssowmini } 8695903Ssowmini 8705903Ssowmini if (err == 0) { 8715903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 8725903Ssowmini err = EINVAL; 8735903Ssowmini } 8745903Ssowmini 8755903Ssowmini break; 8766789Sam223141 case MAC_PROP_PRIVATE: 8775903Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize, 8785903Ssowmini pr_val); 8795903Ssowmini break; 8806512Ssowmini default: 8816512Ssowmini err = ENOTSUP; 8826512Ssowmini break; 8835903Ssowmini } 8845903Ssowmini mutex_exit(bgep->genlock); 8855903Ssowmini return (err); 8865903Ssowmini } 8876512Ssowmini 8888118SVasumathi.Sundaram@Sun.COM /* ARGSUSED */ 8895903Ssowmini static int 8905903Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 8918118SVasumathi.Sundaram@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 8925903Ssowmini { 8935903Ssowmini bge_t *bgep = barg; 8945903Ssowmini int err = 0; 8955903Ssowmini link_flowctrl_t fl; 8966512Ssowmini uint64_t speed; 8976512Ssowmini int flags = bgep->chipid.flags; 8986789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 8996512Ssowmini 9006512Ssowmini if (pr_valsize == 0) 9016512Ssowmini return (EINVAL); 9025903Ssowmini bzero(pr_val, pr_valsize); 9038118SVasumathi.Sundaram@Sun.COM 9048118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 9058118SVasumathi.Sundaram@Sun.COM 9068118SVasumathi.Sundaram@Sun.COM mutex_enter(bgep->genlock); 9078118SVasumathi.Sundaram@Sun.COM if ((bgep->param_loop_mode != BGE_LOOP_NONE && 9088118SVasumathi.Sundaram@Sun.COM bge_param_locked(pr_num)) || 9098118SVasumathi.Sundaram@Sun.COM ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 9108118SVasumathi.Sundaram@Sun.COM ((pr_num == MAC_PROP_EN_100FDX_CAP) || 9118118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_100HDX_CAP) || 9128118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_10FDX_CAP) || 9138118SVasumathi.Sundaram@Sun.COM (pr_num == MAC_PROP_EN_10HDX_CAP))) || 9148118SVasumathi.Sundaram@Sun.COM (DEVICE_5906_SERIES_CHIPSETS(bgep) && 9158922SYong.Tan@Sun.COM ((pr_num == MAC_PROP_EN_1000FDX_CAP) || 9168922SYong.Tan@Sun.COM (pr_num == MAC_PROP_EN_1000HDX_CAP)))) 9178118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9188118SVasumathi.Sundaram@Sun.COM mutex_exit(bgep->genlock); 9198118SVasumathi.Sundaram@Sun.COM 9205903Ssowmini switch (pr_num) { 9216789Sam223141 case MAC_PROP_DUPLEX: 9228118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9236512Ssowmini if (pr_valsize < sizeof (link_duplex_t)) 9245903Ssowmini return (EINVAL); 9256512Ssowmini bcopy(&bgep->param_link_duplex, pr_val, 9266512Ssowmini sizeof (link_duplex_t)); 9275903Ssowmini break; 9286789Sam223141 case MAC_PROP_SPEED: 9298118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9306512Ssowmini if (pr_valsize < sizeof (speed)) 9315903Ssowmini return (EINVAL); 9326512Ssowmini speed = bgep->param_link_speed * 1000000ull; 9336512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 9345903Ssowmini break; 9356789Sam223141 case MAC_PROP_STATUS: 9368118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9376512Ssowmini if (pr_valsize < sizeof (link_state_t)) 9385903Ssowmini return (EINVAL); 9396512Ssowmini bcopy(&bgep->link_state, pr_val, 9406512Ssowmini sizeof (link_state_t)); 9415903Ssowmini break; 9426789Sam223141 case MAC_PROP_AUTONEG: 9436512Ssowmini if (is_default) 9446512Ssowmini *(uint8_t *)pr_val = 1; 9456512Ssowmini else 9466512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg; 9475903Ssowmini break; 9486789Sam223141 case MAC_PROP_FLOWCTRL: 9496512Ssowmini if (pr_valsize < sizeof (fl)) 9505903Ssowmini return (EINVAL); 9516512Ssowmini if (is_default) { 9526512Ssowmini fl = LINK_FLOWCTRL_BI; 9536512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 9546512Ssowmini break; 9556512Ssowmini } 9566512Ssowmini 9575903Ssowmini if (bgep->param_link_rx_pause && 9585903Ssowmini !bgep->param_link_tx_pause) 9595903Ssowmini fl = LINK_FLOWCTRL_RX; 9605903Ssowmini 9615903Ssowmini if (!bgep->param_link_rx_pause && 9625903Ssowmini !bgep->param_link_tx_pause) 9635903Ssowmini fl = LINK_FLOWCTRL_NONE; 9645903Ssowmini 9655903Ssowmini if (!bgep->param_link_rx_pause && 9665903Ssowmini bgep->param_link_tx_pause) 9675903Ssowmini fl = LINK_FLOWCTRL_TX; 9685903Ssowmini 9695903Ssowmini if (bgep->param_link_rx_pause && 9705903Ssowmini bgep->param_link_tx_pause) 9715903Ssowmini fl = LINK_FLOWCTRL_BI; 9725903Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 9735903Ssowmini break; 9746789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 9758118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9767678SYong.Tan@Sun.COM if (is_default) { 9777678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9787678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 9797678SYong.Tan@Sun.COM else 9807678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 9817678SYong.Tan@Sun.COM } 9826512Ssowmini else 9836512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx; 9845903Ssowmini break; 9856789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 9867678SYong.Tan@Sun.COM if (is_default) { 9877678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9887678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 9897678SYong.Tan@Sun.COM else 9907678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 9917678SYong.Tan@Sun.COM } 9926512Ssowmini else 9936512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx; 9945903Ssowmini break; 9956789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 9968118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 9977678SYong.Tan@Sun.COM if (is_default) { 9987678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 9997678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 10007678SYong.Tan@Sun.COM else 10017678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 10027678SYong.Tan@Sun.COM } 10036512Ssowmini else 10046512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx; 10055903Ssowmini break; 10066789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 10077678SYong.Tan@Sun.COM if (is_default) { 10087678SYong.Tan@Sun.COM if (DEVICE_5906_SERIES_CHIPSETS(bgep)) 10097678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 0; 10107678SYong.Tan@Sun.COM else 10117678SYong.Tan@Sun.COM *(uint8_t *)pr_val = 1; 10127678SYong.Tan@Sun.COM } 10136512Ssowmini else 10146512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx; 10155903Ssowmini break; 10166789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 10178118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10186512Ssowmini if (is_default) { 10196512Ssowmini *(uint8_t *)pr_val = 10206512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10216512Ssowmini } else { 10226512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx; 10236512Ssowmini } 10245903Ssowmini break; 10256789Sam223141 case MAC_PROP_EN_100FDX_CAP: 10266512Ssowmini if (is_default) { 10276512Ssowmini *(uint8_t *)pr_val = 10286512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10296512Ssowmini } else { 10306512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx; 10316512Ssowmini } 10325903Ssowmini break; 10336789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 10348118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10356512Ssowmini if (is_default) { 10366512Ssowmini *(uint8_t *)pr_val = 10376512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10386512Ssowmini } else { 10396512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx; 10406512Ssowmini } 10415903Ssowmini break; 10426789Sam223141 case MAC_PROP_EN_100HDX_CAP: 10436512Ssowmini if (is_default) { 10446512Ssowmini *(uint8_t *)pr_val = 10456512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10466512Ssowmini } else { 10476512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx; 10486512Ssowmini } 10495903Ssowmini break; 10506789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 10518118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10526512Ssowmini if (is_default) { 10536512Ssowmini *(uint8_t *)pr_val = 10546512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10556512Ssowmini } else { 10566512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx; 10576512Ssowmini } 10585903Ssowmini break; 10596789Sam223141 case MAC_PROP_EN_10FDX_CAP: 10606512Ssowmini if (is_default) { 10616512Ssowmini *(uint8_t *)pr_val = 10626512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10636512Ssowmini } else { 10646512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx; 10656512Ssowmini } 10665903Ssowmini break; 10676789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 10688118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10696512Ssowmini if (is_default) { 10706512Ssowmini *(uint8_t *)pr_val = 10716512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10726512Ssowmini } else { 10736512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx; 10746512Ssowmini } 10755903Ssowmini break; 10766789Sam223141 case MAC_PROP_EN_10HDX_CAP: 10776512Ssowmini if (is_default) { 10786512Ssowmini *(uint8_t *)pr_val = 10796512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 10806512Ssowmini } else { 10816512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx; 10826512Ssowmini } 10835903Ssowmini break; 10846789Sam223141 case MAC_PROP_ADV_100T4_CAP: 10856789Sam223141 case MAC_PROP_EN_100T4_CAP: 10868118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 10876512Ssowmini *(uint8_t *)pr_val = 0; 10886512Ssowmini break; 10896789Sam223141 case MAC_PROP_PRIVATE: 10906512Ssowmini err = bge_get_priv_prop(bgep, pr_name, pr_flags, 10916512Ssowmini pr_valsize, pr_val); 10926512Ssowmini return (err); 10939514SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: { 10949514SGirish.Moodalbail@Sun.COM mac_propval_range_t range; 10959514SGirish.Moodalbail@Sun.COM 10969514SGirish.Moodalbail@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 10979514SGirish.Moodalbail@Sun.COM return (ENOTSUP); 10989514SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 10999514SGirish.Moodalbail@Sun.COM return (EINVAL); 11009514SGirish.Moodalbail@Sun.COM range.mpr_count = 1; 11019514SGirish.Moodalbail@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 11029514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_min = 11039514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = BGE_DEFAULT_MTU; 11049514SGirish.Moodalbail@Sun.COM if (bge_jumbo_enable && !(flags & CHIP_FLAG_NO_JUMBO)) 11059514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = 11069514SGirish.Moodalbail@Sun.COM BGE_MAXIMUM_MTU; 11079514SGirish.Moodalbail@Sun.COM bcopy(&range, pr_val, sizeof (range)); 11089514SGirish.Moodalbail@Sun.COM break; 11099514SGirish.Moodalbail@Sun.COM } 11105903Ssowmini default: 11116512Ssowmini return (ENOTSUP); 11125903Ssowmini } 11135903Ssowmini return (0); 11145903Ssowmini } 11155903Ssowmini 11165903Ssowmini /* ARGSUSED */ 11175903Ssowmini static int 11185903Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, 11195903Ssowmini const void *pr_val) 11205903Ssowmini { 11215903Ssowmini int err = 0; 11225903Ssowmini long result; 11235903Ssowmini 11246512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 11256512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11266512Ssowmini if (result > 1 || result < 0) { 11276512Ssowmini err = EINVAL; 11286512Ssowmini } else { 11297099Syt223700 bgep->param_adv_pause = (uint32_t)result; 11306512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11316512Ssowmini err = EINVAL; 11326512Ssowmini } 11336512Ssowmini return (err); 11346512Ssowmini } 11356512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 11366512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11376512Ssowmini if (result > 1 || result < 0) { 11386512Ssowmini err = EINVAL; 11396512Ssowmini } else { 11407099Syt223700 bgep->param_adv_asym_pause = (uint32_t)result; 11416512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11426512Ssowmini err = EINVAL; 11436512Ssowmini } 11446512Ssowmini return (err); 11456512Ssowmini } 11465903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 11475903Ssowmini 11485903Ssowmini /* 11495903Ssowmini * on the Tx side, we need to update the h/w register for 11505903Ssowmini * real packet transmission per packet. The drain_max parameter 11515903Ssowmini * is used to reduce the register access. This parameter 11525903Ssowmini * controls the max number of packets that we will hold before 11535903Ssowmini * updating the bge h/w to trigger h/w transmit. The bge 11545903Ssowmini * chipset usually has a max of 512 Tx descriptors, thus 11555903Ssowmini * the upper bound on drain_max is 512. 11565903Ssowmini */ 11575903Ssowmini if (pr_val == NULL) { 11585903Ssowmini err = EINVAL; 11595903Ssowmini return (err); 11605903Ssowmini } 11615903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11625903Ssowmini if (result > 512 || result < 1) 11635903Ssowmini err = EINVAL; 11645903Ssowmini else { 11655903Ssowmini bgep->param_drain_max = (uint32_t)result; 11665903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11675903Ssowmini err = EINVAL; 11685903Ssowmini } 11695903Ssowmini return (err); 11705903Ssowmini } 11715903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 11725903Ssowmini 11735903Ssowmini if (pr_val == NULL) { 11745903Ssowmini err = EINVAL; 11755903Ssowmini return (err); 11765903Ssowmini } 11775903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11785903Ssowmini if (result > 7 || result < 0) 11795903Ssowmini err = EINVAL; 11805903Ssowmini else { 11815903Ssowmini bgep->param_msi_cnt = (uint32_t)result; 11825903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 11835903Ssowmini err = EINVAL; 11845903Ssowmini } 11855903Ssowmini return (err); 11865903Ssowmini } 11879731SYong.Tan@Sun.COM if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0) { 11889731SYong.Tan@Sun.COM if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 11899731SYong.Tan@Sun.COM return (EINVAL); 11909731SYong.Tan@Sun.COM if (result < 0) 11919731SYong.Tan@Sun.COM err = EINVAL; 11929731SYong.Tan@Sun.COM else { 11939731SYong.Tan@Sun.COM bgep->chipid.rx_ticks_norm = (uint32_t)result; 11949731SYong.Tan@Sun.COM bge_chip_coalesce_update(bgep); 11959731SYong.Tan@Sun.COM } 11969731SYong.Tan@Sun.COM return (err); 11979731SYong.Tan@Sun.COM } 11989731SYong.Tan@Sun.COM 11999731SYong.Tan@Sun.COM if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0) { 12006512Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 12015903Ssowmini return (EINVAL); 12025903Ssowmini 12039731SYong.Tan@Sun.COM if (result < 0) 12049731SYong.Tan@Sun.COM err = EINVAL; 12059731SYong.Tan@Sun.COM else { 12069731SYong.Tan@Sun.COM bgep->chipid.rx_count_norm = (uint32_t)result; 12079731SYong.Tan@Sun.COM bge_chip_coalesce_update(bgep); 12089731SYong.Tan@Sun.COM } 12099731SYong.Tan@Sun.COM return (err); 12105903Ssowmini } 12119731SYong.Tan@Sun.COM if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0) { 12125903Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 12135903Ssowmini return (EINVAL); 12149731SYong.Tan@Sun.COM if (result < 0) 12159731SYong.Tan@Sun.COM err = EINVAL; 12169731SYong.Tan@Sun.COM else { 12179731SYong.Tan@Sun.COM bgep->chipid.tx_ticks_norm = (uint32_t)result; 12189731SYong.Tan@Sun.COM bge_chip_coalesce_update(bgep); 12199731SYong.Tan@Sun.COM } 12209731SYong.Tan@Sun.COM return (err); 12219731SYong.Tan@Sun.COM } 12229731SYong.Tan@Sun.COM 12239731SYong.Tan@Sun.COM if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0) { 12249731SYong.Tan@Sun.COM if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 12259731SYong.Tan@Sun.COM return (EINVAL); 12269731SYong.Tan@Sun.COM 12279731SYong.Tan@Sun.COM if (result < 0) 12289731SYong.Tan@Sun.COM err = EINVAL; 12299731SYong.Tan@Sun.COM else { 12309731SYong.Tan@Sun.COM bgep->chipid.tx_count_norm = (uint32_t)result; 12319731SYong.Tan@Sun.COM bge_chip_coalesce_update(bgep); 12329731SYong.Tan@Sun.COM } 12339731SYong.Tan@Sun.COM return (err); 12345903Ssowmini } 12356512Ssowmini return (ENOTSUP); 12365903Ssowmini } 12375903Ssowmini 12385903Ssowmini static int 12396512Ssowmini bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_flags, 12406512Ssowmini uint_t pr_valsize, void *pr_val) 12415903Ssowmini { 12426512Ssowmini int err = ENOTSUP; 12436789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 12446512Ssowmini int value; 12456512Ssowmini 12466512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 12476512Ssowmini value = (is_default? 1 : bge->param_adv_pause); 12486512Ssowmini err = 0; 12496512Ssowmini goto done; 12506512Ssowmini } 12516512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 12526512Ssowmini value = (is_default? 1 : bge->param_adv_asym_pause); 12536512Ssowmini err = 0; 12546512Ssowmini goto done; 12556512Ssowmini } 12565903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 12576512Ssowmini value = (is_default? 64 : bge->param_drain_max); 12585903Ssowmini err = 0; 12595903Ssowmini goto done; 12605903Ssowmini } 12615903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 12626512Ssowmini value = (is_default? 0 : bge->param_msi_cnt); 12635903Ssowmini err = 0; 12645903Ssowmini goto done; 12655903Ssowmini } 12665903Ssowmini 12675903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 12686512Ssowmini value = (is_default? bge_rx_ticks_norm : 12696512Ssowmini bge->chipid.rx_ticks_norm); 12705903Ssowmini err = 0; 12715903Ssowmini goto done; 12725903Ssowmini } 12735903Ssowmini 12745903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 12756512Ssowmini value = (is_default? bge_rx_count_norm : 12766512Ssowmini bge->chipid.rx_count_norm); 12775903Ssowmini err = 0; 12785903Ssowmini goto done; 12795903Ssowmini } 12805903Ssowmini 12815903Ssowmini done: 12826512Ssowmini if (err == 0) { 12836512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 12845903Ssowmini } 12855903Ssowmini return (err); 12865903Ssowmini } 12875903Ssowmini 12882331Skrgopi /* 12891369Sdduvall * Compute the index of the required bit in the multicast hash map. 12901369Sdduvall * This must mirror the way the hardware actually does it! 12911369Sdduvall * See Broadcom document 570X-PG102-R page 125. 12921369Sdduvall */ 12931369Sdduvall static uint32_t 12941369Sdduvall bge_hash_index(const uint8_t *mca) 12951369Sdduvall { 12961369Sdduvall uint32_t hash; 12971369Sdduvall 12981369Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 12991369Sdduvall 13001369Sdduvall return (hash); 13011369Sdduvall } 13021369Sdduvall 13031369Sdduvall /* 13041369Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 13051369Sdduvall */ 13061369Sdduvall static int 13071369Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 13081369Sdduvall { 13091369Sdduvall bge_t *bgep = arg; /* private device info */ 13101369Sdduvall uint32_t hash; 13111369Sdduvall uint32_t index; 13121369Sdduvall uint32_t word; 13131369Sdduvall uint32_t bit; 13141369Sdduvall uint8_t *refp; 13151369Sdduvall 13161369Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 13174588Sml149210 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 13181369Sdduvall 13191369Sdduvall /* 13201369Sdduvall * Precalculate all required masks, pointers etc ... 13211369Sdduvall */ 13221369Sdduvall hash = bge_hash_index(mca); 13231369Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 13241369Sdduvall word = index/32u; 13251369Sdduvall bit = 1 << (index % 32u); 13261369Sdduvall refp = &bgep->mcast_refs[index]; 13271369Sdduvall 13281369Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 13294588Sml149210 hash, index, word, bit, *refp)); 13301369Sdduvall 13311369Sdduvall /* 13321369Sdduvall * We must set the appropriate bit in the hash map (and the 13331369Sdduvall * corresponding h/w register) when the refcount goes from 0 13341369Sdduvall * to >0, and clear it when the last ref goes away (refcount 13351369Sdduvall * goes from >0 back to 0). If we change the hash map, we 13361369Sdduvall * must also update the chip's hardware map registers. 13371369Sdduvall */ 13381369Sdduvall mutex_enter(bgep->genlock); 13391865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 13401865Sdilpreet /* can happen during autorecovery */ 13411865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13421865Sdilpreet mutex_exit(bgep->genlock); 13431865Sdilpreet return (EIO); 13441865Sdilpreet } 13451369Sdduvall if (add) { 13461369Sdduvall if ((*refp)++ == 0) { 13471369Sdduvall bgep->mcast_hash[word] |= bit; 13481408Srandyf #ifdef BGE_IPMI_ASF 13491865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 13501408Srandyf #else 13511865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 13521408Srandyf #endif 13531865Sdilpreet (void) bge_check_acc_handle(bgep, 13541865Sdilpreet bgep->cfg_handle); 13551865Sdilpreet (void) bge_check_acc_handle(bgep, 13561865Sdilpreet bgep->io_handle); 13571865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 13581865Sdilpreet DDI_SERVICE_DEGRADED); 13591865Sdilpreet mutex_exit(bgep->genlock); 13601865Sdilpreet return (EIO); 13611865Sdilpreet } 13621369Sdduvall } 13631369Sdduvall } else { 13641369Sdduvall if (--(*refp) == 0) { 13651369Sdduvall bgep->mcast_hash[word] &= ~bit; 13661408Srandyf #ifdef BGE_IPMI_ASF 13671865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 13681408Srandyf #else 13691865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 13701408Srandyf #endif 13711865Sdilpreet (void) bge_check_acc_handle(bgep, 13721865Sdilpreet bgep->cfg_handle); 13731865Sdilpreet (void) bge_check_acc_handle(bgep, 13741865Sdilpreet bgep->io_handle); 13751865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 13761865Sdilpreet DDI_SERVICE_DEGRADED); 13771865Sdilpreet mutex_exit(bgep->genlock); 13781865Sdilpreet return (EIO); 13791865Sdilpreet } 13801369Sdduvall } 13811369Sdduvall } 13821369Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 13831865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 13841865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13851865Sdilpreet mutex_exit(bgep->genlock); 13861865Sdilpreet return (EIO); 13871865Sdilpreet } 13881865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 13891865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 13901865Sdilpreet mutex_exit(bgep->genlock); 13911865Sdilpreet return (EIO); 13921865Sdilpreet } 13931369Sdduvall mutex_exit(bgep->genlock); 13941369Sdduvall 13951369Sdduvall return (0); 13961369Sdduvall } 13971369Sdduvall 13981369Sdduvall /* 13991369Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 14001369Sdduvall * 14011369Sdduvall * Program the hardware to enable/disable promiscuous and/or 14021369Sdduvall * receive-all-multicast modes. 14031369Sdduvall */ 14041369Sdduvall static int 14051369Sdduvall bge_m_promisc(void *arg, boolean_t on) 14061369Sdduvall { 14071369Sdduvall bge_t *bgep = arg; 14081369Sdduvall 14091369Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 14101369Sdduvall 14111369Sdduvall /* 14121369Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 14131369Sdduvall */ 14141369Sdduvall mutex_enter(bgep->genlock); 14151865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 14161865Sdilpreet /* can happen during autorecovery */ 14171865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14181865Sdilpreet mutex_exit(bgep->genlock); 14191865Sdilpreet return (EIO); 14201865Sdilpreet } 14211369Sdduvall bgep->promisc = on; 14221408Srandyf #ifdef BGE_IPMI_ASF 14231865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 14241408Srandyf #else 14251865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 14261408Srandyf #endif 14271865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 14281865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 14291865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14301865Sdilpreet mutex_exit(bgep->genlock); 14311865Sdilpreet return (EIO); 14321865Sdilpreet } 14331369Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 14341865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 14351865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14361865Sdilpreet mutex_exit(bgep->genlock); 14371865Sdilpreet return (EIO); 14381865Sdilpreet } 14391865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 14401865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14411865Sdilpreet mutex_exit(bgep->genlock); 14421865Sdilpreet return (EIO); 14431865Sdilpreet } 14441369Sdduvall mutex_exit(bgep->genlock); 14451369Sdduvall return (0); 14461369Sdduvall } 14471369Sdduvall 14488275SEric Cheng /* 14498275SEric Cheng * Find the slot for the specified unicast address 14508275SEric Cheng */ 14518275SEric Cheng int 14528275SEric Cheng bge_unicst_find(bge_t *bgep, const uint8_t *mac_addr) 14538275SEric Cheng { 14548275SEric Cheng int slot; 14558275SEric Cheng 14568275SEric Cheng ASSERT(mutex_owned(bgep->genlock)); 14578275SEric Cheng 14588275SEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 14598275SEric Cheng if (bcmp(bgep->curr_addr[slot].addr, mac_addr, ETHERADDRL) == 0) 14608275SEric Cheng return (slot); 14618275SEric Cheng } 14628275SEric Cheng 14638275SEric Cheng return (-1); 14648275SEric Cheng } 14658275SEric Cheng 14668275SEric Cheng /* 14678275SEric Cheng * Programs the classifier to start steering packets matching 'mac_addr' to the 14688275SEric Cheng * specified ring 'arg'. 14698275SEric Cheng */ 14708275SEric Cheng static int 14718275SEric Cheng bge_addmac(void *arg, const uint8_t *mac_addr) 14728275SEric Cheng { 14738275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 14748275SEric Cheng bge_t *bgep = rrp->bgep; 14758275SEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 14768275SEric Cheng bge_rule_info_t *rinfop = NULL; 14778275SEric Cheng uint8_t ring = (uint8_t)(rrp - bgep->recv) + 1; 14788275SEric Cheng int i; 14798275SEric Cheng uint16_t tmp16; 14808275SEric Cheng uint32_t tmp32; 14818275SEric Cheng int slot; 14828275SEric Cheng int err; 14838275SEric Cheng 14848275SEric Cheng mutex_enter(bgep->genlock); 14858275SEric Cheng if (bgep->unicst_addr_avail == 0) { 14868275SEric Cheng mutex_exit(bgep->genlock); 14878275SEric Cheng return (ENOSPC); 14888275SEric Cheng } 14898275SEric Cheng 14908275SEric Cheng /* 14918275SEric Cheng * First add the unicast address to a available slot. 14928275SEric Cheng */ 14938275SEric Cheng slot = bge_unicst_find(bgep, mac_addr); 14948275SEric Cheng ASSERT(slot == -1); 14958275SEric Cheng 14968275SEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) { 14978275SEric Cheng if (!bgep->curr_addr[slot].set) { 14988275SEric Cheng bgep->curr_addr[slot].set = B_TRUE; 14998275SEric Cheng break; 15008275SEric Cheng } 15018275SEric Cheng } 15028275SEric Cheng 15038275SEric Cheng ASSERT(slot < bgep->unicst_addr_total); 15048275SEric Cheng bgep->unicst_addr_avail--; 15058275SEric Cheng mutex_exit(bgep->genlock); 15068275SEric Cheng 15078275SEric Cheng if ((err = bge_unicst_set(bgep, mac_addr, slot)) != 0) 15088275SEric Cheng goto fail; 15098275SEric Cheng 15108275SEric Cheng /* A rule is already here. Deny this. */ 15118275SEric Cheng if (rrp->mac_addr_rule != NULL) { 15128275SEric Cheng err = ether_cmp(mac_addr, rrp->mac_addr_val) ? EEXIST : EBUSY; 15138275SEric Cheng goto fail; 15148275SEric Cheng } 15158275SEric Cheng 15168275SEric Cheng /* 15178275SEric Cheng * Allocate a bge_rule_info_t to keep track of which rule slots 15188275SEric Cheng * are being used. 15198275SEric Cheng */ 15208275SEric Cheng rinfop = kmem_zalloc(sizeof (bge_rule_info_t), KM_NOSLEEP); 15218275SEric Cheng if (rinfop == NULL) { 15228275SEric Cheng err = ENOMEM; 15238275SEric Cheng goto fail; 15248275SEric Cheng } 15258275SEric Cheng 15268275SEric Cheng /* 15278275SEric Cheng * Look for the starting slot to place the rules. 15288275SEric Cheng * The two slots we reserve must be contiguous. 15298275SEric Cheng */ 15308275SEric Cheng for (i = 0; i + 1 < RECV_RULES_NUM_MAX; i++) 15318275SEric Cheng if ((rulep[i].control & RECV_RULE_CTL_ENABLE) == 0 && 15328275SEric Cheng (rulep[i+1].control & RECV_RULE_CTL_ENABLE) == 0) 15338275SEric Cheng break; 15348275SEric Cheng 15358275SEric Cheng ASSERT(i + 1 < RECV_RULES_NUM_MAX); 15368275SEric Cheng 15378275SEric Cheng bcopy(mac_addr, &tmp32, sizeof (tmp32)); 15388275SEric Cheng rulep[i].mask_value = ntohl(tmp32); 15398275SEric Cheng rulep[i].control = RULE_DEST_MAC_1(ring) | RECV_RULE_CTL_AND; 15408275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep[i].mask_value); 15418275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep[i].control); 15428275SEric Cheng 15438275SEric Cheng bcopy(mac_addr + 4, &tmp16, sizeof (tmp16)); 15448275SEric Cheng rulep[i+1].mask_value = 0xffff0000 | ntohs(tmp16); 15458275SEric Cheng rulep[i+1].control = RULE_DEST_MAC_2(ring); 15468275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i+1), rulep[i+1].mask_value); 15478275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i+1), rulep[i+1].control); 15488275SEric Cheng rinfop->start = i; 15498275SEric Cheng rinfop->count = 2; 15508275SEric Cheng 15518275SEric Cheng rrp->mac_addr_rule = rinfop; 15528275SEric Cheng bcopy(mac_addr, rrp->mac_addr_val, ETHERADDRL); 15538275SEric Cheng 15548275SEric Cheng return (0); 15558275SEric Cheng 15568275SEric Cheng fail: 15578275SEric Cheng /* Clear the address just set */ 15588275SEric Cheng (void) bge_unicst_set(bgep, zero_addr, slot); 15598275SEric Cheng mutex_enter(bgep->genlock); 15608275SEric Cheng bgep->curr_addr[slot].set = B_FALSE; 15618275SEric Cheng bgep->unicst_addr_avail++; 15628275SEric Cheng mutex_exit(bgep->genlock); 15638275SEric Cheng 15648275SEric Cheng return (err); 15658275SEric Cheng } 15668275SEric Cheng 15678275SEric Cheng /* 15688275SEric Cheng * Stop classifying packets matching the MAC address to the specified ring. 15698275SEric Cheng */ 15708275SEric Cheng static int 15718275SEric Cheng bge_remmac(void *arg, const uint8_t *mac_addr) 15728275SEric Cheng { 15738275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg; 15748275SEric Cheng bge_t *bgep = rrp->bgep; 15758275SEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules; 15768275SEric Cheng bge_rule_info_t *rinfop = rrp->mac_addr_rule; 15778275SEric Cheng int start; 15788275SEric Cheng int slot; 15798275SEric Cheng int err; 15808275SEric Cheng 15818275SEric Cheng /* 15828275SEric Cheng * Remove the MAC address from its slot. 15838275SEric Cheng */ 15848275SEric Cheng mutex_enter(bgep->genlock); 15858275SEric Cheng slot = bge_unicst_find(bgep, mac_addr); 15868275SEric Cheng if (slot == -1) { 15878275SEric Cheng mutex_exit(bgep->genlock); 15888275SEric Cheng return (EINVAL); 15898275SEric Cheng } 15908275SEric Cheng 15918275SEric Cheng ASSERT(bgep->curr_addr[slot].set); 15928275SEric Cheng mutex_exit(bgep->genlock); 15938275SEric Cheng 15948275SEric Cheng if ((err = bge_unicst_set(bgep, zero_addr, slot)) != 0) 15958275SEric Cheng return (err); 15968275SEric Cheng 15978275SEric Cheng if (rinfop == NULL || ether_cmp(mac_addr, rrp->mac_addr_val) != 0) 15988275SEric Cheng return (EINVAL); 15998275SEric Cheng 16008275SEric Cheng start = rinfop->start; 16018275SEric Cheng rulep[start].mask_value = 0; 16028275SEric Cheng rulep[start].control = 0; 16038275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 16048275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 16058275SEric Cheng start++; 16068275SEric Cheng rulep[start].mask_value = 0; 16078275SEric Cheng rulep[start].control = 0; 16088275SEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value); 16098275SEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control); 16108275SEric Cheng 16118275SEric Cheng kmem_free(rinfop, sizeof (bge_rule_info_t)); 16128275SEric Cheng rrp->mac_addr_rule = NULL; 16138275SEric Cheng bzero(rrp->mac_addr_val, ETHERADDRL); 16148275SEric Cheng 16158275SEric Cheng mutex_enter(bgep->genlock); 16168275SEric Cheng bgep->curr_addr[slot].set = B_FALSE; 16178275SEric Cheng bgep->unicst_addr_avail++; 16188275SEric Cheng mutex_exit(bgep->genlock); 16198275SEric Cheng 16208275SEric Cheng return (0); 16218275SEric Cheng } 16228275SEric Cheng 16238275SEric Cheng static int 16248275SEric Cheng bge_flag_intr_enable(mac_intr_handle_t ih) 16258275SEric Cheng { 16268275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 16278275SEric Cheng bge_t *bgep = rrp->bgep; 16288275SEric Cheng 16298275SEric Cheng mutex_enter(bgep->genlock); 16308275SEric Cheng rrp->poll_flag = 0; 16318275SEric Cheng mutex_exit(bgep->genlock); 16328275SEric Cheng 16338275SEric Cheng return (0); 16348275SEric Cheng } 16358275SEric Cheng 16368275SEric Cheng static int 16378275SEric Cheng bge_flag_intr_disable(mac_intr_handle_t ih) 16388275SEric Cheng { 16398275SEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih; 16408275SEric Cheng bge_t *bgep = rrp->bgep; 16418275SEric Cheng 16428275SEric Cheng mutex_enter(bgep->genlock); 16438275SEric Cheng rrp->poll_flag = 1; 16448275SEric Cheng mutex_exit(bgep->genlock); 16458275SEric Cheng 16468275SEric Cheng return (0); 16478275SEric Cheng } 16488275SEric Cheng 16498275SEric Cheng static int 16508275SEric Cheng bge_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 16518275SEric Cheng { 16528275SEric Cheng recv_ring_t *rx_ring; 16538275SEric Cheng 16548275SEric Cheng rx_ring = (recv_ring_t *)rh; 16558275SEric Cheng mutex_enter(rx_ring->rx_lock); 16568275SEric Cheng rx_ring->ring_gen_num = mr_gen_num; 16578275SEric Cheng mutex_exit(rx_ring->rx_lock); 16588275SEric Cheng return (0); 16598275SEric Cheng } 16608275SEric Cheng 16618275SEric Cheng 16628275SEric Cheng /* 16638275SEric Cheng * Callback funtion for MAC layer to register all rings 16648275SEric Cheng * for given ring_group, noted by rg_index. 16658275SEric Cheng */ 16668275SEric Cheng void 16678275SEric Cheng bge_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, 16688275SEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh) 16698275SEric Cheng { 16708275SEric Cheng bge_t *bgep = arg; 16718275SEric Cheng mac_intr_t *mintr; 16728275SEric Cheng 16738275SEric Cheng switch (rtype) { 16748275SEric Cheng case MAC_RING_TYPE_RX: { 16758275SEric Cheng recv_ring_t *rx_ring; 16768275SEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 16778275SEric Cheng MAC_ADDRESS_REGS_MAX) && index == 0); 16788275SEric Cheng 16798275SEric Cheng rx_ring = &bgep->recv[rg_index]; 16808275SEric Cheng rx_ring->ring_handle = rh; 16818275SEric Cheng 16828275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 16838275SEric Cheng infop->mri_start = bge_ring_start; 16848275SEric Cheng infop->mri_stop = NULL; 16858275SEric Cheng infop->mri_poll = bge_poll_ring; 16868275SEric Cheng 16878275SEric Cheng mintr = &infop->mri_intr; 16888275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 16898275SEric Cheng mintr->mi_enable = bge_flag_intr_enable; 16908275SEric Cheng mintr->mi_disable = bge_flag_intr_disable; 16918275SEric Cheng 16928275SEric Cheng break; 16938275SEric Cheng } 16948275SEric Cheng case MAC_RING_TYPE_TX: 16958275SEric Cheng default: 16968275SEric Cheng ASSERT(0); 16978275SEric Cheng break; 16988275SEric Cheng } 16998275SEric Cheng } 17008275SEric Cheng 17018275SEric Cheng /* 17028275SEric Cheng * Fill infop passed as argument 17038275SEric Cheng * fill in respective ring_group info 17048275SEric Cheng * Each group has a single ring in it. We keep it simple 17058275SEric Cheng * and use the same internal handle for rings and groups. 17068275SEric Cheng */ 17078275SEric Cheng void 17088275SEric Cheng bge_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index, 17098275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 17108275SEric Cheng { 17118275SEric Cheng bge_t *bgep = arg; 17128275SEric Cheng 17138275SEric Cheng switch (rtype) { 17148275SEric Cheng case MAC_RING_TYPE_RX: { 17158275SEric Cheng recv_ring_t *rx_ring; 17168275SEric Cheng 17178275SEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings, 17188275SEric Cheng MAC_ADDRESS_REGS_MAX)); 17198275SEric Cheng rx_ring = &bgep->recv[rg_index]; 17208275SEric Cheng rx_ring->ring_group_handle = gh; 17218275SEric Cheng 17228275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring; 17238275SEric Cheng infop->mgi_start = NULL; 17248275SEric Cheng infop->mgi_stop = NULL; 17258275SEric Cheng infop->mgi_addmac = bge_addmac; 17268275SEric Cheng infop->mgi_remmac = bge_remmac; 17278275SEric Cheng infop->mgi_count = 1; 17288275SEric Cheng break; 17298275SEric Cheng } 17308275SEric Cheng case MAC_RING_TYPE_TX: 17318275SEric Cheng default: 17328275SEric Cheng ASSERT(0); 17338275SEric Cheng break; 17348275SEric Cheng } 17358275SEric Cheng } 17368275SEric Cheng 17372311Sseb /*ARGSUSED*/ 17382311Sseb static boolean_t 17392311Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 17402311Sseb { 17412331Skrgopi bge_t *bgep = arg; 17422331Skrgopi 17432311Sseb switch (cap) { 17442311Sseb case MAC_CAPAB_HCKSUM: { 17452311Sseb uint32_t *txflags = cap_data; 17462311Sseb 17472311Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 17482311Sseb break; 17492311Sseb } 17508275SEric Cheng case MAC_CAPAB_RINGS: { 17518275SEric Cheng mac_capab_rings_t *cap_rings = cap_data; 17528275SEric Cheng 17538275SEric Cheng /* Temporarily disable multiple tx rings. */ 17548275SEric Cheng if (cap_rings->mr_type != MAC_RING_TYPE_RX) 17558275SEric Cheng return (B_FALSE); 17568275SEric Cheng 17578275SEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 17588275SEric Cheng cap_rings->mr_rnum = cap_rings->mr_gnum = 17598275SEric Cheng MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX); 17608275SEric Cheng cap_rings->mr_rget = bge_fill_ring; 17618275SEric Cheng cap_rings->mr_gget = bge_fill_group; 17622331Skrgopi break; 17632331Skrgopi } 17642311Sseb default: 17652311Sseb return (B_FALSE); 17662311Sseb } 17672311Sseb return (B_TRUE); 17682311Sseb } 17692311Sseb 17701369Sdduvall /* 17711369Sdduvall * Loopback ioctl code 17721369Sdduvall */ 17731369Sdduvall 17741369Sdduvall static lb_property_t loopmodes[] = { 17751369Sdduvall { normal, "normal", BGE_LOOP_NONE }, 17761369Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 17771369Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 17781369Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 17791369Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 17801369Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 17811369Sdduvall }; 17821369Sdduvall 17831369Sdduvall static enum ioc_reply 17841369Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 17851369Sdduvall { 17861369Sdduvall /* 17871369Sdduvall * If the mode isn't being changed, there's nothing to do ... 17881369Sdduvall */ 17891369Sdduvall if (mode == bgep->param_loop_mode) 17901369Sdduvall return (IOC_ACK); 17911369Sdduvall 17921369Sdduvall /* 17931369Sdduvall * Validate the requested mode and prepare a suitable message 17941369Sdduvall * to explain the link down/up cycle that the change will 17951369Sdduvall * probably induce ... 17961369Sdduvall */ 17971369Sdduvall switch (mode) { 17981369Sdduvall default: 17991369Sdduvall return (IOC_INVAL); 18001369Sdduvall 18011369Sdduvall case BGE_LOOP_NONE: 18021369Sdduvall case BGE_LOOP_EXTERNAL_1000: 18031369Sdduvall case BGE_LOOP_EXTERNAL_100: 18041369Sdduvall case BGE_LOOP_EXTERNAL_10: 18051369Sdduvall case BGE_LOOP_INTERNAL_PHY: 18061369Sdduvall case BGE_LOOP_INTERNAL_MAC: 18071369Sdduvall break; 18081369Sdduvall } 18091369Sdduvall 18101369Sdduvall /* 18111369Sdduvall * All OK; tell the caller to reprogram 18121369Sdduvall * the PHY and/or MAC for the new mode ... 18131369Sdduvall */ 18141369Sdduvall bgep->param_loop_mode = mode; 18151369Sdduvall return (IOC_RESTART_ACK); 18161369Sdduvall } 18171369Sdduvall 18181369Sdduvall static enum ioc_reply 18191369Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 18201369Sdduvall { 18211369Sdduvall lb_info_sz_t *lbsp; 18221369Sdduvall lb_property_t *lbpp; 18231369Sdduvall uint32_t *lbmp; 18241369Sdduvall int cmd; 18251369Sdduvall 18261369Sdduvall _NOTE(ARGUNUSED(wq)) 18271369Sdduvall 18281369Sdduvall /* 18291369Sdduvall * Validate format of ioctl 18301369Sdduvall */ 18311369Sdduvall if (mp->b_cont == NULL) 18321369Sdduvall return (IOC_INVAL); 18331369Sdduvall 18341369Sdduvall cmd = iocp->ioc_cmd; 18351369Sdduvall switch (cmd) { 18361369Sdduvall default: 18371369Sdduvall /* NOTREACHED */ 18381369Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 18391369Sdduvall return (IOC_INVAL); 18401369Sdduvall 18411369Sdduvall case LB_GET_INFO_SIZE: 18421369Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 18431369Sdduvall return (IOC_INVAL); 18447099Syt223700 lbsp = (void *)mp->b_cont->b_rptr; 18451369Sdduvall *lbsp = sizeof (loopmodes); 18461369Sdduvall return (IOC_REPLY); 18471369Sdduvall 18481369Sdduvall case LB_GET_INFO: 18491369Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 18501369Sdduvall return (IOC_INVAL); 18517099Syt223700 lbpp = (void *)mp->b_cont->b_rptr; 18521369Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 18531369Sdduvall return (IOC_REPLY); 18541369Sdduvall 18551369Sdduvall case LB_GET_MODE: 18561369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 18571369Sdduvall return (IOC_INVAL); 18587099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 18591369Sdduvall *lbmp = bgep->param_loop_mode; 18601369Sdduvall return (IOC_REPLY); 18611369Sdduvall 18621369Sdduvall case LB_SET_MODE: 18631369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 18641369Sdduvall return (IOC_INVAL); 18657099Syt223700 lbmp = (void *)mp->b_cont->b_rptr; 18661369Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 18671369Sdduvall } 18681369Sdduvall } 18691369Sdduvall 18701369Sdduvall /* 18711369Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 18721369Sdduvall */ 18731369Sdduvall static void 18741369Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 18751369Sdduvall { 18761369Sdduvall bge_t *bgep = arg; 18771369Sdduvall struct iocblk *iocp; 18781369Sdduvall enum ioc_reply status; 18791369Sdduvall boolean_t need_privilege; 18801369Sdduvall int err; 18811369Sdduvall int cmd; 18821369Sdduvall 18831369Sdduvall /* 18841369Sdduvall * Validate the command before bothering with the mutex ... 18851369Sdduvall */ 18867099Syt223700 iocp = (void *)mp->b_rptr; 18871369Sdduvall iocp->ioc_error = 0; 18881369Sdduvall need_privilege = B_TRUE; 18891369Sdduvall cmd = iocp->ioc_cmd; 18901369Sdduvall switch (cmd) { 18911369Sdduvall default: 18921369Sdduvall miocnak(wq, mp, 0, EINVAL); 18931369Sdduvall return; 18941369Sdduvall 18951369Sdduvall case BGE_MII_READ: 18961369Sdduvall case BGE_MII_WRITE: 18971369Sdduvall case BGE_SEE_READ: 18981369Sdduvall case BGE_SEE_WRITE: 18992675Szh199473 case BGE_FLASH_READ: 19002675Szh199473 case BGE_FLASH_WRITE: 19011369Sdduvall case BGE_DIAG: 19021369Sdduvall case BGE_PEEK: 19031369Sdduvall case BGE_POKE: 19041369Sdduvall case BGE_PHY_RESET: 19051369Sdduvall case BGE_SOFT_RESET: 19061369Sdduvall case BGE_HARD_RESET: 19071369Sdduvall break; 19081369Sdduvall 19091369Sdduvall case LB_GET_INFO_SIZE: 19101369Sdduvall case LB_GET_INFO: 19111369Sdduvall case LB_GET_MODE: 19121369Sdduvall need_privilege = B_FALSE; 19131369Sdduvall /* FALLTHRU */ 19141369Sdduvall case LB_SET_MODE: 19151369Sdduvall break; 19161369Sdduvall 19171369Sdduvall } 19181369Sdduvall 19191369Sdduvall if (need_privilege) { 19201369Sdduvall /* 19211369Sdduvall * Check for specific net_config privilege on Solaris 10+. 19221369Sdduvall */ 19232681Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 19241369Sdduvall if (err != 0) { 19251369Sdduvall miocnak(wq, mp, 0, err); 19261369Sdduvall return; 19271369Sdduvall } 19281369Sdduvall } 19291369Sdduvall 19301369Sdduvall mutex_enter(bgep->genlock); 19311865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 19321865Sdilpreet /* can happen during autorecovery */ 19331865Sdilpreet mutex_exit(bgep->genlock); 19341865Sdilpreet miocnak(wq, mp, 0, EIO); 19351865Sdilpreet return; 19361865Sdilpreet } 19371369Sdduvall 19381369Sdduvall switch (cmd) { 19391369Sdduvall default: 19401369Sdduvall _NOTE(NOTREACHED) 19411369Sdduvall status = IOC_INVAL; 19421369Sdduvall break; 19431369Sdduvall 19441369Sdduvall case BGE_MII_READ: 19451369Sdduvall case BGE_MII_WRITE: 19461369Sdduvall case BGE_SEE_READ: 19471369Sdduvall case BGE_SEE_WRITE: 19482675Szh199473 case BGE_FLASH_READ: 19492675Szh199473 case BGE_FLASH_WRITE: 19501369Sdduvall case BGE_DIAG: 19511369Sdduvall case BGE_PEEK: 19521369Sdduvall case BGE_POKE: 19531369Sdduvall case BGE_PHY_RESET: 19541369Sdduvall case BGE_SOFT_RESET: 19551369Sdduvall case BGE_HARD_RESET: 19561369Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 19571369Sdduvall break; 19581369Sdduvall 19591369Sdduvall case LB_GET_INFO_SIZE: 19601369Sdduvall case LB_GET_INFO: 19611369Sdduvall case LB_GET_MODE: 19621369Sdduvall case LB_SET_MODE: 19631369Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 19641369Sdduvall break; 19651369Sdduvall 19661369Sdduvall } 19671369Sdduvall 19681369Sdduvall /* 19691369Sdduvall * Do we need to reprogram the PHY and/or the MAC? 19701369Sdduvall * Do it now, while we still have the mutex. 19711369Sdduvall * 19721369Sdduvall * Note: update the PHY first, 'cos it controls the 19731369Sdduvall * speed/duplex parameters that the MAC code uses. 19741369Sdduvall */ 19751369Sdduvall switch (status) { 19761369Sdduvall case IOC_RESTART_REPLY: 19771369Sdduvall case IOC_RESTART_ACK: 19785903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 19791865Sdilpreet status = IOC_INVAL; 19801369Sdduvall break; 19811369Sdduvall } 19821369Sdduvall 19831865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 19841865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 19851865Sdilpreet status = IOC_INVAL; 19861865Sdilpreet } 19871865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 19881865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 19891865Sdilpreet status = IOC_INVAL; 19901865Sdilpreet } 19911369Sdduvall mutex_exit(bgep->genlock); 19921369Sdduvall 19931369Sdduvall /* 19941369Sdduvall * Finally, decide how to reply 19951369Sdduvall */ 19961369Sdduvall switch (status) { 19971369Sdduvall default: 19981369Sdduvall case IOC_INVAL: 19991369Sdduvall /* 20001369Sdduvall * Error, reply with a NAK and EINVAL or the specified error 20011369Sdduvall */ 20021369Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 20034588Sml149210 EINVAL : iocp->ioc_error); 20041369Sdduvall break; 20051369Sdduvall 20061369Sdduvall case IOC_DONE: 20071369Sdduvall /* 20081369Sdduvall * OK, reply already sent 20091369Sdduvall */ 20101369Sdduvall break; 20111369Sdduvall 20121369Sdduvall case IOC_RESTART_ACK: 20131369Sdduvall case IOC_ACK: 20141369Sdduvall /* 20151369Sdduvall * OK, reply with an ACK 20161369Sdduvall */ 20171369Sdduvall miocack(wq, mp, 0, 0); 20181369Sdduvall break; 20191369Sdduvall 20201369Sdduvall case IOC_RESTART_REPLY: 20211369Sdduvall case IOC_REPLY: 20221369Sdduvall /* 20231369Sdduvall * OK, send prepared reply as ACK or NAK 20241369Sdduvall */ 20251369Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 20264588Sml149210 M_IOCACK : M_IOCNAK; 20271369Sdduvall qreply(wq, mp); 20281369Sdduvall break; 20291369Sdduvall } 20301369Sdduvall } 20311369Sdduvall 20321369Sdduvall /* 20331369Sdduvall * ========== Per-instance setup/teardown code ========== 20341369Sdduvall */ 20351369Sdduvall 20361369Sdduvall #undef BGE_DBG 20371369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 20383334Sgs150176 /* 20393334Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 20403334Sgs150176 */ 20413334Sgs150176 static int 20423334Sgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 20433334Sgs150176 uint_t dma_flags, dma_area_t *dma_p) 20443334Sgs150176 { 20453334Sgs150176 caddr_t va; 20463334Sgs150176 int err; 20473334Sgs150176 20483334Sgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 20494588Sml149210 (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 20503334Sgs150176 20513334Sgs150176 /* 20523334Sgs150176 * Allocate handle 20533334Sgs150176 */ 20543334Sgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 20554588Sml149210 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 20563334Sgs150176 if (err != DDI_SUCCESS) 20573334Sgs150176 return (DDI_FAILURE); 20583334Sgs150176 20593334Sgs150176 /* 20603334Sgs150176 * Allocate memory 20613334Sgs150176 */ 20623334Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 20634588Sml149210 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, 20644588Sml149210 &dma_p->acc_hdl); 20653334Sgs150176 if (err != DDI_SUCCESS) 20663334Sgs150176 return (DDI_FAILURE); 20673334Sgs150176 20683334Sgs150176 /* 20693334Sgs150176 * Bind the two together 20703334Sgs150176 */ 20713334Sgs150176 dma_p->mem_va = va; 20723334Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 20734588Sml149210 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 20744588Sml149210 &dma_p->cookie, &dma_p->ncookies); 20753334Sgs150176 20763334Sgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 20774588Sml149210 dma_p->alength, err, dma_p->ncookies)); 20783334Sgs150176 20793334Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 20803334Sgs150176 return (DDI_FAILURE); 20813334Sgs150176 20823334Sgs150176 dma_p->nslots = ~0U; 20833334Sgs150176 dma_p->size = ~0U; 20843334Sgs150176 dma_p->token = ~0U; 20853334Sgs150176 dma_p->offset = 0; 20863334Sgs150176 return (DDI_SUCCESS); 20873334Sgs150176 } 20883334Sgs150176 20893334Sgs150176 /* 20903334Sgs150176 * Free one allocated area of DMAable memory 20913334Sgs150176 */ 20923334Sgs150176 static void 20933334Sgs150176 bge_free_dma_mem(dma_area_t *dma_p) 20943334Sgs150176 { 20953334Sgs150176 if (dma_p->dma_hdl != NULL) { 20963334Sgs150176 if (dma_p->ncookies) { 20973334Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 20983334Sgs150176 dma_p->ncookies = 0; 20993334Sgs150176 } 21003334Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 21013334Sgs150176 dma_p->dma_hdl = NULL; 21023334Sgs150176 } 21033334Sgs150176 21043334Sgs150176 if (dma_p->acc_hdl != NULL) { 21053334Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 21063334Sgs150176 dma_p->acc_hdl = NULL; 21073334Sgs150176 } 21083334Sgs150176 } 21091369Sdduvall /* 21101369Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 21111369Sdduvall * updating the chunk descriptor accordingly. The size of the slice 21121369Sdduvall * is given by the product of the <qty> and <size> parameters. 21131369Sdduvall */ 21141369Sdduvall static void 21151369Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 21161369Sdduvall uint32_t qty, uint32_t size) 21171369Sdduvall { 21181369Sdduvall static uint32_t sequence = 0xbcd5704a; 21191369Sdduvall size_t totsize; 21201369Sdduvall 21211369Sdduvall totsize = qty*size; 21221369Sdduvall ASSERT(totsize <= chunk->alength); 21231369Sdduvall 21241369Sdduvall *slice = *chunk; 21251369Sdduvall slice->nslots = qty; 21261369Sdduvall slice->size = size; 21271369Sdduvall slice->alength = totsize; 21281369Sdduvall slice->token = ++sequence; 21291369Sdduvall 21301369Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 21311369Sdduvall chunk->alength -= totsize; 21321369Sdduvall chunk->offset += totsize; 21331369Sdduvall chunk->cookie.dmac_laddress += totsize; 21341369Sdduvall chunk->cookie.dmac_size -= totsize; 21351369Sdduvall } 21361369Sdduvall 21371369Sdduvall /* 21381369Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 21391369Sdduvall * the information in the <dma_area> descriptors that it contains 21401369Sdduvall * to set up all the other fields. This routine should be called 21411369Sdduvall * only once for each ring. 21421369Sdduvall */ 21431369Sdduvall static void 21441369Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 21451369Sdduvall { 21461369Sdduvall buff_ring_t *brp; 21471369Sdduvall bge_status_t *bsp; 21481369Sdduvall sw_rbd_t *srbdp; 21491369Sdduvall dma_area_t pbuf; 21501369Sdduvall uint32_t bufsize; 21511369Sdduvall uint32_t nslots; 21521369Sdduvall uint32_t slot; 21531369Sdduvall uint32_t split; 21541369Sdduvall 21551369Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 21561369Sdduvall NIC_MEM_SHADOW_BUFF_STD, 21571369Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 21581369Sdduvall NIC_MEM_SHADOW_BUFF_MINI 21591369Sdduvall }; 21601369Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 21611369Sdduvall RECV_STD_PROD_INDEX_REG, 21621369Sdduvall RECV_JUMBO_PROD_INDEX_REG, 21631369Sdduvall RECV_MINI_PROD_INDEX_REG 21641369Sdduvall }; 21651369Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 21661369Sdduvall STATUS_STD_BUFF_CONS_INDEX, 21671369Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 21681369Sdduvall STATUS_MINI_BUFF_CONS_INDEX 21691369Sdduvall }; 21701369Sdduvall 21711369Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 21724588Sml149210 (void *)bgep, ring)); 21731369Sdduvall 21741369Sdduvall brp = &bgep->buff[ring]; 21751369Sdduvall nslots = brp->desc.nslots; 21761369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 21771369Sdduvall bufsize = brp->buf[0].size; 21781369Sdduvall 21791369Sdduvall /* 21801369Sdduvall * Set up the copy of the h/w RCB 21811369Sdduvall * 21821369Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 21831369Sdduvall * field holds the number of slots), in a Receive Buffer Ring 21841369Sdduvall * this field indicates the size of each buffer in the ring. 21851369Sdduvall */ 21861369Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 21877099Syt223700 brp->hw_rcb.max_len = (uint16_t)bufsize; 21881369Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21891369Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 21901369Sdduvall 21911369Sdduvall /* 21921369Sdduvall * Other one-off initialisation of per-ring data 21931369Sdduvall */ 21941369Sdduvall brp->bgep = bgep; 21951369Sdduvall bsp = DMA_VPTR(bgep->status_block); 21961369Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 21971369Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 21981369Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 21991369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22001369Sdduvall 22011369Sdduvall /* 22021369Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 22031369Sdduvall */ 22041369Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 22051369Sdduvall brp->sw_rbds = srbdp; 22061369Sdduvall 22071369Sdduvall /* 22081369Sdduvall * Now initialise each array element once and for all 22091369Sdduvall */ 22101369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 22111369Sdduvall pbuf = brp->buf[split]; 22121369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 22131369Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 22141369Sdduvall ASSERT(pbuf.alength == 0); 22151369Sdduvall } 22161369Sdduvall } 22171369Sdduvall 22181369Sdduvall /* 22191369Sdduvall * Clean up initialisation done above before the memory is freed 22201369Sdduvall */ 22211369Sdduvall static void 22221369Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 22231369Sdduvall { 22241369Sdduvall buff_ring_t *brp; 22251369Sdduvall sw_rbd_t *srbdp; 22261369Sdduvall 22271369Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 22284588Sml149210 (void *)bgep, ring)); 22291369Sdduvall 22301369Sdduvall brp = &bgep->buff[ring]; 22311369Sdduvall srbdp = brp->sw_rbds; 22321369Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 22331369Sdduvall 22341369Sdduvall mutex_destroy(brp->rf_lock); 22351369Sdduvall } 22361369Sdduvall 22371369Sdduvall /* 22381369Sdduvall * Initialise the specified Receive (Return) Ring, using the 22391369Sdduvall * information in the <dma_area> descriptors that it contains 22401369Sdduvall * to set up all the other fields. This routine should be called 22411369Sdduvall * only once for each ring. 22421369Sdduvall */ 22431369Sdduvall static void 22441369Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 22451369Sdduvall { 22461369Sdduvall recv_ring_t *rrp; 22471369Sdduvall bge_status_t *bsp; 22481369Sdduvall uint32_t nslots; 22491369Sdduvall 22501369Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 22514588Sml149210 (void *)bgep, ring)); 22521369Sdduvall 22531369Sdduvall /* 22541369Sdduvall * The chip architecture requires that receive return rings have 22551369Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 22561369Sdduvall */ 22571369Sdduvall rrp = &bgep->recv[ring]; 22581369Sdduvall nslots = rrp->desc.nslots; 22591369Sdduvall ASSERT(nslots == 0 || nslots == 512 || 22604588Sml149210 nslots == 1024 || nslots == 2048); 22611369Sdduvall 22621369Sdduvall /* 22631369Sdduvall * Set up the copy of the h/w RCB 22641369Sdduvall */ 22651369Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 22667099Syt223700 rrp->hw_rcb.max_len = (uint16_t)nslots; 22671369Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 22681369Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 22691369Sdduvall 22701369Sdduvall /* 22711369Sdduvall * Other one-off initialisation of per-ring data 22721369Sdduvall */ 22731369Sdduvall rrp->bgep = bgep; 22741369Sdduvall bsp = DMA_VPTR(bgep->status_block); 22751369Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 22761369Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 22771369Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 22781369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22791369Sdduvall } 22801369Sdduvall 22811369Sdduvall 22821369Sdduvall /* 22831369Sdduvall * Clean up initialisation done above before the memory is freed 22841369Sdduvall */ 22851369Sdduvall static void 22861369Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 22871369Sdduvall { 22881369Sdduvall recv_ring_t *rrp; 22891369Sdduvall 22901369Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 22914588Sml149210 (void *)bgep, ring)); 22921369Sdduvall 22931369Sdduvall rrp = &bgep->recv[ring]; 22941369Sdduvall if (rrp->rx_softint) 22951369Sdduvall ddi_remove_softintr(rrp->rx_softint); 22961369Sdduvall mutex_destroy(rrp->rx_lock); 22971369Sdduvall } 22981369Sdduvall 22991369Sdduvall /* 23001369Sdduvall * Initialise the specified Send Ring, using the information in the 23011369Sdduvall * <dma_area> descriptors that it contains to set up all the other 23021369Sdduvall * fields. This routine should be called only once for each ring. 23031369Sdduvall */ 23041369Sdduvall static void 23051369Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 23061369Sdduvall { 23071369Sdduvall send_ring_t *srp; 23081369Sdduvall bge_status_t *bsp; 23091369Sdduvall sw_sbd_t *ssbdp; 23101369Sdduvall dma_area_t desc; 23111369Sdduvall dma_area_t pbuf; 23121369Sdduvall uint32_t nslots; 23131369Sdduvall uint32_t slot; 23141369Sdduvall uint32_t split; 23153334Sgs150176 sw_txbuf_t *txbuf; 23161369Sdduvall 23171369Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 23184588Sml149210 (void *)bgep, ring)); 23191369Sdduvall 23201369Sdduvall /* 23211369Sdduvall * The chip architecture requires that host-based send rings 23221369Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 23231369Sdduvall */ 23241369Sdduvall srp = &bgep->send[ring]; 23251369Sdduvall nslots = srp->desc.nslots; 23261369Sdduvall ASSERT(nslots == 0 || nslots == 512); 23271369Sdduvall 23281369Sdduvall /* 23291369Sdduvall * Set up the copy of the h/w RCB 23301369Sdduvall */ 23311369Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 23327099Syt223700 srp->hw_rcb.max_len = (uint16_t)nslots; 23331369Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 23341369Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 23351369Sdduvall 23361369Sdduvall /* 23371369Sdduvall * Other one-off initialisation of per-ring data 23381369Sdduvall */ 23391369Sdduvall srp->bgep = bgep; 23401369Sdduvall bsp = DMA_VPTR(bgep->status_block); 23411369Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 23421369Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 23431369Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 23441369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 23453334Sgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER, 23463334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 23473334Sgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER, 23483334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 23491369Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 23501369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 23513334Sgs150176 if (nslots == 0) 23523334Sgs150176 return; 23531369Sdduvall 23541369Sdduvall /* 23551369Sdduvall * Allocate the array of s/w Send Buffer Descriptors 23561369Sdduvall */ 23571369Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 23583334Sgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP); 23593334Sgs150176 srp->txbuf_head = 23603334Sgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP); 23613334Sgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP); 23621369Sdduvall srp->sw_sbds = ssbdp; 23633334Sgs150176 srp->txbuf = txbuf; 23643334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 23653334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 23663334Sgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT) 23673334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO; 23683334Sgs150176 else 23693334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY; 23703334Sgs150176 srp->tx_array = 1; 23711369Sdduvall 23721369Sdduvall /* 23733334Sgs150176 * Chunk tx desc area 23741369Sdduvall */ 23751369Sdduvall desc = srp->desc; 23763334Sgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) { 23773334Sgs150176 bge_slice_chunk(&ssbdp->desc, &desc, 1, 23783334Sgs150176 sizeof (bge_sbd_t)); 23793334Sgs150176 } 23803334Sgs150176 ASSERT(desc.alength == 0); 23813334Sgs150176 23823334Sgs150176 /* 23833334Sgs150176 * Chunk tx buffer area 23843334Sgs150176 */ 23851369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 23863334Sgs150176 pbuf = srp->buf[0][split]; 23873334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 23883334Sgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1, 23893334Sgs150176 bgep->chipid.snd_buff_size); 23903334Sgs150176 txbuf++; 23911369Sdduvall } 23921369Sdduvall ASSERT(pbuf.alength == 0); 23931369Sdduvall } 23941369Sdduvall } 23951369Sdduvall 23961369Sdduvall /* 23971369Sdduvall * Clean up initialisation done above before the memory is freed 23981369Sdduvall */ 23991369Sdduvall static void 24001369Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 24011369Sdduvall { 24021369Sdduvall send_ring_t *srp; 24033334Sgs150176 uint32_t array; 24043334Sgs150176 uint32_t split; 24053334Sgs150176 uint32_t nslots; 24061369Sdduvall 24071369Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 24084588Sml149210 (void *)bgep, ring)); 24091369Sdduvall 24101369Sdduvall srp = &bgep->send[ring]; 24113334Sgs150176 mutex_destroy(srp->tc_lock); 24123334Sgs150176 mutex_destroy(srp->freetxbuf_lock); 24133334Sgs150176 mutex_destroy(srp->txbuf_lock); 24141369Sdduvall mutex_destroy(srp->tx_lock); 24153334Sgs150176 nslots = srp->desc.nslots; 24163334Sgs150176 if (nslots == 0) 24173334Sgs150176 return; 24183334Sgs150176 24193334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 24203334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 24213334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 24223334Sgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds)); 24233334Sgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head)); 24243334Sgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf)); 24253334Sgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp)); 24263334Sgs150176 srp->sw_sbds = NULL; 24273334Sgs150176 srp->txbuf_head = NULL; 24283334Sgs150176 srp->txbuf = NULL; 24293334Sgs150176 srp->pktp = NULL; 24301369Sdduvall } 24311369Sdduvall 24321369Sdduvall /* 24331369Sdduvall * Initialise all transmit, receive, and buffer rings. 24341369Sdduvall */ 24351865Sdilpreet void 24361369Sdduvall bge_init_rings(bge_t *bgep) 24371369Sdduvall { 24383334Sgs150176 uint32_t ring; 24391369Sdduvall 24401369Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 24411369Sdduvall 24421369Sdduvall /* 24431369Sdduvall * Perform one-off initialisation of each ring ... 24441369Sdduvall */ 24451369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 24461369Sdduvall bge_init_send_ring(bgep, ring); 24471369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 24481369Sdduvall bge_init_recv_ring(bgep, ring); 24491369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 24501369Sdduvall bge_init_buff_ring(bgep, ring); 24511369Sdduvall } 24521369Sdduvall 24531369Sdduvall /* 24541369Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 24551369Sdduvall */ 24561865Sdilpreet void 24571369Sdduvall bge_fini_rings(bge_t *bgep) 24581369Sdduvall { 24593334Sgs150176 uint32_t ring; 24601369Sdduvall 24611369Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 24621369Sdduvall 24631369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 24641369Sdduvall bge_fini_buff_ring(bgep, ring); 24651369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 24661369Sdduvall bge_fini_recv_ring(bgep, ring); 24671369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 24681369Sdduvall bge_fini_send_ring(bgep, ring); 24691369Sdduvall } 24701369Sdduvall 24711369Sdduvall /* 24723334Sgs150176 * Called from the bge_m_stop() to free the tx buffers which are 24733334Sgs150176 * allocated from the tx process. 24741369Sdduvall */ 24753334Sgs150176 void 24763334Sgs150176 bge_free_txbuf_arrays(send_ring_t *srp) 24771369Sdduvall { 24783334Sgs150176 uint32_t array; 24793334Sgs150176 uint32_t split; 24803334Sgs150176 24813334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 24821369Sdduvall 24831369Sdduvall /* 24843334Sgs150176 * Free the extra tx buffer DMA area 24851369Sdduvall */ 24863334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 24873334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 24883334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 24891369Sdduvall 24901369Sdduvall /* 24913334Sgs150176 * Restore initial tx buffer numbers 24921369Sdduvall */ 24933334Sgs150176 srp->tx_array = 1; 24943334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 24953334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 24963334Sgs150176 srp->tx_flow = 0; 24973334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 24981369Sdduvall } 24991369Sdduvall 25001369Sdduvall /* 25013334Sgs150176 * Called from tx process to allocate more tx buffers 25021369Sdduvall */ 25033334Sgs150176 bge_queue_item_t * 25043334Sgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp) 25051369Sdduvall { 25063334Sgs150176 bge_queue_t *txbuf_queue; 25073334Sgs150176 bge_queue_item_t *txbuf_item_last; 25083334Sgs150176 bge_queue_item_t *txbuf_item; 25093334Sgs150176 bge_queue_item_t *txbuf_item_rtn; 25103334Sgs150176 sw_txbuf_t *txbuf; 25113334Sgs150176 dma_area_t area; 25123334Sgs150176 size_t txbuffsize; 25133334Sgs150176 uint32_t slot; 25143334Sgs150176 uint32_t array; 25153334Sgs150176 uint32_t split; 25163334Sgs150176 uint32_t err; 25173334Sgs150176 25183334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 25193334Sgs150176 25203334Sgs150176 array = srp->tx_array; 25213334Sgs150176 if (array >= srp->tx_array_max) 25223334Sgs150176 return (NULL); 25233334Sgs150176 25243334Sgs150176 /* 25253334Sgs150176 * Allocate memory & handles for TX buffers 25263334Sgs150176 */ 25273334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 25283334Sgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0); 25293334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 25303334Sgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 25314588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 25324588Sml149210 &srp->buf[array][split]); 25333334Sgs150176 if (err != DDI_SUCCESS) { 25343334Sgs150176 /* Free the last already allocated OK chunks */ 25353334Sgs150176 for (slot = 0; slot <= split; ++slot) 25363334Sgs150176 bge_free_dma_mem(&srp->buf[array][slot]); 25373334Sgs150176 srp->tx_alloc_fail++; 25383334Sgs150176 return (NULL); 25391369Sdduvall } 25403334Sgs150176 } 25413334Sgs150176 25423334Sgs150176 /* 25433334Sgs150176 * Chunk tx buffer area 25443334Sgs150176 */ 25453334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 25463334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 25473334Sgs150176 area = srp->buf[array][split]; 25483334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 25493334Sgs150176 bge_slice_chunk(&txbuf->buf, &area, 1, 25503334Sgs150176 bgep->chipid.snd_buff_size); 25513334Sgs150176 txbuf++; 25523334Sgs150176 } 25531369Sdduvall } 25541369Sdduvall 25553334Sgs150176 /* 25563334Sgs150176 * Add above buffers to the tx buffer pop queue 25573334Sgs150176 */ 25583334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 25593334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 25603334Sgs150176 txbuf_item_last = NULL; 25613334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) { 25623334Sgs150176 txbuf_item->item = txbuf; 25633334Sgs150176 txbuf_item->next = txbuf_item_last; 25643334Sgs150176 txbuf_item_last = txbuf_item; 25653334Sgs150176 txbuf++; 25663334Sgs150176 txbuf_item++; 25671369Sdduvall } 25683334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 25693334Sgs150176 txbuf_item_rtn = txbuf_item; 25703334Sgs150176 txbuf_item++; 25713334Sgs150176 txbuf_queue = srp->txbuf_pop_queue; 25723334Sgs150176 mutex_enter(txbuf_queue->lock); 25733334Sgs150176 txbuf_item->next = txbuf_queue->head; 25743334Sgs150176 txbuf_queue->head = txbuf_item_last; 25753334Sgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1; 25763334Sgs150176 mutex_exit(txbuf_queue->lock); 25773334Sgs150176 25783334Sgs150176 srp->tx_array++; 25793334Sgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM; 25803334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 25813334Sgs150176 25823334Sgs150176 return (txbuf_item_rtn); 25831369Sdduvall } 25841369Sdduvall 25851369Sdduvall /* 25861369Sdduvall * This function allocates all the transmit and receive buffers 25873334Sgs150176 * and descriptors, in four chunks. 25881369Sdduvall */ 25891865Sdilpreet int 25901369Sdduvall bge_alloc_bufs(bge_t *bgep) 25911369Sdduvall { 25921369Sdduvall dma_area_t area; 25931369Sdduvall size_t rxbuffsize; 25941369Sdduvall size_t txbuffsize; 25951369Sdduvall size_t rxbuffdescsize; 25961369Sdduvall size_t rxdescsize; 25971369Sdduvall size_t txdescsize; 25983334Sgs150176 uint32_t ring; 25993334Sgs150176 uint32_t rx_rings = bgep->chipid.rx_rings; 26003334Sgs150176 uint32_t tx_rings = bgep->chipid.tx_rings; 26011369Sdduvall int split; 26021369Sdduvall int err; 26031369Sdduvall 26041369Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 26054588Sml149210 (void *)bgep)); 26061369Sdduvall 26071908Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size; 26081369Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 26091369Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 26101369Sdduvall 26113334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 26121369Sdduvall txbuffsize *= tx_rings; 26131369Sdduvall 26141369Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 26151369Sdduvall rxdescsize *= sizeof (bge_rbd_t); 26161369Sdduvall 26171369Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 26181369Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 26191369Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 26201369Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 26211369Sdduvall 26221369Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 26231369Sdduvall txdescsize *= sizeof (bge_sbd_t); 26241369Sdduvall txdescsize += sizeof (bge_statistics_t); 26251369Sdduvall txdescsize += sizeof (bge_status_t); 26261369Sdduvall txdescsize += BGE_STATUS_PADDING; 26271369Sdduvall 26281369Sdduvall /* 26293907Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers 26303907Szh199473 */ 26313907Szh199473 if (bge_relaxed_ordering) 26323907Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING; 26333907Szh199473 26343907Szh199473 /* 26351369Sdduvall * Allocate memory & handles for RX buffers 26361369Sdduvall */ 26371369Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 26381369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26391369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 26404588Sml149210 &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 26414588Sml149210 &bgep->rx_buff[split]); 26421369Sdduvall if (err != DDI_SUCCESS) 26431369Sdduvall return (DDI_FAILURE); 26441369Sdduvall } 26451369Sdduvall 26461369Sdduvall /* 26471369Sdduvall * Allocate memory & handles for TX buffers 26481369Sdduvall */ 26491369Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 26501369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26511369Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 26524588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 26534588Sml149210 &bgep->tx_buff[split]); 26541369Sdduvall if (err != DDI_SUCCESS) 26551369Sdduvall return (DDI_FAILURE); 26561369Sdduvall } 26571369Sdduvall 26583907Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING; 26593907Szh199473 26601369Sdduvall /* 26611369Sdduvall * Allocate memory & handles for receive return rings 26621369Sdduvall */ 26631369Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 26641369Sdduvall for (split = 0; split < rx_rings; ++split) { 26651369Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 26664588Sml149210 &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 26674588Sml149210 &bgep->rx_desc[split]); 26681369Sdduvall if (err != DDI_SUCCESS) 26691369Sdduvall return (DDI_FAILURE); 26701369Sdduvall } 26711369Sdduvall 26721369Sdduvall /* 26731369Sdduvall * Allocate memory & handles for buffer (producer) descriptor rings 26741369Sdduvall */ 26751369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 26764588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 26771369Sdduvall if (err != DDI_SUCCESS) 26781369Sdduvall return (DDI_FAILURE); 26791369Sdduvall 26801369Sdduvall /* 26811369Sdduvall * Allocate memory & handles for TX descriptor rings, 26821369Sdduvall * status block, and statistics area 26831369Sdduvall */ 26841369Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 26854588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 26861369Sdduvall if (err != DDI_SUCCESS) 26871369Sdduvall return (DDI_FAILURE); 26881369Sdduvall 26891369Sdduvall /* 26901369Sdduvall * Now carve up each of the allocated areas ... 26911369Sdduvall */ 26921369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 26931369Sdduvall area = bgep->rx_buff[split]; 26941369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 26954588Sml149210 &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 26964588Sml149210 bgep->chipid.std_buf_size); 26971369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 26984588Sml149210 &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 26994588Sml149210 bgep->chipid.recv_jumbo_size); 27001369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 27014588Sml149210 &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 27024588Sml149210 BGE_MINI_BUFF_SIZE); 27031369Sdduvall } 27041369Sdduvall 27051369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 27061369Sdduvall area = bgep->tx_buff[split]; 27071369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 27083334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 27094588Sml149210 &area, BGE_SEND_BUF_NUM/BGE_SPLIT, 27104588Sml149210 bgep->chipid.snd_buff_size); 27111369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 27123334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 27134588Sml149210 &area, 0, bgep->chipid.snd_buff_size); 27141369Sdduvall } 27151369Sdduvall 27161369Sdduvall for (ring = 0; ring < rx_rings; ++ring) 27171369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 27184588Sml149210 bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 27191369Sdduvall 27201369Sdduvall area = bgep->rx_desc[rx_rings]; 27211369Sdduvall for (; ring < BGE_RECV_RINGS_MAX; ++ring) 27221369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 27234588Sml149210 0, sizeof (bge_rbd_t)); 27241369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 27254588Sml149210 BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 27261369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 27274588Sml149210 bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 27281369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 27294588Sml149210 BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 27301369Sdduvall ASSERT(area.alength == 0); 27311369Sdduvall 27321369Sdduvall area = bgep->tx_desc; 27331369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 27341369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 27354588Sml149210 BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 27361369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 27371369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 27384588Sml149210 0, sizeof (bge_sbd_t)); 27391369Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 27401369Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 27411369Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 27421369Sdduvall DMA_ZERO(bgep->status_block); 27431369Sdduvall 27441369Sdduvall return (DDI_SUCCESS); 27451369Sdduvall } 27461369Sdduvall 27471369Sdduvall /* 27481369Sdduvall * This routine frees the transmit and receive buffers and descriptors. 27491369Sdduvall * Make sure the chip is stopped before calling it! 27501369Sdduvall */ 27511865Sdilpreet void 27521369Sdduvall bge_free_bufs(bge_t *bgep) 27531369Sdduvall { 27541369Sdduvall int split; 27551369Sdduvall 27561369Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 27574588Sml149210 (void *)bgep)); 27581369Sdduvall 27591369Sdduvall bge_free_dma_mem(&bgep->tx_desc); 27601369Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 27611369Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 27621369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 27631369Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 27641369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 27651369Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 27661369Sdduvall } 27671369Sdduvall 27681369Sdduvall /* 27691369Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 27701369Sdduvall */ 27711369Sdduvall 27721369Sdduvall static void 27731369Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 27741369Sdduvall { 27751369Sdduvall struct ether_addr sysaddr; 27761369Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 27771369Sdduvall uchar_t *bytes; 27781369Sdduvall int *ints; 27791369Sdduvall uint_t nelts; 27801369Sdduvall int err; 27811369Sdduvall 27821369Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 27834588Sml149210 (void *)bgep)); 27841369Sdduvall 27851369Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 27864588Sml149210 cidp->hw_mac_addr, 27874588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27884588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27891369Sdduvall 27901369Sdduvall /* 27911369Sdduvall * The "vendor's factory-set address" may already have 27921369Sdduvall * been extracted from the chip, but if the property 27931369Sdduvall * "local-mac-address" is set we use that instead. It 27941369Sdduvall * will normally be set by OBP, but it could also be 27951369Sdduvall * specified in a .conf file(!) 27961369Sdduvall * 27971369Sdduvall * There doesn't seem to be a way to define byte-array 27981369Sdduvall * properties in a .conf, so we check whether it looks 27991369Sdduvall * like an array of 6 ints instead. 28001369Sdduvall * 28011369Sdduvall * Then, we check whether it looks like an array of 6 28021369Sdduvall * bytes (which it should, if OBP set it). If we can't 28031369Sdduvall * make sense of it either way, we'll ignore it. 28041369Sdduvall */ 28051369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 28064588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 28071369Sdduvall if (err == DDI_PROP_SUCCESS) { 28081369Sdduvall if (nelts == ETHERADDRL) { 28091369Sdduvall while (nelts--) 28101369Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 28112331Skrgopi cidp->vendor_addr.set = B_TRUE; 28121369Sdduvall } 28131369Sdduvall ddi_prop_free(ints); 28141369Sdduvall } 28151369Sdduvall 28161369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 28174588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 28181369Sdduvall if (err == DDI_PROP_SUCCESS) { 28191369Sdduvall if (nelts == ETHERADDRL) { 28201369Sdduvall while (nelts--) 28211369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 28222331Skrgopi cidp->vendor_addr.set = B_TRUE; 28231369Sdduvall } 28241369Sdduvall ddi_prop_free(bytes); 28251369Sdduvall } 28261369Sdduvall 28271369Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 28284588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 28294588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 28301369Sdduvall 28311369Sdduvall /* 28321369Sdduvall * Look up the OBP property "local-mac-address?". Note that even 28331369Sdduvall * though its value is a string (which should be "true" or "false"), 28341369Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 28351369Sdduvall * the buffer first and then fetch the property as an untyped array; 28361369Sdduvall * this may or may not include a final NUL, but since there will 28371369Sdduvall * always be one left at the end of the buffer we can now treat it 28381369Sdduvall * as a string anyway. 28391369Sdduvall */ 28401369Sdduvall nelts = sizeof (propbuf); 28411369Sdduvall bzero(propbuf, nelts--); 28421369Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 28434588Sml149210 DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 28441369Sdduvall 28451369Sdduvall /* 28461369Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 28471369Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 28481369Sdduvall * 'local-mac-address? = false', use "the system address" instead 28491369Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 28501369Sdduvall */ 28512331Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0) 28521369Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 28531369Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 28542331Skrgopi cidp->vendor_addr.set = B_TRUE; 28551369Sdduvall } 28561369Sdduvall 28571369Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 28584588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 28594588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 28601369Sdduvall 28611369Sdduvall /* 28621369Sdduvall * Finally(!), if there's a valid "mac-address" property (created 28631369Sdduvall * if we netbooted from this interface), we must use this instead 28641369Sdduvall * of any of the above to ensure that the NFS/install server doesn't 28651369Sdduvall * get confused by the address changing as Solaris takes over! 28661369Sdduvall */ 28671369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 28684588Sml149210 DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 28691369Sdduvall if (err == DDI_PROP_SUCCESS) { 28701369Sdduvall if (nelts == ETHERADDRL) { 28711369Sdduvall while (nelts--) 28721369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 28732331Skrgopi cidp->vendor_addr.set = B_TRUE; 28741369Sdduvall } 28751369Sdduvall ddi_prop_free(bytes); 28761369Sdduvall } 28771369Sdduvall 28781369Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 28794588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 28804588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 28811369Sdduvall } 28821369Sdduvall 28831865Sdilpreet 28841865Sdilpreet /*ARGSUSED*/ 28851865Sdilpreet int 28861865Sdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 28871865Sdilpreet { 28881865Sdilpreet ddi_fm_error_t de; 28891865Sdilpreet 28901865Sdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 28911865Sdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 28921865Sdilpreet return (de.fme_status); 28931865Sdilpreet } 28941865Sdilpreet 28951865Sdilpreet /*ARGSUSED*/ 28961865Sdilpreet int 28971865Sdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 28981865Sdilpreet { 28991865Sdilpreet ddi_fm_error_t de; 29001865Sdilpreet 29011865Sdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 29021865Sdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 29031865Sdilpreet return (de.fme_status); 29041865Sdilpreet } 29051865Sdilpreet 29061865Sdilpreet /* 29071865Sdilpreet * The IO fault service error handling callback function 29081865Sdilpreet */ 29091865Sdilpreet /*ARGSUSED*/ 29101865Sdilpreet static int 29111865Sdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 29121865Sdilpreet { 29131865Sdilpreet /* 29141865Sdilpreet * as the driver can always deal with an error in any dma or 29151865Sdilpreet * access handle, we can just return the fme_status value. 29161865Sdilpreet */ 29171865Sdilpreet pci_ereport_post(dip, err, NULL); 29181865Sdilpreet return (err->fme_status); 29191865Sdilpreet } 29201865Sdilpreet 29211865Sdilpreet static void 29221865Sdilpreet bge_fm_init(bge_t *bgep) 29231865Sdilpreet { 29241865Sdilpreet ddi_iblock_cookie_t iblk; 29251865Sdilpreet 29261865Sdilpreet /* Only register with IO Fault Services if we have some capability */ 29271865Sdilpreet if (bgep->fm_capabilities) { 29281865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 29291865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 29301865Sdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 29311865Sdilpreet 29321865Sdilpreet /* Register capabilities with IO Fault Services */ 29331865Sdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 29341865Sdilpreet 29351865Sdilpreet /* 29361865Sdilpreet * Initialize pci ereport capabilities if ereport capable 29371865Sdilpreet */ 29381865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 29391865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29401865Sdilpreet pci_ereport_setup(bgep->devinfo); 29411865Sdilpreet 29421865Sdilpreet /* 29431865Sdilpreet * Register error callback if error callback capable 29441865Sdilpreet */ 29451865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29461865Sdilpreet ddi_fm_handler_register(bgep->devinfo, 29474588Sml149210 bge_fm_error_cb, (void*) bgep); 29481865Sdilpreet } else { 29491865Sdilpreet /* 29501865Sdilpreet * These fields have to be cleared of FMA if there are no 29511865Sdilpreet * FMA capabilities at runtime. 29521865Sdilpreet */ 29531865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 29541865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 29551865Sdilpreet dma_attr.dma_attr_flags = 0; 29561865Sdilpreet } 29571865Sdilpreet } 29581865Sdilpreet 29591865Sdilpreet static void 29601865Sdilpreet bge_fm_fini(bge_t *bgep) 29611865Sdilpreet { 29621865Sdilpreet /* Only unregister FMA capabilities if we registered some */ 29631865Sdilpreet if (bgep->fm_capabilities) { 29641865Sdilpreet 29651865Sdilpreet /* 29661865Sdilpreet * Release any resources allocated by pci_ereport_setup() 29671865Sdilpreet */ 29681865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 29691865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29701865Sdilpreet pci_ereport_teardown(bgep->devinfo); 29711865Sdilpreet 29721865Sdilpreet /* 29731865Sdilpreet * Un-register error callback if error callback capable 29741865Sdilpreet */ 29751865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 29761865Sdilpreet ddi_fm_handler_unregister(bgep->devinfo); 29771865Sdilpreet 29781865Sdilpreet /* Unregister from IO Fault Services */ 29791865Sdilpreet ddi_fm_fini(bgep->devinfo); 29801865Sdilpreet } 29811865Sdilpreet } 29821865Sdilpreet 29831369Sdduvall static void 29841408Srandyf #ifdef BGE_IPMI_ASF 29851408Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 29861408Srandyf #else 29871369Sdduvall bge_unattach(bge_t *bgep) 29881408Srandyf #endif 29891369Sdduvall { 29901369Sdduvall BGE_TRACE(("bge_unattach($%p)", 29911369Sdduvall (void *)bgep)); 29921369Sdduvall 29931369Sdduvall /* 29941369Sdduvall * Flag that no more activity may be initiated 29951369Sdduvall */ 29961369Sdduvall bgep->progress &= ~PROGRESS_READY; 29971369Sdduvall 29981369Sdduvall /* 29991369Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 30001369Sdduvall * Clean up and free all BGE data structures 30011369Sdduvall */ 30025107Seota if (bgep->periodic_id != NULL) { 30035107Seota ddi_periodic_delete(bgep->periodic_id); 30045107Seota bgep->periodic_id = NULL; 30051369Sdduvall } 30061369Sdduvall if (bgep->progress & PROGRESS_KSTATS) 30071369Sdduvall bge_fini_kstats(bgep); 30081369Sdduvall if (bgep->progress & PROGRESS_PHY) 30091369Sdduvall bge_phys_reset(bgep); 30101369Sdduvall if (bgep->progress & PROGRESS_HWINT) { 30111369Sdduvall mutex_enter(bgep->genlock); 30121408Srandyf #ifdef BGE_IPMI_ASF 30131865Sdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 30141865Sdilpreet #else 30151865Sdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 30161865Sdilpreet #endif 30171865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 30181865Sdilpreet DDI_SERVICE_UNAFFECTED); 30191865Sdilpreet #ifdef BGE_IPMI_ASF 30201408Srandyf if (bgep->asf_enabled) { 30211408Srandyf /* 30221408Srandyf * This register has been overlaid. We restore its 30231408Srandyf * initial value here. 30241408Srandyf */ 30251408Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 30261408Srandyf BGE_NIC_DATA_SIG); 30271408Srandyf } 30281408Srandyf #endif 30291865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 30301865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 30311865Sdilpreet DDI_SERVICE_UNAFFECTED); 30321865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 30331865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 30341865Sdilpreet DDI_SERVICE_UNAFFECTED); 30351369Sdduvall mutex_exit(bgep->genlock); 30361369Sdduvall } 30371369Sdduvall if (bgep->progress & PROGRESS_INTR) { 30381865Sdilpreet bge_intr_disable(bgep); 30391369Sdduvall bge_fini_rings(bgep); 30401369Sdduvall } 30411865Sdilpreet if (bgep->progress & PROGRESS_HWINT) { 30421865Sdilpreet bge_rem_intrs(bgep); 30431865Sdilpreet rw_destroy(bgep->errlock); 30441865Sdilpreet mutex_destroy(bgep->softintrlock); 30451865Sdilpreet mutex_destroy(bgep->genlock); 30461865Sdilpreet } 30471369Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 30481369Sdduvall ddi_remove_softintr(bgep->factotum_id); 30491369Sdduvall if (bgep->progress & PROGRESS_RESCHED) 30503334Sgs150176 ddi_remove_softintr(bgep->drain_id); 30511865Sdilpreet if (bgep->progress & PROGRESS_BUFS) 30521865Sdilpreet bge_free_bufs(bgep); 30531369Sdduvall if (bgep->progress & PROGRESS_REGS) 30541369Sdduvall ddi_regs_map_free(&bgep->io_handle); 30551369Sdduvall if (bgep->progress & PROGRESS_CFG) 30561369Sdduvall pci_config_teardown(&bgep->cfg_handle); 30571369Sdduvall 30581865Sdilpreet bge_fm_fini(bgep); 30591865Sdilpreet 30601369Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 30613334Sgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t)); 30621369Sdduvall kmem_free(bgep, sizeof (*bgep)); 30631369Sdduvall } 30641369Sdduvall 30651369Sdduvall static int 30661369Sdduvall bge_resume(dev_info_t *devinfo) 30671369Sdduvall { 30681369Sdduvall bge_t *bgep; /* Our private data */ 30691369Sdduvall chip_id_t *cidp; 30701369Sdduvall chip_id_t chipid; 30711369Sdduvall 30721369Sdduvall bgep = ddi_get_driver_private(devinfo); 30731369Sdduvall if (bgep == NULL) 30741369Sdduvall return (DDI_FAILURE); 30751369Sdduvall 30761369Sdduvall /* 30771369Sdduvall * Refuse to resume if the data structures aren't consistent 30781369Sdduvall */ 30791369Sdduvall if (bgep->devinfo != devinfo) 30801369Sdduvall return (DDI_FAILURE); 30811369Sdduvall 30821408Srandyf #ifdef BGE_IPMI_ASF 30831408Srandyf /* 30841408Srandyf * Power management hasn't been supported in BGE now. If you 30851408Srandyf * want to implement it, please add the ASF/IPMI related 30861408Srandyf * code here. 30871408Srandyf */ 30881408Srandyf 30891408Srandyf #endif 30901408Srandyf 30911369Sdduvall /* 30921369Sdduvall * Read chip ID & set up config space command register(s) 30931369Sdduvall * Refuse to resume if the chip has changed its identity! 30941369Sdduvall */ 30951369Sdduvall cidp = &bgep->chipid; 30961865Sdilpreet mutex_enter(bgep->genlock); 30971369Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 30981865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 30991865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31001865Sdilpreet mutex_exit(bgep->genlock); 31011865Sdilpreet return (DDI_FAILURE); 31021865Sdilpreet } 31031865Sdilpreet mutex_exit(bgep->genlock); 31041369Sdduvall if (chipid.vendor != cidp->vendor) 31051369Sdduvall return (DDI_FAILURE); 31061369Sdduvall if (chipid.device != cidp->device) 31071369Sdduvall return (DDI_FAILURE); 31081369Sdduvall if (chipid.revision != cidp->revision) 31091369Sdduvall return (DDI_FAILURE); 31101369Sdduvall if (chipid.asic_rev != cidp->asic_rev) 31111369Sdduvall return (DDI_FAILURE); 31121369Sdduvall 31131369Sdduvall /* 31141369Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 31151369Sdduvall */ 31161369Sdduvall mutex_enter(bgep->genlock); 31171865Sdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 31181865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 31191865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 31201865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31211865Sdilpreet mutex_exit(bgep->genlock); 31221865Sdilpreet return (DDI_FAILURE); 31231865Sdilpreet } 31241865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 31251865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31261865Sdilpreet mutex_exit(bgep->genlock); 31271865Sdilpreet return (DDI_FAILURE); 31281865Sdilpreet } 31291865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 31301865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31311865Sdilpreet mutex_exit(bgep->genlock); 31321865Sdilpreet return (DDI_FAILURE); 31331865Sdilpreet } 31341369Sdduvall mutex_exit(bgep->genlock); 31351369Sdduvall return (DDI_SUCCESS); 31361369Sdduvall } 31371369Sdduvall 31381369Sdduvall /* 31391369Sdduvall * attach(9E) -- Attach a device to the system 31401369Sdduvall * 31411369Sdduvall * Called once for each board successfully probed. 31421369Sdduvall */ 31431369Sdduvall static int 31441369Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 31451369Sdduvall { 31461369Sdduvall bge_t *bgep; /* Our private data */ 31472311Sseb mac_register_t *macp; 31481369Sdduvall chip_id_t *cidp; 31491369Sdduvall caddr_t regs; 31501369Sdduvall int instance; 31511369Sdduvall int err; 31521369Sdduvall int intr_types; 31531408Srandyf #ifdef BGE_IPMI_ASF 31541408Srandyf uint32_t mhcrValue; 31553918Sml149210 #ifdef __sparc 31563918Sml149210 uint16_t value16; 31573918Sml149210 #endif 31583918Sml149210 #ifdef BGE_NETCONSOLE 31593918Sml149210 int retval; 31603918Sml149210 #endif 31611408Srandyf #endif 31621369Sdduvall 31631369Sdduvall instance = ddi_get_instance(devinfo); 31641369Sdduvall 31651369Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 31664588Sml149210 (void *)devinfo, cmd, instance)); 31671369Sdduvall BGE_BRKPT(NULL, "bge_attach"); 31681369Sdduvall 31691369Sdduvall switch (cmd) { 31701369Sdduvall default: 31711369Sdduvall return (DDI_FAILURE); 31721369Sdduvall 31731369Sdduvall case DDI_RESUME: 31741369Sdduvall return (bge_resume(devinfo)); 31751369Sdduvall 31761369Sdduvall case DDI_ATTACH: 31771369Sdduvall break; 31781369Sdduvall } 31791369Sdduvall 31801369Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 31813334Sgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP); 31821369Sdduvall ddi_set_driver_private(devinfo, bgep); 31831369Sdduvall bgep->bge_guard = BGE_GUARD; 31841369Sdduvall bgep->devinfo = devinfo; 31855903Ssowmini bgep->param_drain_max = 64; 31865903Ssowmini bgep->param_msi_cnt = 0; 31875903Ssowmini bgep->param_loop_mode = 0; 31881369Sdduvall 31891369Sdduvall /* 31901369Sdduvall * Initialize more fields in BGE private data 31911369Sdduvall */ 31921369Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31934588Sml149210 DDI_PROP_DONTPASS, debug_propname, bge_debug); 31941369Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 31954588Sml149210 BGE_DRIVER_NAME, instance); 31961369Sdduvall 31971369Sdduvall /* 31981865Sdilpreet * Initialize for fma support 31991865Sdilpreet */ 32001865Sdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32011865Sdilpreet DDI_PROP_DONTPASS, fm_cap, 32021865Sdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 32031865Sdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 32041865Sdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 32051865Sdilpreet bge_fm_init(bgep); 32061865Sdilpreet 32071865Sdilpreet /* 32081369Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 32091369Sdduvall * a power of 2) and convert to a mask. This can be used to 32101369Sdduvall * determine whether a message buffer crosses a page boundary. 32111369Sdduvall * Note: in 2s complement binary notation, if X is a power of 32121369Sdduvall * 2, then -X has the representation "11...1100...00". 32131369Sdduvall */ 32141369Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 32151369Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 32161369Sdduvall bgep->pagemask = -bgep->pagemask; 32171369Sdduvall 32181369Sdduvall /* 32191369Sdduvall * Map config space registers 32201369Sdduvall * Read chip ID & set up config space command register(s) 32211369Sdduvall * 32221369Sdduvall * Note: this leaves the chip accessible by Memory Space 32231369Sdduvall * accesses, but with interrupts and Bus Mastering off. 32241369Sdduvall * This should ensure that nothing untoward will happen 32251369Sdduvall * if it has been left active by the (net-)bootloader. 32261369Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 32271369Sdduvall * and allow interrupts only when everything else is set up. 32281369Sdduvall */ 32291369Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 32301408Srandyf #ifdef BGE_IPMI_ASF 32313918Sml149210 #ifdef __sparc 32323918Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM); 32333918Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME); 32343918Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16); 32353918Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 32364588Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 32374588Sml149210 MHCR_MASK_INTERRUPT_MODE | 32384588Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 32394588Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 32404588Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 32414588Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 32423918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue); 32433918Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG, 32444588Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) | 32454588Sml149210 MEMORY_ARBITER_ENABLE); 32463918Sml149210 #else 32471408Srandyf mhcrValue = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 32483918Sml149210 #endif 32491408Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 32501408Srandyf bgep->asf_wordswapped = B_TRUE; 32511408Srandyf } else { 32521408Srandyf bgep->asf_wordswapped = B_FALSE; 32531408Srandyf } 32541408Srandyf bge_asf_get_config(bgep); 32551408Srandyf #endif 32561369Sdduvall if (err != DDI_SUCCESS) { 32571369Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 32581369Sdduvall goto attach_fail; 32591369Sdduvall } 32601369Sdduvall bgep->progress |= PROGRESS_CFG; 32611369Sdduvall cidp = &bgep->chipid; 32621369Sdduvall bzero(cidp, sizeof (*cidp)); 32631369Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 32641865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 32651865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 32661865Sdilpreet goto attach_fail; 32671865Sdilpreet } 32681369Sdduvall 32691408Srandyf #ifdef BGE_IPMI_ASF 32701408Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 32711408Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 32721408Srandyf bgep->asf_newhandshake = B_TRUE; 32731408Srandyf } else { 32741408Srandyf bgep->asf_newhandshake = B_FALSE; 32751408Srandyf } 32761408Srandyf #endif 32771408Srandyf 32781369Sdduvall /* 32791369Sdduvall * Update those parts of the chip ID derived from volatile 32801369Sdduvall * registers with the values seen by OBP (in case the chip 32811369Sdduvall * has been reset externally and therefore lost them). 32821369Sdduvall */ 32831369Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32844588Sml149210 DDI_PROP_DONTPASS, subven_propname, cidp->subven); 32851369Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32864588Sml149210 DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 32871369Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32884588Sml149210 DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 32891369Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32904588Sml149210 DDI_PROP_DONTPASS, latency_propname, cidp->latency); 32911369Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32924588Sml149210 DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 32931369Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32944588Sml149210 DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 32951369Sdduvall 32961369Sdduvall if (bge_jumbo_enable == B_TRUE) { 32971369Sdduvall cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 32984588Sml149210 DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 32991369Sdduvall if ((cidp->default_mtu < BGE_DEFAULT_MTU)|| 33004588Sml149210 (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 33011369Sdduvall cidp->default_mtu = BGE_DEFAULT_MTU; 33021369Sdduvall } 33031369Sdduvall } 33041369Sdduvall /* 33051369Sdduvall * Map operating registers 33061369Sdduvall */ 33071369Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 33084588Sml149210 ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 33091369Sdduvall if (err != DDI_SUCCESS) { 33101369Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 33111369Sdduvall goto attach_fail; 33121369Sdduvall } 33131369Sdduvall bgep->io_regs = regs; 33141369Sdduvall bgep->progress |= PROGRESS_REGS; 33151369Sdduvall 33161369Sdduvall /* 33171369Sdduvall * Characterise the device, so we know its requirements. 33181369Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 33191369Sdduvall */ 33201865Sdilpreet if (bge_chip_id_init(bgep) == EIO) { 33211865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33221865Sdilpreet goto attach_fail; 33231865Sdilpreet } 33246512Ssowmini 33256512Ssowmini 33261369Sdduvall err = bge_alloc_bufs(bgep); 33271369Sdduvall if (err != DDI_SUCCESS) { 33281369Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 33291369Sdduvall goto attach_fail; 33301369Sdduvall } 33311865Sdilpreet bgep->progress |= PROGRESS_BUFS; 33321369Sdduvall 33331369Sdduvall /* 33341369Sdduvall * Add the softint handlers: 33351369Sdduvall * 33361369Sdduvall * Both of these handlers are used to avoid restrictions on the 33371369Sdduvall * context and/or mutexes required for some operations. In 33381369Sdduvall * particular, the hardware interrupt handler and its subfunctions 33391369Sdduvall * can detect a number of conditions that we don't want to handle 33401369Sdduvall * in that context or with that set of mutexes held. So, these 33411369Sdduvall * softints are triggered instead: 33421369Sdduvall * 33432135Szh199473 * the <resched> softint is triggered if we have previously 33441369Sdduvall * had to refuse to send a packet because of resource shortage 33451369Sdduvall * (we've run out of transmit buffers), but the send completion 33461369Sdduvall * interrupt handler has now detected that more buffers have 33471369Sdduvall * become available. 33481369Sdduvall * 33491369Sdduvall * the <factotum> is triggered if the h/w interrupt handler 33501369Sdduvall * sees the <link state changed> or <error> bits in the status 33511369Sdduvall * block. It's also triggered periodically to poll the link 33521369Sdduvall * state, just in case we aren't getting link status change 33531369Sdduvall * interrupts ... 33541369Sdduvall */ 33553334Sgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id, 33564588Sml149210 NULL, NULL, bge_send_drain, (caddr_t)bgep); 33571369Sdduvall if (err != DDI_SUCCESS) { 33581369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 33591369Sdduvall goto attach_fail; 33601369Sdduvall } 33611369Sdduvall bgep->progress |= PROGRESS_RESCHED; 33621369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 33634588Sml149210 NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 33641369Sdduvall if (err != DDI_SUCCESS) { 33651369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 33661369Sdduvall goto attach_fail; 33671369Sdduvall } 33681369Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 33691369Sdduvall 33701369Sdduvall /* Get supported interrupt types */ 33711369Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 33721369Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 33731369Sdduvall 33741369Sdduvall goto attach_fail; 33751369Sdduvall } 33761369Sdduvall 33772675Szh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x", 33784588Sml149210 bgep->ifname, intr_types)); 33791369Sdduvall 33801369Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 33811369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 33821369Sdduvall bge_error(bgep, "MSI registration failed, " 33831369Sdduvall "trying FIXED interrupt type\n"); 33841369Sdduvall } else { 33852675Szh199473 BGE_DEBUG(("%s: Using MSI interrupt type", 33864588Sml149210 bgep->ifname)); 33871369Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 33881865Sdilpreet bgep->progress |= PROGRESS_HWINT; 33891369Sdduvall } 33901369Sdduvall } 33911369Sdduvall 33921865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 33931369Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 33941369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 33951369Sdduvall bge_error(bgep, "FIXED interrupt " 33961369Sdduvall "registration failed\n"); 33971369Sdduvall goto attach_fail; 33981369Sdduvall } 33991369Sdduvall 34002675Szh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname)); 34011369Sdduvall 34021369Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 34031865Sdilpreet bgep->progress |= PROGRESS_HWINT; 34041369Sdduvall } 34051369Sdduvall 34061865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 34071369Sdduvall bge_error(bgep, "No interrupts registered\n"); 34081369Sdduvall goto attach_fail; 34091369Sdduvall } 34101369Sdduvall 34111369Sdduvall /* 34121369Sdduvall * Note that interrupts are not enabled yet as 34131865Sdilpreet * mutex locks are not initialized. Initialize mutex locks. 34141865Sdilpreet */ 34151865Sdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 34161865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 34171865Sdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 34181865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 34191865Sdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 34201865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 34211865Sdilpreet 34221865Sdilpreet /* 34231865Sdilpreet * Initialize rings. 34241369Sdduvall */ 34251369Sdduvall bge_init_rings(bgep); 34261369Sdduvall 34271369Sdduvall /* 34281369Sdduvall * Now that mutex locks are initialized, enable interrupts. 34291369Sdduvall */ 34301865Sdilpreet bge_intr_enable(bgep); 34311865Sdilpreet bgep->progress |= PROGRESS_INTR; 34321369Sdduvall 34331369Sdduvall /* 34341369Sdduvall * Initialise link state variables 34351369Sdduvall * Stop, reset & reinitialise the chip. 34361369Sdduvall * Initialise the (internal) PHY. 34371369Sdduvall */ 34381369Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 34391369Sdduvall 34401369Sdduvall mutex_enter(bgep->genlock); 34411369Sdduvall 34421369Sdduvall /* 34431369Sdduvall * Reset chip & rings to initial state; also reset address 34441369Sdduvall * filtering, promiscuity, loopback mode. 34451369Sdduvall */ 34461408Srandyf #ifdef BGE_IPMI_ASF 34473918Sml149210 #ifdef BGE_NETCONSOLE 34483918Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 34493918Sml149210 #else 34501865Sdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 34513918Sml149210 #endif 34521408Srandyf #else 34531865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 34541408Srandyf #endif 34551865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 34561865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 34571865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34581865Sdilpreet mutex_exit(bgep->genlock); 34591865Sdilpreet goto attach_fail; 34601865Sdilpreet } 34611369Sdduvall 34622675Szh199473 #ifdef BGE_IPMI_ASF 34632675Szh199473 if (bgep->asf_enabled) { 34642675Szh199473 bgep->asf_status = ASF_STAT_RUN_INIT; 34652675Szh199473 } 34662675Szh199473 #endif 34672675Szh199473 34681369Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 34691369Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 34701369Sdduvall bgep->promisc = B_FALSE; 34711369Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 34721865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 34731865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34741865Sdilpreet mutex_exit(bgep->genlock); 34751865Sdilpreet goto attach_fail; 34761865Sdilpreet } 34771865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 34781865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34791865Sdilpreet mutex_exit(bgep->genlock); 34801865Sdilpreet goto attach_fail; 34811865Sdilpreet } 34821369Sdduvall 34831369Sdduvall mutex_exit(bgep->genlock); 34841369Sdduvall 34851865Sdilpreet if (bge_phys_init(bgep) == EIO) { 34861865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 34871865Sdilpreet goto attach_fail; 34881865Sdilpreet } 34891369Sdduvall bgep->progress |= PROGRESS_PHY; 34901369Sdduvall 34911369Sdduvall /* 34926512Ssowmini * initialize NDD-tweakable parameters 34931369Sdduvall */ 34941369Sdduvall if (bge_nd_init(bgep)) { 34951369Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 34961369Sdduvall goto attach_fail; 34971369Sdduvall } 34981369Sdduvall bgep->progress |= PROGRESS_NDD; 34991369Sdduvall 35001369Sdduvall /* 35011369Sdduvall * Create & initialise named kstats 35021369Sdduvall */ 35031369Sdduvall bge_init_kstats(bgep, instance); 35041369Sdduvall bgep->progress |= PROGRESS_KSTATS; 35051369Sdduvall 35061369Sdduvall /* 35071369Sdduvall * Determine whether to override the chip's own MAC address 35081369Sdduvall */ 35091369Sdduvall bge_find_mac_address(bgep, cidp); 35102331Skrgopi 35112406Skrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX; 35128275SEric Cheng bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX; 35131369Sdduvall 35142311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 35152311Sseb goto attach_fail; 35162311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 35172311Sseb macp->m_driver = bgep; 35181369Sdduvall macp->m_dip = devinfo; 35198275SEric Cheng macp->m_src_addr = cidp->vendor_addr.addr; 35202311Sseb macp->m_callbacks = &bge_m_callbacks; 35212311Sseb macp->m_min_sdu = 0; 35222311Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); 35235895Syz147064 macp->m_margin = VLAN_TAGSZ; 35246512Ssowmini macp->m_priv_props = bge_priv_prop; 35256512Ssowmini macp->m_priv_prop_count = BGE_MAX_PRIV_PROPS; 35268275SEric Cheng macp->m_v12n = MAC_VIRT_LEVEL1; 35276512Ssowmini 35281369Sdduvall /* 35291369Sdduvall * Finally, we're ready to register ourselves with the MAC layer 35301369Sdduvall * interface; if this succeeds, we're all ready to start() 35311369Sdduvall */ 35322311Sseb err = mac_register(macp, &bgep->mh); 35332311Sseb mac_free(macp); 35342311Sseb if (err != 0) 35351369Sdduvall goto attach_fail; 35361369Sdduvall 35375107Seota /* 35385107Seota * Register a periodical handler. 35395107Seota * bge_chip_cyclic() is invoked in kernel context. 35405107Seota */ 35415107Seota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep, 35425107Seota BGE_CYCLIC_PERIOD, DDI_IPL_0); 35431369Sdduvall 35441369Sdduvall bgep->progress |= PROGRESS_READY; 35451369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 35463918Sml149210 #ifdef BGE_IPMI_ASF 35473918Sml149210 #ifdef BGE_NETCONSOLE 35483918Sml149210 if (bgep->asf_enabled) { 35493918Sml149210 mutex_enter(bgep->genlock); 35503918Sml149210 retval = bge_chip_start(bgep, B_TRUE); 35513918Sml149210 mutex_exit(bgep->genlock); 35523918Sml149210 if (retval != DDI_SUCCESS) 35533918Sml149210 goto attach_fail; 35543918Sml149210 } 35553918Sml149210 #endif 35563918Sml149210 #endif 35577656SSherry.Moore@Sun.COM 35587656SSherry.Moore@Sun.COM ddi_report_dev(devinfo); 35598993SYong.Tan@Sun.COM BGE_REPORT((bgep, "bge version: %s", bge_version)); 35608922SYong.Tan@Sun.COM 35611369Sdduvall return (DDI_SUCCESS); 35621369Sdduvall 35631369Sdduvall attach_fail: 35641408Srandyf #ifdef BGE_IPMI_ASF 35652675Szh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN); 35661408Srandyf #else 35671369Sdduvall bge_unattach(bgep); 35681408Srandyf #endif 35691369Sdduvall return (DDI_FAILURE); 35701369Sdduvall } 35711369Sdduvall 35721369Sdduvall /* 35731369Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 35741369Sdduvall */ 35751369Sdduvall static int 35761369Sdduvall bge_suspend(bge_t *bgep) 35771369Sdduvall { 35781369Sdduvall /* 35791369Sdduvall * Stop processing and idle (powerdown) the PHY ... 35801369Sdduvall */ 35811369Sdduvall mutex_enter(bgep->genlock); 35821408Srandyf #ifdef BGE_IPMI_ASF 35831408Srandyf /* 35841408Srandyf * Power management hasn't been supported in BGE now. If you 35851408Srandyf * want to implement it, please add the ASF/IPMI related 35861408Srandyf * code here. 35871408Srandyf */ 35881408Srandyf #endif 35891369Sdduvall bge_stop(bgep); 35901865Sdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 35911865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 35921865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 35931865Sdilpreet mutex_exit(bgep->genlock); 35941865Sdilpreet return (DDI_FAILURE); 35951865Sdilpreet } 35961865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 35971865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 35981865Sdilpreet mutex_exit(bgep->genlock); 35991865Sdilpreet return (DDI_FAILURE); 36001865Sdilpreet } 36011369Sdduvall mutex_exit(bgep->genlock); 36021369Sdduvall 36031369Sdduvall return (DDI_SUCCESS); 36041369Sdduvall } 36051369Sdduvall 36061369Sdduvall /* 36077656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 36087656SSherry.Moore@Sun.COM * 36097656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 36107656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 36117656SSherry.Moore@Sun.COM * blocked. 36127656SSherry.Moore@Sun.COM * 36137656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 36147656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 36157656SSherry.Moore@Sun.COM */ 36167656SSherry.Moore@Sun.COM #ifdef __sparc 36177656SSherry.Moore@Sun.COM #define bge_quiesce ddi_quiesce_not_supported 36187656SSherry.Moore@Sun.COM #else 36197656SSherry.Moore@Sun.COM static int 36207656SSherry.Moore@Sun.COM bge_quiesce(dev_info_t *devinfo) 36217656SSherry.Moore@Sun.COM { 36227656SSherry.Moore@Sun.COM bge_t *bgep = ddi_get_driver_private(devinfo); 36237656SSherry.Moore@Sun.COM 36247656SSherry.Moore@Sun.COM if (bgep == NULL) 36257656SSherry.Moore@Sun.COM return (DDI_FAILURE); 36267656SSherry.Moore@Sun.COM 36277656SSherry.Moore@Sun.COM if (bgep->intr_type == DDI_INTR_TYPE_FIXED) { 36287656SSherry.Moore@Sun.COM bge_reg_set32(bgep, PCI_CONF_BGE_MHCR, 36297656SSherry.Moore@Sun.COM MHCR_MASK_PCI_INT_OUTPUT); 36307656SSherry.Moore@Sun.COM } else { 36317656SSherry.Moore@Sun.COM bge_reg_clr32(bgep, MSI_MODE_REG, MSI_MSI_ENABLE); 36327656SSherry.Moore@Sun.COM } 36337656SSherry.Moore@Sun.COM 36347656SSherry.Moore@Sun.COM /* Stop the chip */ 36357656SSherry.Moore@Sun.COM bge_chip_stop_nonblocking(bgep); 36367656SSherry.Moore@Sun.COM 36377656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 36387656SSherry.Moore@Sun.COM } 36397656SSherry.Moore@Sun.COM #endif 36407656SSherry.Moore@Sun.COM 36417656SSherry.Moore@Sun.COM /* 36421369Sdduvall * detach(9E) -- Detach a device from the system 36431369Sdduvall */ 36441369Sdduvall static int 36451369Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 36461369Sdduvall { 36471369Sdduvall bge_t *bgep; 36481408Srandyf #ifdef BGE_IPMI_ASF 36491408Srandyf uint_t asf_mode; 36501408Srandyf asf_mode = ASF_MODE_NONE; 36511408Srandyf #endif 36521369Sdduvall 36531369Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 36541369Sdduvall 36551369Sdduvall bgep = ddi_get_driver_private(devinfo); 36561369Sdduvall 36571369Sdduvall switch (cmd) { 36581369Sdduvall default: 36591369Sdduvall return (DDI_FAILURE); 36601369Sdduvall 36611369Sdduvall case DDI_SUSPEND: 36621369Sdduvall return (bge_suspend(bgep)); 36631369Sdduvall 36641369Sdduvall case DDI_DETACH: 36651369Sdduvall break; 36661369Sdduvall } 36671369Sdduvall 36681408Srandyf #ifdef BGE_IPMI_ASF 36691408Srandyf mutex_enter(bgep->genlock); 36702675Szh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) || 36714588Sml149210 (bgep->asf_status == ASF_STAT_RUN_INIT))) { 36721408Srandyf 36731408Srandyf bge_asf_update_status(bgep); 36742675Szh199473 if (bgep->asf_status == ASF_STAT_RUN) { 36752675Szh199473 bge_asf_stop_timer(bgep); 36762675Szh199473 } 36771408Srandyf bgep->asf_status = ASF_STAT_STOP; 36781408Srandyf 36791408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 36801408Srandyf 36811408Srandyf if (bgep->asf_pseudostop) { 36821408Srandyf bge_chip_stop(bgep, B_FALSE); 36831408Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 36841408Srandyf bgep->asf_pseudostop = B_FALSE; 36851408Srandyf } 36861408Srandyf 36871408Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 36881865Sdilpreet 36891865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 36901865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 36911865Sdilpreet DDI_SERVICE_UNAFFECTED); 36921865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 36931865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 36941865Sdilpreet DDI_SERVICE_UNAFFECTED); 36951408Srandyf } 36961408Srandyf mutex_exit(bgep->genlock); 36971408Srandyf #endif 36981408Srandyf 36991369Sdduvall /* 37001369Sdduvall * Unregister from the GLD subsystem. This can fail, in 37011369Sdduvall * particular if there are DLPI style-2 streams still open - 37021369Sdduvall * in which case we just return failure without shutting 37031369Sdduvall * down chip operations. 37041369Sdduvall */ 37052311Sseb if (mac_unregister(bgep->mh) != 0) 37061369Sdduvall return (DDI_FAILURE); 37071369Sdduvall 37081369Sdduvall /* 37091369Sdduvall * All activity stopped, so we can clean up & exit 37101369Sdduvall */ 37111408Srandyf #ifdef BGE_IPMI_ASF 37121408Srandyf bge_unattach(bgep, asf_mode); 37131408Srandyf #else 37141369Sdduvall bge_unattach(bgep); 37151408Srandyf #endif 37161369Sdduvall return (DDI_SUCCESS); 37171369Sdduvall } 37181369Sdduvall 37191369Sdduvall 37201369Sdduvall /* 37211369Sdduvall * ========== Module Loading Data & Entry Points ========== 37221369Sdduvall */ 37231369Sdduvall 37241369Sdduvall #undef BGE_DBG 37251369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 37261369Sdduvall 37277656SSherry.Moore@Sun.COM DDI_DEFINE_STREAM_OPS(bge_dev_ops, 37287656SSherry.Moore@Sun.COM nulldev, /* identify */ 37297656SSherry.Moore@Sun.COM nulldev, /* probe */ 37307656SSherry.Moore@Sun.COM bge_attach, /* attach */ 37317656SSherry.Moore@Sun.COM bge_detach, /* detach */ 37327656SSherry.Moore@Sun.COM nodev, /* reset */ 37337656SSherry.Moore@Sun.COM NULL, /* cb_ops */ 37347656SSherry.Moore@Sun.COM D_MP, /* bus_ops */ 37357656SSherry.Moore@Sun.COM NULL, /* power */ 37367656SSherry.Moore@Sun.COM bge_quiesce /* quiesce */ 37377656SSherry.Moore@Sun.COM ); 37381369Sdduvall 37391369Sdduvall static struct modldrv bge_modldrv = { 37401369Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 37411369Sdduvall bge_ident, /* short description */ 37421369Sdduvall &bge_dev_ops /* driver specific ops */ 37431369Sdduvall }; 37441369Sdduvall 37451369Sdduvall static struct modlinkage modlinkage = { 37461369Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 37471369Sdduvall }; 37481369Sdduvall 37491369Sdduvall 37501369Sdduvall int 37511369Sdduvall _info(struct modinfo *modinfop) 37521369Sdduvall { 37531369Sdduvall return (mod_info(&modlinkage, modinfop)); 37541369Sdduvall } 37551369Sdduvall 37561369Sdduvall int 37571369Sdduvall _init(void) 37581369Sdduvall { 37591369Sdduvall int status; 37601369Sdduvall 37611369Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 37621369Sdduvall status = mod_install(&modlinkage); 37631369Sdduvall if (status == DDI_SUCCESS) 37641369Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 37651369Sdduvall else 37661369Sdduvall mac_fini_ops(&bge_dev_ops); 37671369Sdduvall return (status); 37681369Sdduvall } 37691369Sdduvall 37701369Sdduvall int 37711369Sdduvall _fini(void) 37721369Sdduvall { 37731369Sdduvall int status; 37741369Sdduvall 37751369Sdduvall status = mod_remove(&modlinkage); 37761369Sdduvall if (status == DDI_SUCCESS) { 37771369Sdduvall mac_fini_ops(&bge_dev_ops); 37781369Sdduvall mutex_destroy(bge_log_mutex); 37791369Sdduvall } 37801369Sdduvall return (status); 37811369Sdduvall } 37821369Sdduvall 37831369Sdduvall 37841369Sdduvall /* 37851369Sdduvall * bge_add_intrs: 37861369Sdduvall * 37871369Sdduvall * Register FIXED or MSI interrupts. 37881369Sdduvall */ 37891369Sdduvall static int 37901369Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 37911369Sdduvall { 37921369Sdduvall dev_info_t *dip = bgep->devinfo; 37931369Sdduvall int avail, actual, intr_size, count = 0; 37941369Sdduvall int i, flag, ret; 37951369Sdduvall 37962675Szh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type)); 37971369Sdduvall 37981369Sdduvall /* Get number of interrupts */ 37991369Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 38001369Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 38011369Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 38021369Sdduvall "count: %d", ret, count); 38031369Sdduvall 38041369Sdduvall return (DDI_FAILURE); 38051369Sdduvall } 38061369Sdduvall 38071369Sdduvall /* Get number of available interrupts */ 38081369Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 38091369Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 38101369Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 38111369Sdduvall "ret: %d, avail: %d\n", ret, avail); 38121369Sdduvall 38131369Sdduvall return (DDI_FAILURE); 38141369Sdduvall } 38151369Sdduvall 38161369Sdduvall if (avail < count) { 38172675Szh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d", 38182675Szh199473 bgep->ifname, count, avail)); 38191369Sdduvall } 38201369Sdduvall 38211369Sdduvall /* 38221369Sdduvall * BGE hardware generates only single MSI even though it claims 38231369Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 38241369Sdduvall */ 38251369Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 38261369Sdduvall count = 1; 38271369Sdduvall flag = DDI_INTR_ALLOC_STRICT; 38281369Sdduvall } else { 38291369Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 38301369Sdduvall } 38311369Sdduvall 38321369Sdduvall /* Allocate an array of interrupt handles */ 38331369Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 38341369Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 38351369Sdduvall 38361369Sdduvall /* Call ddi_intr_alloc() */ 38371369Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 38381369Sdduvall count, &actual, flag); 38391369Sdduvall 38401369Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 38411369Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 38421369Sdduvall 38431369Sdduvall kmem_free(bgep->htable, intr_size); 38441369Sdduvall return (DDI_FAILURE); 38451369Sdduvall } 38461369Sdduvall 38471369Sdduvall if (actual < count) { 38482675Szh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d", 38494588Sml149210 bgep->ifname, count, actual)); 38501369Sdduvall } 38511369Sdduvall 38521369Sdduvall bgep->intr_cnt = actual; 38531369Sdduvall 38541369Sdduvall /* 38551369Sdduvall * Get priority for first msi, assume remaining are all the same 38561369Sdduvall */ 38571369Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 38581369Sdduvall DDI_SUCCESS) { 38591369Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 38601369Sdduvall 38611369Sdduvall /* Free already allocated intr */ 38621369Sdduvall for (i = 0; i < actual; i++) { 38631369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38641369Sdduvall } 38651369Sdduvall 38661369Sdduvall kmem_free(bgep->htable, intr_size); 38671369Sdduvall return (DDI_FAILURE); 38681369Sdduvall } 38691369Sdduvall 38701369Sdduvall /* Call ddi_intr_add_handler() */ 38711369Sdduvall for (i = 0; i < actual; i++) { 38721369Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 38731369Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 38741369Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 38751369Sdduvall "failed %d\n", ret); 38761369Sdduvall 38771369Sdduvall /* Free already allocated intr */ 38781369Sdduvall for (i = 0; i < actual; i++) { 38791369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38801369Sdduvall } 38811369Sdduvall 38821369Sdduvall kmem_free(bgep->htable, intr_size); 38831369Sdduvall return (DDI_FAILURE); 38841369Sdduvall } 38851369Sdduvall } 38861369Sdduvall 38871369Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 38884588Sml149210 != DDI_SUCCESS) { 38891369Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 38901369Sdduvall 38911369Sdduvall for (i = 0; i < actual; i++) { 38921369Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 38931369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 38941369Sdduvall } 38951369Sdduvall 38961369Sdduvall kmem_free(bgep->htable, intr_size); 38971369Sdduvall return (DDI_FAILURE); 38981369Sdduvall } 38991369Sdduvall 39001369Sdduvall return (DDI_SUCCESS); 39011369Sdduvall } 39021369Sdduvall 39031369Sdduvall /* 39041369Sdduvall * bge_rem_intrs: 39051369Sdduvall * 39061369Sdduvall * Unregister FIXED or MSI interrupts 39071369Sdduvall */ 39081369Sdduvall static void 39091369Sdduvall bge_rem_intrs(bge_t *bgep) 39101369Sdduvall { 39111369Sdduvall int i; 39121369Sdduvall 39132675Szh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep)); 39141369Sdduvall 39151865Sdilpreet /* Call ddi_intr_remove_handler() */ 39161865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 39171865Sdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 39181865Sdilpreet (void) ddi_intr_free(bgep->htable[i]); 39191865Sdilpreet } 39201865Sdilpreet 39211865Sdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 39221865Sdilpreet } 39231865Sdilpreet 39241865Sdilpreet 39251865Sdilpreet void 39261865Sdilpreet bge_intr_enable(bge_t *bgep) 39271865Sdilpreet { 39281865Sdilpreet int i; 39291865Sdilpreet 39301865Sdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 39311865Sdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 39321865Sdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 39331865Sdilpreet } else { 39341865Sdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 39351865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 39361865Sdilpreet (void) ddi_intr_enable(bgep->htable[i]); 39371865Sdilpreet } 39381865Sdilpreet } 39391865Sdilpreet } 39401865Sdilpreet 39411865Sdilpreet 39421865Sdilpreet void 39431865Sdilpreet bge_intr_disable(bge_t *bgep) 39441865Sdilpreet { 39451865Sdilpreet int i; 39461865Sdilpreet 39471369Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 39481369Sdduvall /* Call ddi_intr_block_disable() */ 39491369Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 39501369Sdduvall } else { 39511369Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 39521369Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 39531369Sdduvall } 39541369Sdduvall } 39551369Sdduvall } 39565903Ssowmini 39575903Ssowmini int 39585903Ssowmini bge_reprogram(bge_t *bgep) 39595903Ssowmini { 39605903Ssowmini int status = 0; 39615903Ssowmini 39625903Ssowmini ASSERT(mutex_owned(bgep->genlock)); 39635903Ssowmini 39645903Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) { 39655903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 39665903Ssowmini status = IOC_INVAL; 39675903Ssowmini } 39685903Ssowmini #ifdef BGE_IPMI_ASF 39695903Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 39705903Ssowmini #else 39715903Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) { 39725903Ssowmini #endif 39735903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 39745903Ssowmini status = IOC_INVAL; 39755903Ssowmini } 39765903Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI) 39775903Ssowmini bge_chip_msi_trig(bgep); 39785903Ssowmini return (status); 39795903Ssowmini } 3980