11369Sdduvall /* 21369Sdduvall * CDDL HEADER START 31369Sdduvall * 41369Sdduvall * The contents of this file are subject to the terms of the 51369Sdduvall * Common Development and Distribution License (the "License"). 61369Sdduvall * You may not use this file except in compliance with the License. 71369Sdduvall * 81369Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91369Sdduvall * or http://www.opensolaris.org/os/licensing. 101369Sdduvall * See the License for the specific language governing permissions 111369Sdduvall * and limitations under the License. 121369Sdduvall * 131369Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 141369Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151369Sdduvall * If applicable, add the following below this CDDL HEADER, with the 161369Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 171369Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 181369Sdduvall * 191369Sdduvall * CDDL HEADER END 201369Sdduvall */ 211369Sdduvall 221369Sdduvall /* 235895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 271369Sdduvall #pragma ident "%Z%%M% %I% %E% SMI" 281369Sdduvall 292675Szh199473 #include "bge_impl.h" 301369Sdduvall #include <sys/sdt.h> 315903Ssowmini #include <sys/dld.h> 321369Sdduvall 331369Sdduvall /* 341369Sdduvall * This is the string displayed by modinfo, etc. 351369Sdduvall * Make sure you keep the version ID up to date! 361369Sdduvall */ 37*6546Sgh162552 static char bge_ident[] = "Broadcom Gb Ethernet v0.62"; 381369Sdduvall 391369Sdduvall /* 401369Sdduvall * Property names 411369Sdduvall */ 421369Sdduvall static char debug_propname[] = "bge-debug-flags"; 431369Sdduvall static char clsize_propname[] = "cache-line-size"; 441369Sdduvall static char latency_propname[] = "latency-timer"; 451369Sdduvall static char localmac_boolname[] = "local-mac-address?"; 461369Sdduvall static char localmac_propname[] = "local-mac-address"; 471369Sdduvall static char macaddr_propname[] = "mac-address"; 481369Sdduvall static char subdev_propname[] = "subsystem-id"; 491369Sdduvall static char subven_propname[] = "subsystem-vendor-id"; 501369Sdduvall static char rxrings_propname[] = "bge-rx-rings"; 511369Sdduvall static char txrings_propname[] = "bge-tx-rings"; 521865Sdilpreet static char fm_cap[] = "fm-capable"; 531908Sly149593 static char default_mtu[] = "default_mtu"; 541369Sdduvall 551369Sdduvall static int bge_add_intrs(bge_t *, int); 561369Sdduvall static void bge_rem_intrs(bge_t *); 571369Sdduvall 581369Sdduvall /* 591369Sdduvall * Describes the chip's DMA engine 601369Sdduvall */ 611369Sdduvall static ddi_dma_attr_t dma_attr = { 621369Sdduvall DMA_ATTR_V0, /* dma_attr version */ 631369Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */ 641369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 651369Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 661369Sdduvall 0x0000000000000001ull, /* dma_attr_align */ 671369Sdduvall 0x00000FFF, /* dma_attr_burstsizes */ 681369Sdduvall 0x00000001, /* dma_attr_minxfer */ 691369Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */ 701369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 711369Sdduvall 1, /* dma_attr_sgllen */ 721369Sdduvall 0x00000001, /* dma_attr_granular */ 731865Sdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */ 741369Sdduvall }; 751369Sdduvall 761369Sdduvall /* 771369Sdduvall * PIO access attributes for registers 781369Sdduvall */ 791369Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = { 801369Sdduvall DDI_DEVICE_ATTR_V0, 811369Sdduvall DDI_NEVERSWAP_ACC, 821865Sdilpreet DDI_STRICTORDER_ACC, 831865Sdilpreet DDI_FLAGERR_ACC 841369Sdduvall }; 851369Sdduvall 861369Sdduvall /* 871369Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped. 881369Sdduvall */ 891369Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = { 901369Sdduvall DDI_DEVICE_ATTR_V0, 911369Sdduvall DDI_NEVERSWAP_ACC, 921865Sdilpreet DDI_STRICTORDER_ACC, 931865Sdilpreet DDI_FLAGERR_ACC 941369Sdduvall }; 951369Sdduvall 961369Sdduvall /* 971369Sdduvall * DMA access attributes for data: NOT to be byte swapped. 981369Sdduvall */ 991369Sdduvall static ddi_device_acc_attr_t bge_data_accattr = { 1001369Sdduvall DDI_DEVICE_ATTR_V0, 1011369Sdduvall DDI_NEVERSWAP_ACC, 1021369Sdduvall DDI_STRICTORDER_ACC 1031369Sdduvall }; 1041369Sdduvall 1051369Sdduvall /* 1061369Sdduvall * Versions of the O/S up to Solaris 8 didn't support network booting 1071369Sdduvall * from any network interface except the first (NET0). Patching this 1081369Sdduvall * flag to a non-zero value will tell the driver to work around this 1091369Sdduvall * limitation by creating an extra (internal) pathname node. To do 1101369Sdduvall * this, just add a line like the following to the CLIENT'S etc/system 1111369Sdduvall * file ON THE ROOT FILESYSTEM SERVER before booting the client: 1121369Sdduvall * 1131369Sdduvall * set bge:bge_net1_boot_support = 1; 1141369Sdduvall */ 1151369Sdduvall static uint32_t bge_net1_boot_support = 1; 1161369Sdduvall 1172311Sseb static int bge_m_start(void *); 1182311Sseb static void bge_m_stop(void *); 1192311Sseb static int bge_m_promisc(void *, boolean_t); 1202311Sseb static int bge_m_multicst(void *, boolean_t, const uint8_t *); 1212311Sseb static int bge_m_unicst(void *, const uint8_t *); 1222311Sseb static void bge_m_resources(void *); 1232311Sseb static void bge_m_ioctl(void *, queue_t *, mblk_t *); 1242311Sseb static boolean_t bge_m_getcapab(void *, mac_capab_t, void *); 1252331Skrgopi static int bge_unicst_set(void *, const uint8_t *, 1262331Skrgopi mac_addr_slot_t); 1272331Skrgopi static int bge_m_unicst_add(void *, mac_multi_addr_t *); 1282331Skrgopi static int bge_m_unicst_remove(void *, mac_addr_slot_t); 1292331Skrgopi static int bge_m_unicst_modify(void *, mac_multi_addr_t *); 1302331Skrgopi static int bge_m_unicst_get(void *, mac_multi_addr_t *); 1315903Ssowmini static int bge_m_setprop(void *, const char *, mac_prop_id_t, 1325903Ssowmini uint_t, const void *); 1335903Ssowmini static int bge_m_getprop(void *, const char *, mac_prop_id_t, 1346512Ssowmini uint_t, uint_t, void *); 1355903Ssowmini static int bge_set_priv_prop(bge_t *, const char *, uint_t, 1365903Ssowmini const void *); 1375903Ssowmini static int bge_get_priv_prop(bge_t *, const char *, uint_t, 1386512Ssowmini uint_t, void *); 1395903Ssowmini 1405903Ssowmini #define BGE_M_CALLBACK_FLAGS\ 1415903Ssowmini (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1422311Sseb 1432311Sseb static mac_callbacks_t bge_m_callbacks = { 1442311Sseb BGE_M_CALLBACK_FLAGS, 1452311Sseb bge_m_stat, 1462311Sseb bge_m_start, 1472311Sseb bge_m_stop, 1482311Sseb bge_m_promisc, 1492311Sseb bge_m_multicst, 1502311Sseb bge_m_unicst, 1512311Sseb bge_m_tx, 1522311Sseb bge_m_resources, 1532311Sseb bge_m_ioctl, 1545903Ssowmini bge_m_getcapab, 1555903Ssowmini NULL, 1565903Ssowmini NULL, 1575903Ssowmini bge_m_setprop, 1585903Ssowmini bge_m_getprop 1592311Sseb }; 1602311Sseb 1616512Ssowmini mac_priv_prop_t bge_priv_prop[] = { 1626512Ssowmini {"_adv_asym_pause_cap", MAC_PROP_PERM_RW}, 1636512Ssowmini {"_adv_pause_cap", MAC_PROP_PERM_RW} 1646512Ssowmini }; 1656512Ssowmini 1666512Ssowmini #define BGE_MAX_PRIV_PROPS \ 1676512Ssowmini (sizeof (bge_priv_prop) / sizeof (mac_priv_prop_t)) 1686512Ssowmini 1691369Sdduvall /* 1701369Sdduvall * ========== Transmit and receive ring reinitialisation ========== 1711369Sdduvall */ 1721369Sdduvall 1731369Sdduvall /* 1741369Sdduvall * These <reinit> routines each reset the specified ring to an initial 1751369Sdduvall * state, assuming that the corresponding <init> routine has already 1761369Sdduvall * been called exactly once. 1771369Sdduvall */ 1781369Sdduvall 1791369Sdduvall static void 1801369Sdduvall bge_reinit_send_ring(send_ring_t *srp) 1811369Sdduvall { 1823334Sgs150176 bge_queue_t *txbuf_queue; 1833334Sgs150176 bge_queue_item_t *txbuf_head; 1843334Sgs150176 sw_txbuf_t *txbuf; 1853334Sgs150176 sw_sbd_t *ssbdp; 1863334Sgs150176 uint32_t slot; 1873334Sgs150176 1881369Sdduvall /* 1891369Sdduvall * Reinitialise control variables ... 1901369Sdduvall */ 1913334Sgs150176 srp->tx_flow = 0; 1921369Sdduvall srp->tx_next = 0; 1933334Sgs150176 srp->txfill_next = 0; 1941369Sdduvall srp->tx_free = srp->desc.nslots; 1951369Sdduvall ASSERT(mutex_owned(srp->tc_lock)); 1961369Sdduvall srp->tc_next = 0; 1973334Sgs150176 srp->txpkt_next = 0; 1983334Sgs150176 srp->tx_block = 0; 1993334Sgs150176 srp->tx_nobd = 0; 2003334Sgs150176 srp->tx_nobuf = 0; 2013334Sgs150176 2023334Sgs150176 /* 2033334Sgs150176 * Initialize the tx buffer push queue 2043334Sgs150176 */ 2053334Sgs150176 mutex_enter(srp->freetxbuf_lock); 2063334Sgs150176 mutex_enter(srp->txbuf_lock); 2073334Sgs150176 txbuf_queue = &srp->freetxbuf_queue; 2083334Sgs150176 txbuf_queue->head = NULL; 2093334Sgs150176 txbuf_queue->count = 0; 2103334Sgs150176 txbuf_queue->lock = srp->freetxbuf_lock; 2113334Sgs150176 srp->txbuf_push_queue = txbuf_queue; 2123334Sgs150176 2133334Sgs150176 /* 2143334Sgs150176 * Initialize the tx buffer pop queue 2153334Sgs150176 */ 2163334Sgs150176 txbuf_queue = &srp->txbuf_queue; 2173334Sgs150176 txbuf_queue->head = NULL; 2183334Sgs150176 txbuf_queue->count = 0; 2193334Sgs150176 txbuf_queue->lock = srp->txbuf_lock; 2203334Sgs150176 srp->txbuf_pop_queue = txbuf_queue; 2213334Sgs150176 txbuf_head = srp->txbuf_head; 2223334Sgs150176 txbuf = srp->txbuf; 2233334Sgs150176 for (slot = 0; slot < srp->tx_buffers; ++slot) { 2243334Sgs150176 txbuf_head->item = txbuf; 2253334Sgs150176 txbuf_head->next = txbuf_queue->head; 2263334Sgs150176 txbuf_queue->head = txbuf_head; 2273334Sgs150176 txbuf_queue->count++; 2283334Sgs150176 txbuf++; 2293334Sgs150176 txbuf_head++; 2303334Sgs150176 } 2313334Sgs150176 mutex_exit(srp->txbuf_lock); 2323334Sgs150176 mutex_exit(srp->freetxbuf_lock); 2331369Sdduvall 2341369Sdduvall /* 2351369Sdduvall * Zero and sync all the h/w Send Buffer Descriptors 2361369Sdduvall */ 2371369Sdduvall DMA_ZERO(srp->desc); 2381369Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 2393334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 2403334Sgs150176 ssbdp = srp->sw_sbds; 2413334Sgs150176 for (slot = 0; slot < srp->desc.nslots; ++ssbdp, ++slot) 2423334Sgs150176 ssbdp->pbuf = NULL; 2431369Sdduvall } 2441369Sdduvall 2451369Sdduvall static void 2461369Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp) 2471369Sdduvall { 2481369Sdduvall /* 2491369Sdduvall * Reinitialise control variables ... 2501369Sdduvall */ 2511369Sdduvall rrp->rx_next = 0; 2521369Sdduvall } 2531369Sdduvall 2541369Sdduvall static void 2553334Sgs150176 bge_reinit_buff_ring(buff_ring_t *brp, uint32_t ring) 2561369Sdduvall { 2571369Sdduvall bge_rbd_t *hw_rbd_p; 2581369Sdduvall sw_rbd_t *srbdp; 2591369Sdduvall uint32_t bufsize; 2601369Sdduvall uint32_t nslots; 2611369Sdduvall uint32_t slot; 2621369Sdduvall 2631369Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = { 2641369Sdduvall RBD_FLAG_STD_RING, 2651369Sdduvall RBD_FLAG_JUMBO_RING, 2661369Sdduvall RBD_FLAG_MINI_RING 2671369Sdduvall }; 2681369Sdduvall 2691369Sdduvall /* 2701369Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors 2711369Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>, 2721369Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>) 2731369Sdduvall * should be zeroed, and so don't need to be set up specifically 2741369Sdduvall * once the whole area has been cleared. 2751369Sdduvall */ 2761369Sdduvall DMA_ZERO(brp->desc); 2771369Sdduvall 2781369Sdduvall hw_rbd_p = DMA_VPTR(brp->desc); 2791369Sdduvall nslots = brp->desc.nslots; 2801369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 2811369Sdduvall bufsize = brp->buf[0].size; 2821369Sdduvall srbdp = brp->sw_rbds; 2831369Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) { 2841369Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress; 2851369Sdduvall hw_rbd_p->index = slot; 2861369Sdduvall hw_rbd_p->len = bufsize; 2871369Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token; 2881369Sdduvall hw_rbd_p->flags |= ring_type_flag[ring]; 2891369Sdduvall } 2901369Sdduvall 2911369Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV); 2921369Sdduvall 2931369Sdduvall /* 2941369Sdduvall * Finally, reinitialise the ring control variables ... 2951369Sdduvall */ 2961369Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0; 2971369Sdduvall } 2981369Sdduvall 2991369Sdduvall /* 3001369Sdduvall * Reinitialize all rings 3011369Sdduvall */ 3021369Sdduvall static void 3031369Sdduvall bge_reinit_rings(bge_t *bgep) 3041369Sdduvall { 3053334Sgs150176 uint32_t ring; 3061369Sdduvall 3071369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3081369Sdduvall 3091369Sdduvall /* 3101369Sdduvall * Send Rings ... 3111369Sdduvall */ 3121369Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) 3131369Sdduvall bge_reinit_send_ring(&bgep->send[ring]); 3141369Sdduvall 3151369Sdduvall /* 3161369Sdduvall * Receive Return Rings ... 3171369Sdduvall */ 3181369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring) 3191369Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]); 3201369Sdduvall 3211369Sdduvall /* 3221369Sdduvall * Receive Producer Rings ... 3231369Sdduvall */ 3241369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 3251369Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring); 3261369Sdduvall } 3271369Sdduvall 3281369Sdduvall /* 3291369Sdduvall * ========== Internal state management entry points ========== 3301369Sdduvall */ 3311369Sdduvall 3321369Sdduvall #undef BGE_DBG 3331369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 3341369Sdduvall 3351369Sdduvall /* 3361369Sdduvall * These routines provide all the functionality required by the 3371369Sdduvall * corresponding GLD entry points, but don't update the GLD state 3381369Sdduvall * so they can be called internally without disturbing our record 3391369Sdduvall * of what GLD thinks we should be doing ... 3401369Sdduvall */ 3411369Sdduvall 3421369Sdduvall /* 3431369Sdduvall * bge_reset() -- reset h/w & rings to initial state 3441369Sdduvall */ 3451865Sdilpreet static int 3461408Srandyf #ifdef BGE_IPMI_ASF 3471408Srandyf bge_reset(bge_t *bgep, uint_t asf_mode) 3481408Srandyf #else 3491369Sdduvall bge_reset(bge_t *bgep) 3501408Srandyf #endif 3511369Sdduvall { 3523334Sgs150176 uint32_t ring; 3531865Sdilpreet int retval; 3541369Sdduvall 3551369Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep)); 3561369Sdduvall 3571369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3581369Sdduvall 3591369Sdduvall /* 3601369Sdduvall * Grab all the other mutexes in the world (this should 3611369Sdduvall * ensure no other threads are manipulating driver state) 3621369Sdduvall */ 3631369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 3641369Sdduvall mutex_enter(bgep->recv[ring].rx_lock); 3651369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 3661369Sdduvall mutex_enter(bgep->buff[ring].rf_lock); 3671369Sdduvall rw_enter(bgep->errlock, RW_WRITER); 3681369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3693334Sgs150176 mutex_enter(bgep->send[ring].tx_lock); 3703334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3711369Sdduvall mutex_enter(bgep->send[ring].tc_lock); 3721369Sdduvall 3731408Srandyf #ifdef BGE_IPMI_ASF 3741865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode); 3751408Srandyf #else 3761865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE); 3771408Srandyf #endif 3781369Sdduvall bge_reinit_rings(bgep); 3791369Sdduvall 3801369Sdduvall /* 3811369Sdduvall * Free the world ... 3821369Sdduvall */ 3831369Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; ) 3841369Sdduvall mutex_exit(bgep->send[ring].tc_lock); 3853334Sgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 3863334Sgs150176 mutex_exit(bgep->send[ring].tx_lock); 3871369Sdduvall rw_exit(bgep->errlock); 3881369Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; ) 3891369Sdduvall mutex_exit(bgep->buff[ring].rf_lock); 3901369Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; ) 3911369Sdduvall mutex_exit(bgep->recv[ring].rx_lock); 3921369Sdduvall 3931369Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep)); 3941865Sdilpreet return (retval); 3951369Sdduvall } 3961369Sdduvall 3971369Sdduvall /* 3981369Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings 3991369Sdduvall */ 4001369Sdduvall static void 4011369Sdduvall bge_stop(bge_t *bgep) 4021369Sdduvall { 4031369Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep)); 4041369Sdduvall 4051369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4061369Sdduvall 4071408Srandyf #ifdef BGE_IPMI_ASF 4081408Srandyf if (bgep->asf_enabled) { 4091408Srandyf bgep->asf_pseudostop = B_TRUE; 4101408Srandyf } else { 4111408Srandyf #endif 4121408Srandyf bge_chip_stop(bgep, B_FALSE); 4131408Srandyf #ifdef BGE_IPMI_ASF 4141408Srandyf } 4151408Srandyf #endif 4161369Sdduvall 4171369Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep)); 4181369Sdduvall } 4191369Sdduvall 4201369Sdduvall /* 4211369Sdduvall * bge_start() -- start transmitting/receiving 4221369Sdduvall */ 4231865Sdilpreet static int 4241369Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys) 4251369Sdduvall { 4261865Sdilpreet int retval; 4271865Sdilpreet 4281369Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys)); 4291369Sdduvall 4301369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4311369Sdduvall 4321369Sdduvall /* 4331369Sdduvall * Start chip processing, including enabling interrupts 4341369Sdduvall */ 4351865Sdilpreet retval = bge_chip_start(bgep, reset_phys); 4361369Sdduvall 4371369Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys)); 4381865Sdilpreet return (retval); 4391369Sdduvall } 4401369Sdduvall 4411369Sdduvall /* 4421369Sdduvall * bge_restart - restart transmitting/receiving after error or suspend 4431369Sdduvall */ 4441865Sdilpreet int 4451369Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys) 4461369Sdduvall { 4471865Sdilpreet int retval = DDI_SUCCESS; 4481369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 4491369Sdduvall 4501408Srandyf #ifdef BGE_IPMI_ASF 4511408Srandyf if (bgep->asf_enabled) { 4521865Sdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS) 4531865Sdilpreet retval = DDI_FAILURE; 4541408Srandyf } else 4551865Sdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS) 4561865Sdilpreet retval = DDI_FAILURE; 4571408Srandyf #else 4581865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) 4591865Sdilpreet retval = DDI_FAILURE; 4601408Srandyf #endif 4613440Szh199473 if (bgep->bge_mac_state == BGE_MAC_STARTED) { 4621865Sdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS) 4631865Sdilpreet retval = DDI_FAILURE; 4641369Sdduvall bgep->watchdog = 0; 4653334Sgs150176 ddi_trigger_softintr(bgep->drain_id); 4661369Sdduvall } 4671369Sdduvall 4681369Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys)); 4691865Sdilpreet return (retval); 4701369Sdduvall } 4711369Sdduvall 4721369Sdduvall 4731369Sdduvall /* 4741369Sdduvall * ========== Nemo-required management entry points ========== 4751369Sdduvall */ 4761369Sdduvall 4771369Sdduvall #undef BGE_DBG 4781369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 4791369Sdduvall 4801369Sdduvall /* 4811369Sdduvall * bge_m_stop() -- stop transmitting/receiving 4821369Sdduvall */ 4831369Sdduvall static void 4841369Sdduvall bge_m_stop(void *arg) 4851369Sdduvall { 4861369Sdduvall bge_t *bgep = arg; /* private device info */ 4873334Sgs150176 send_ring_t *srp; 4883334Sgs150176 uint32_t ring; 4891369Sdduvall 4901369Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg)); 4911369Sdduvall 4921369Sdduvall /* 4931369Sdduvall * Just stop processing, then record new GLD state 4941369Sdduvall */ 4951369Sdduvall mutex_enter(bgep->genlock); 4961865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 4971865Sdilpreet /* can happen during autorecovery */ 4981865Sdilpreet mutex_exit(bgep->genlock); 4991865Sdilpreet return; 5001865Sdilpreet } 5011369Sdduvall bge_stop(bgep); 502*6546Sgh162552 503*6546Sgh162552 bgep->link_update_timer = 0; 504*6546Sgh162552 bgep->link_state = LINK_STATE_UNKNOWN; 505*6546Sgh162552 mac_link_update(bgep->mh, bgep->link_state); 506*6546Sgh162552 5073334Sgs150176 /* 5083334Sgs150176 * Free the possible tx buffers allocated in tx process. 5093334Sgs150176 */ 5103334Sgs150176 #ifdef BGE_IPMI_ASF 5113334Sgs150176 if (!bgep->asf_pseudostop) 5123334Sgs150176 #endif 5133334Sgs150176 { 5143334Sgs150176 rw_enter(bgep->errlock, RW_WRITER); 5153334Sgs150176 for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) { 5163334Sgs150176 srp = &bgep->send[ring]; 5173334Sgs150176 mutex_enter(srp->tx_lock); 5183334Sgs150176 if (srp->tx_array > 1) 5193334Sgs150176 bge_free_txbuf_arrays(srp); 5203334Sgs150176 mutex_exit(srp->tx_lock); 5213334Sgs150176 } 5223334Sgs150176 rw_exit(bgep->errlock); 5233334Sgs150176 } 5241369Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED; 5251369Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg)); 5261865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 5271865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 5281369Sdduvall mutex_exit(bgep->genlock); 5291369Sdduvall } 5301369Sdduvall 5311369Sdduvall /* 5321369Sdduvall * bge_m_start() -- start transmitting/receiving 5331369Sdduvall */ 5341369Sdduvall static int 5351369Sdduvall bge_m_start(void *arg) 5361369Sdduvall { 5371369Sdduvall bge_t *bgep = arg; /* private device info */ 5381369Sdduvall 5391369Sdduvall BGE_TRACE(("bge_m_start($%p)", arg)); 5401369Sdduvall 5411369Sdduvall /* 5421369Sdduvall * Start processing and record new GLD state 5431369Sdduvall */ 5441369Sdduvall mutex_enter(bgep->genlock); 5451865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 5461865Sdilpreet /* can happen during autorecovery */ 5471865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5481865Sdilpreet mutex_exit(bgep->genlock); 5491865Sdilpreet return (EIO); 5501865Sdilpreet } 5511408Srandyf #ifdef BGE_IPMI_ASF 5521408Srandyf if (bgep->asf_enabled) { 5531408Srandyf if ((bgep->asf_status == ASF_STAT_RUN) && 5544588Sml149210 (bgep->asf_pseudostop)) { 5551408Srandyf bgep->bge_mac_state = BGE_MAC_STARTED; 5561408Srandyf mutex_exit(bgep->genlock); 5571408Srandyf return (0); 5581408Srandyf } 5591408Srandyf } 5601865Sdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 5611408Srandyf #else 5621865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 5631408Srandyf #endif 5641865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5651865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5661865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5671865Sdilpreet mutex_exit(bgep->genlock); 5681865Sdilpreet return (EIO); 5691865Sdilpreet } 5701865Sdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) { 5711865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 5721865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 5731865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5741865Sdilpreet mutex_exit(bgep->genlock); 5751865Sdilpreet return (EIO); 5761865Sdilpreet } 5771369Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 5781369Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 5791408Srandyf 5801865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 5811865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5821865Sdilpreet mutex_exit(bgep->genlock); 5831865Sdilpreet return (EIO); 5841865Sdilpreet } 5851865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 5861865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 5871865Sdilpreet mutex_exit(bgep->genlock); 5881865Sdilpreet return (EIO); 5891865Sdilpreet } 5901408Srandyf #ifdef BGE_IPMI_ASF 5911408Srandyf if (bgep->asf_enabled) { 5921408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 5931408Srandyf /* start ASF heart beat */ 5941408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 5954588Sml149210 (void *)bgep, 5964588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 5971408Srandyf bgep->asf_status = ASF_STAT_RUN; 5981408Srandyf } 5991408Srandyf } 6001408Srandyf #endif 6011369Sdduvall mutex_exit(bgep->genlock); 6021369Sdduvall 6031369Sdduvall return (0); 6041369Sdduvall } 6051369Sdduvall 6061369Sdduvall /* 6072331Skrgopi * bge_m_unicst() -- set the physical network address 6081369Sdduvall */ 6091369Sdduvall static int 6101369Sdduvall bge_m_unicst(void *arg, const uint8_t *macaddr) 6111369Sdduvall { 6122331Skrgopi /* 6132331Skrgopi * Request to set address in 6142331Skrgopi * address slot 0, i.e., default address 6152331Skrgopi */ 6162331Skrgopi return (bge_unicst_set(arg, macaddr, 0)); 6172331Skrgopi } 6182331Skrgopi 6192331Skrgopi /* 6202331Skrgopi * bge_unicst_set() -- set the physical network address 6212331Skrgopi */ 6222331Skrgopi static int 6232331Skrgopi bge_unicst_set(void *arg, const uint8_t *macaddr, mac_addr_slot_t slot) 6242331Skrgopi { 6251369Sdduvall bge_t *bgep = arg; /* private device info */ 6261369Sdduvall 6271369Sdduvall BGE_TRACE(("bge_m_unicst_set($%p, %s)", arg, 6284588Sml149210 ether_sprintf((void *)macaddr))); 6291369Sdduvall /* 6301369Sdduvall * Remember the new current address in the driver state 6311369Sdduvall * Sync the chip's idea of the address too ... 6321369Sdduvall */ 6331369Sdduvall mutex_enter(bgep->genlock); 6341865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 6351865Sdilpreet /* can happen during autorecovery */ 6361865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6371865Sdilpreet mutex_exit(bgep->genlock); 6381865Sdilpreet return (EIO); 6391865Sdilpreet } 6402331Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr); 6411408Srandyf #ifdef BGE_IPMI_ASF 6421865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 6431865Sdilpreet #else 6441865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6451865Sdilpreet #endif 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, DDI_SERVICE_DEGRADED); 6491865Sdilpreet mutex_exit(bgep->genlock); 6501865Sdilpreet return (EIO); 6511865Sdilpreet } 6521865Sdilpreet #ifdef BGE_IPMI_ASF 6531408Srandyf if (bgep->asf_enabled) { 6541408Srandyf /* 6551408Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 6561408Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 6571408Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 6581408Srandyf */ 6591408Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 6601408Srandyf /* 6611408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 6621408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 6631408Srandyf * may crash. 6641408Srandyf */ 6651408Srandyf bge_asf_update_status(bgep); 6661408Srandyf bge_asf_stop_timer(bgep); 6671408Srandyf bgep->asf_status = ASF_STAT_STOP; 6681408Srandyf 6691408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 6701408Srandyf } 6711865Sdilpreet bge_chip_stop(bgep, B_FALSE); 6721408Srandyf 6731865Sdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 6741865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 6751865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 6761865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 6771865Sdilpreet DDI_SERVICE_DEGRADED); 6781865Sdilpreet mutex_exit(bgep->genlock); 6791865Sdilpreet return (EIO); 6801865Sdilpreet } 6811865Sdilpreet 6821408Srandyf /* 6831408Srandyf * Start our ASF heartbeat counter as soon as possible. 6841408Srandyf */ 6851408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 6861408Srandyf /* start ASF heart beat */ 6871408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 6884588Sml149210 (void *)bgep, 6894588Sml149210 drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 6901408Srandyf bgep->asf_status = ASF_STAT_RUN; 6911408Srandyf } 6921408Srandyf } 6931408Srandyf #endif 6941369Sdduvall BGE_DEBUG(("bge_m_unicst_set($%p) done", arg)); 6951865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 6961865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 6971865Sdilpreet mutex_exit(bgep->genlock); 6981865Sdilpreet return (EIO); 6991865Sdilpreet } 7001865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 7011865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 7021865Sdilpreet mutex_exit(bgep->genlock); 7031865Sdilpreet return (EIO); 7041865Sdilpreet } 7051369Sdduvall mutex_exit(bgep->genlock); 7061369Sdduvall 7071369Sdduvall return (0); 7081369Sdduvall } 7091369Sdduvall 7101369Sdduvall /* 7112331Skrgopi * The following four routines are used as callbacks for multiple MAC 7122331Skrgopi * address support: 7132331Skrgopi * - bge_m_unicst_add(void *, mac_multi_addr_t *); 7142331Skrgopi * - bge_m_unicst_remove(void *, mac_addr_slot_t); 7152331Skrgopi * - bge_m_unicst_modify(void *, mac_multi_addr_t *); 7162331Skrgopi * - bge_m_unicst_get(void *, mac_multi_addr_t *); 7172331Skrgopi */ 7182331Skrgopi 7192331Skrgopi /* 7202331Skrgopi * bge_m_unicst_add() - will find an unused address slot, set the 7212331Skrgopi * address value to the one specified, reserve that slot and enable 7222331Skrgopi * the NIC to start filtering on the new MAC address. 7232331Skrgopi * address slot. Returns 0 on success. 7242331Skrgopi */ 7252331Skrgopi static int 7262331Skrgopi bge_m_unicst_add(void *arg, mac_multi_addr_t *maddr) 7272331Skrgopi { 7282331Skrgopi bge_t *bgep = arg; /* private device info */ 7292331Skrgopi mac_addr_slot_t slot; 7302406Skrgopi int err; 7312331Skrgopi 7322331Skrgopi if (mac_unicst_verify(bgep->mh, 7332331Skrgopi maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 7342331Skrgopi return (EINVAL); 7352331Skrgopi 7362331Skrgopi mutex_enter(bgep->genlock); 7372331Skrgopi if (bgep->unicst_addr_avail == 0) { 7382331Skrgopi /* no slots available */ 7392331Skrgopi mutex_exit(bgep->genlock); 7402331Skrgopi return (ENOSPC); 7412331Skrgopi } 7422331Skrgopi 7432331Skrgopi /* 7442331Skrgopi * Primary/default address is in slot 0. The next three 7452331Skrgopi * addresses are the multiple MAC addresses. So multiple 7462331Skrgopi * MAC address 0 is in slot 1, 1 in slot 2, and so on. 7472406Skrgopi * So the first multiple MAC address resides in slot 1. 7482331Skrgopi */ 7492406Skrgopi for (slot = 1; slot < bgep->unicst_addr_total; slot++) { 7502406Skrgopi if (bgep->curr_addr[slot].set == B_FALSE) { 7512406Skrgopi bgep->curr_addr[slot].set = B_TRUE; 7522331Skrgopi break; 7532331Skrgopi } 7542331Skrgopi } 7552331Skrgopi 7562406Skrgopi ASSERT(slot < bgep->unicst_addr_total); 7572331Skrgopi bgep->unicst_addr_avail--; 7582331Skrgopi mutex_exit(bgep->genlock); 7592331Skrgopi maddr->mma_slot = slot; 7602331Skrgopi 7612331Skrgopi if ((err = bge_unicst_set(bgep, maddr->mma_addr, slot)) != 0) { 7622331Skrgopi mutex_enter(bgep->genlock); 7632406Skrgopi bgep->curr_addr[slot].set = B_FALSE; 7642331Skrgopi bgep->unicst_addr_avail++; 7652331Skrgopi mutex_exit(bgep->genlock); 7662331Skrgopi } 7672331Skrgopi return (err); 7682331Skrgopi } 7692331Skrgopi 7702331Skrgopi /* 7712331Skrgopi * bge_m_unicst_remove() - removes a MAC address that was added by a 7722331Skrgopi * call to bge_m_unicst_add(). The slot number that was returned in 7732331Skrgopi * add() is passed in the call to remove the address. 7742331Skrgopi * Returns 0 on success. 7752331Skrgopi */ 7762331Skrgopi static int 7772331Skrgopi bge_m_unicst_remove(void *arg, mac_addr_slot_t slot) 7782331Skrgopi { 7792331Skrgopi bge_t *bgep = arg; /* private device info */ 7802331Skrgopi 7812406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 7822406Skrgopi return (EINVAL); 7832406Skrgopi 7842331Skrgopi mutex_enter(bgep->genlock); 7852406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 7862406Skrgopi bgep->curr_addr[slot].set = B_FALSE; 7872331Skrgopi bgep->unicst_addr_avail++; 7882331Skrgopi mutex_exit(bgep->genlock); 7892331Skrgopi /* 7902331Skrgopi * Copy the default address to the passed slot 7912331Skrgopi */ 7922406Skrgopi return (bge_unicst_set(bgep, bgep->curr_addr[0].addr, slot)); 7932331Skrgopi } 7942331Skrgopi mutex_exit(bgep->genlock); 7952331Skrgopi return (EINVAL); 7962331Skrgopi } 7972331Skrgopi 7982331Skrgopi /* 7992331Skrgopi * bge_m_unicst_modify() - modifies the value of an address that 8002331Skrgopi * has been added by bge_m_unicst_add(). The new address, address 8012331Skrgopi * length and the slot number that was returned in the call to add 8022331Skrgopi * should be passed to bge_m_unicst_modify(). mma_flags should be 8032331Skrgopi * set to 0. Returns 0 on success. 8042331Skrgopi */ 8052331Skrgopi static int 8062331Skrgopi bge_m_unicst_modify(void *arg, mac_multi_addr_t *maddr) 8072331Skrgopi { 8082331Skrgopi bge_t *bgep = arg; /* private device info */ 8092331Skrgopi mac_addr_slot_t slot; 8102331Skrgopi 8112331Skrgopi if (mac_unicst_verify(bgep->mh, 8122331Skrgopi maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 8132331Skrgopi return (EINVAL); 8142331Skrgopi 8152331Skrgopi slot = maddr->mma_slot; 8162331Skrgopi 8172406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 8182406Skrgopi return (EINVAL); 8192406Skrgopi 8202331Skrgopi mutex_enter(bgep->genlock); 8212406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 8222331Skrgopi mutex_exit(bgep->genlock); 8232331Skrgopi return (bge_unicst_set(bgep, maddr->mma_addr, slot)); 8242331Skrgopi } 8252331Skrgopi mutex_exit(bgep->genlock); 8262331Skrgopi 8272331Skrgopi return (EINVAL); 8282331Skrgopi } 8292331Skrgopi 8302331Skrgopi /* 8312331Skrgopi * bge_m_unicst_get() - will get the MAC address and all other 8322331Skrgopi * information related to the address slot passed in mac_multi_addr_t. 8332331Skrgopi * mma_flags should be set to 0 in the call. 8342331Skrgopi * On return, mma_flags can take the following values: 8352331Skrgopi * 1) MMAC_SLOT_UNUSED 8362331Skrgopi * 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR 8372331Skrgopi * 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR 8382331Skrgopi * 4) MMAC_SLOT_USED 8392331Skrgopi */ 8402331Skrgopi static int 8412331Skrgopi bge_m_unicst_get(void *arg, mac_multi_addr_t *maddr) 8422331Skrgopi { 8432331Skrgopi bge_t *bgep = arg; /* private device info */ 8442331Skrgopi mac_addr_slot_t slot; 8452331Skrgopi 8462331Skrgopi slot = maddr->mma_slot; 8472331Skrgopi 8482406Skrgopi if (slot <= 0 || slot >= bgep->unicst_addr_total) 8492331Skrgopi return (EINVAL); 8502331Skrgopi 8512331Skrgopi mutex_enter(bgep->genlock); 8522406Skrgopi if (bgep->curr_addr[slot].set == B_TRUE) { 8532406Skrgopi ethaddr_copy(bgep->curr_addr[slot].addr, 8542331Skrgopi maddr->mma_addr); 8552331Skrgopi maddr->mma_flags = MMAC_SLOT_USED; 8562331Skrgopi } else { 8572331Skrgopi maddr->mma_flags = MMAC_SLOT_UNUSED; 8582331Skrgopi } 8592331Skrgopi mutex_exit(bgep->genlock); 8602331Skrgopi 8612331Skrgopi return (0); 8622331Skrgopi } 8632331Skrgopi 8645903Ssowmini extern void bge_wake_factotum(bge_t *); 8655903Ssowmini 8665903Ssowmini static boolean_t 8675903Ssowmini bge_param_locked(mac_prop_id_t pr_num) 8685903Ssowmini { 8695903Ssowmini /* 8705903Ssowmini * All adv_* parameters are locked (read-only) while 8715903Ssowmini * the device is in any sort of loopback mode ... 8725903Ssowmini */ 8735903Ssowmini switch (pr_num) { 8745903Ssowmini case DLD_PROP_ADV_1000FDX_CAP: 8755903Ssowmini case DLD_PROP_EN_1000FDX_CAP: 8765903Ssowmini case DLD_PROP_ADV_1000HDX_CAP: 8775903Ssowmini case DLD_PROP_EN_1000HDX_CAP: 8785903Ssowmini case DLD_PROP_ADV_100FDX_CAP: 8795903Ssowmini case DLD_PROP_EN_100FDX_CAP: 8805903Ssowmini case DLD_PROP_ADV_100HDX_CAP: 8815903Ssowmini case DLD_PROP_EN_100HDX_CAP: 8825903Ssowmini case DLD_PROP_ADV_10FDX_CAP: 8835903Ssowmini case DLD_PROP_EN_10FDX_CAP: 8845903Ssowmini case DLD_PROP_ADV_10HDX_CAP: 8855903Ssowmini case DLD_PROP_EN_10HDX_CAP: 8865903Ssowmini case DLD_PROP_AUTONEG: 8875903Ssowmini case DLD_PROP_FLOWCTRL: 8885903Ssowmini return (B_TRUE); 8895903Ssowmini } 8905903Ssowmini return (B_FALSE); 8915903Ssowmini } 8925903Ssowmini /* 8935903Ssowmini * callback functions for set/get of properties 8945903Ssowmini */ 8955903Ssowmini static int 8965903Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 8975903Ssowmini uint_t pr_valsize, const void *pr_val) 8985903Ssowmini { 8995903Ssowmini bge_t *bgep = barg; 9005903Ssowmini int err = 0; 9016512Ssowmini uint32_t cur_mtu, new_mtu; 9025903Ssowmini uint_t maxsdu; 9035903Ssowmini link_flowctrl_t fl; 9045903Ssowmini 9055903Ssowmini mutex_enter(bgep->genlock); 9065903Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE && 9075903Ssowmini bge_param_locked(pr_num)) { 9085903Ssowmini /* 9095903Ssowmini * All adv_* parameters are locked (read-only) 9105903Ssowmini * while the device is in any sort of loopback mode. 9115903Ssowmini */ 9125903Ssowmini mutex_exit(bgep->genlock); 9135903Ssowmini return (EBUSY); 9145903Ssowmini } 9156512Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) && 9166512Ssowmini ((pr_num == DLD_PROP_EN_100FDX_CAP) || 9176512Ssowmini (pr_num == DLD_PROP_EN_100FDX_CAP) || 9186512Ssowmini (pr_num == DLD_PROP_EN_10FDX_CAP) || 9196512Ssowmini (pr_num == DLD_PROP_EN_10HDX_CAP))) { 9206512Ssowmini /* 9216512Ssowmini * these properties are read/write on copper, 9226512Ssowmini * read-only and 0 on serdes 9236512Ssowmini */ 9246512Ssowmini mutex_exit(bgep->genlock); 9256512Ssowmini return (ENOTSUP); 9266512Ssowmini } 9276512Ssowmini 9285903Ssowmini switch (pr_num) { 9295903Ssowmini case DLD_PROP_EN_1000FDX_CAP: 9305903Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val; 9315903Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val; 9325903Ssowmini goto reprogram; 9335903Ssowmini case DLD_PROP_EN_1000HDX_CAP: 9345903Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val; 9355903Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val; 9365903Ssowmini goto reprogram; 9375903Ssowmini case DLD_PROP_EN_100FDX_CAP: 9385903Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val; 9395903Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val; 9405903Ssowmini goto reprogram; 9415903Ssowmini case DLD_PROP_EN_100HDX_CAP: 9425903Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val; 9435903Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val; 9445903Ssowmini goto reprogram; 9455903Ssowmini case DLD_PROP_EN_10FDX_CAP: 9465903Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val; 9475903Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val; 9485903Ssowmini goto reprogram; 9495903Ssowmini case DLD_PROP_EN_10HDX_CAP: 9505903Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val; 9515903Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val; 9525903Ssowmini reprogram: 9535903Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) 9545903Ssowmini err = EINVAL; 9555903Ssowmini break; 9565903Ssowmini case DLD_PROP_ADV_1000FDX_CAP: 9575903Ssowmini case DLD_PROP_ADV_1000HDX_CAP: 9585903Ssowmini case DLD_PROP_ADV_100FDX_CAP: 9595903Ssowmini case DLD_PROP_ADV_100HDX_CAP: 9605903Ssowmini case DLD_PROP_ADV_10FDX_CAP: 9615903Ssowmini case DLD_PROP_ADV_10HDX_CAP: 9625903Ssowmini case DLD_PROP_STATUS: 9635903Ssowmini case DLD_PROP_SPEED: 9645903Ssowmini case DLD_PROP_DUPLEX: 9656512Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */ 9665903Ssowmini break; 9675903Ssowmini case DLD_PROP_AUTONEG: 9685903Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val; 9695903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 9705903Ssowmini err = EINVAL; 9715903Ssowmini break; 9726512Ssowmini case DLD_PROP_MTU: 9735903Ssowmini cur_mtu = bgep->chipid.default_mtu; 9745903Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 9756512Ssowmini 9765903Ssowmini if (new_mtu == cur_mtu) { 9775903Ssowmini err = 0; 9785903Ssowmini break; 9795903Ssowmini } 9805903Ssowmini if (new_mtu < BGE_DEFAULT_MTU || 9815903Ssowmini new_mtu > BGE_MAXIMUM_MTU) { 9825903Ssowmini err = EINVAL; 9835903Ssowmini break; 9845903Ssowmini } 9855903Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) && 9865903Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { 9875903Ssowmini err = EINVAL; 9885903Ssowmini break; 9895903Ssowmini } 9905903Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) { 9915903Ssowmini err = EBUSY; 9925903Ssowmini break; 9935903Ssowmini } 9945903Ssowmini bgep->chipid.default_mtu = new_mtu; 9955903Ssowmini if (bge_chip_id_init(bgep)) { 9965903Ssowmini err = EINVAL; 9975903Ssowmini break; 9985903Ssowmini } 9995903Ssowmini maxsdu = bgep->chipid.ethmax_size - 10005903Ssowmini sizeof (struct ether_header); 10015903Ssowmini err = mac_maxsdu_update(bgep->mh, maxsdu); 10025903Ssowmini if (err == 0) { 10035903Ssowmini bgep->bge_dma_error = B_TRUE; 10045903Ssowmini bgep->manual_reset = B_TRUE; 10055903Ssowmini bge_chip_stop(bgep, B_TRUE); 10065903Ssowmini bge_wake_factotum(bgep); 10075903Ssowmini err = 0; 10085903Ssowmini } 10095903Ssowmini break; 10105903Ssowmini case DLD_PROP_FLOWCTRL: 10115903Ssowmini bcopy(pr_val, &fl, sizeof (fl)); 10125903Ssowmini switch (fl) { 10135903Ssowmini default: 10146512Ssowmini err = ENOTSUP; 10155903Ssowmini break; 10165903Ssowmini case LINK_FLOWCTRL_NONE: 10175903Ssowmini bgep->param_adv_pause = 0; 10185903Ssowmini bgep->param_adv_asym_pause = 0; 10195903Ssowmini 10205903Ssowmini bgep->param_link_rx_pause = B_FALSE; 10215903Ssowmini bgep->param_link_tx_pause = B_FALSE; 10225903Ssowmini break; 10235903Ssowmini case LINK_FLOWCTRL_RX: 10245903Ssowmini if (!((bgep->param_lp_pause == 0) && 10255903Ssowmini (bgep->param_lp_asym_pause == 1))) { 10265903Ssowmini err = EINVAL; 10275903Ssowmini break; 10285903Ssowmini } 10295903Ssowmini bgep->param_adv_pause = 1; 10305903Ssowmini bgep->param_adv_asym_pause = 1; 10315903Ssowmini 10325903Ssowmini bgep->param_link_rx_pause = B_TRUE; 10335903Ssowmini bgep->param_link_tx_pause = B_FALSE; 10345903Ssowmini break; 10355903Ssowmini case LINK_FLOWCTRL_TX: 10365903Ssowmini if (!((bgep->param_lp_pause == 1) && 10375903Ssowmini (bgep->param_lp_asym_pause == 1))) { 10385903Ssowmini err = EINVAL; 10395903Ssowmini break; 10405903Ssowmini } 10415903Ssowmini bgep->param_adv_pause = 0; 10425903Ssowmini bgep->param_adv_asym_pause = 1; 10435903Ssowmini 10445903Ssowmini bgep->param_link_rx_pause = B_FALSE; 10455903Ssowmini bgep->param_link_tx_pause = B_TRUE; 10465903Ssowmini break; 10475903Ssowmini case LINK_FLOWCTRL_BI: 10485903Ssowmini if (bgep->param_lp_pause != 1) { 10495903Ssowmini err = EINVAL; 10505903Ssowmini break; 10515903Ssowmini } 10525903Ssowmini bgep->param_adv_pause = 1; 10535903Ssowmini 10545903Ssowmini bgep->param_link_rx_pause = B_TRUE; 10555903Ssowmini bgep->param_link_tx_pause = B_TRUE; 10565903Ssowmini break; 10575903Ssowmini } 10585903Ssowmini 10595903Ssowmini if (err == 0) { 10605903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 10615903Ssowmini err = EINVAL; 10625903Ssowmini } 10635903Ssowmini 10645903Ssowmini break; 10656512Ssowmini case DLD_PROP_PRIVATE: 10665903Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize, 10675903Ssowmini pr_val); 10685903Ssowmini break; 10696512Ssowmini default: 10706512Ssowmini err = ENOTSUP; 10716512Ssowmini break; 10725903Ssowmini } 10735903Ssowmini mutex_exit(bgep->genlock); 10745903Ssowmini return (err); 10755903Ssowmini } 10766512Ssowmini 10775903Ssowmini static int 10785903Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 10796512Ssowmini uint_t pr_flags, uint_t pr_valsize, void *pr_val) 10805903Ssowmini { 10815903Ssowmini bge_t *bgep = barg; 10825903Ssowmini int err = 0; 10835903Ssowmini link_flowctrl_t fl; 10846512Ssowmini uint64_t speed; 10856512Ssowmini int flags = bgep->chipid.flags; 10866512Ssowmini boolean_t is_default = (pr_flags & DLD_DEFAULT); 10876512Ssowmini 10886512Ssowmini if (pr_valsize == 0) 10896512Ssowmini return (EINVAL); 10905903Ssowmini bzero(pr_val, pr_valsize); 10915903Ssowmini switch (pr_num) { 10925903Ssowmini case DLD_PROP_DUPLEX: 10936512Ssowmini if (pr_valsize < sizeof (link_duplex_t)) 10945903Ssowmini return (EINVAL); 10956512Ssowmini bcopy(&bgep->param_link_duplex, pr_val, 10966512Ssowmini sizeof (link_duplex_t)); 10975903Ssowmini break; 10985903Ssowmini case DLD_PROP_SPEED: 10996512Ssowmini if (pr_valsize < sizeof (speed)) 11005903Ssowmini return (EINVAL); 11016512Ssowmini speed = bgep->param_link_speed * 1000000ull; 11026512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 11035903Ssowmini break; 11045903Ssowmini case DLD_PROP_STATUS: 11056512Ssowmini if (pr_valsize < sizeof (link_state_t)) 11065903Ssowmini return (EINVAL); 11076512Ssowmini bcopy(&bgep->link_state, pr_val, 11086512Ssowmini sizeof (link_state_t)); 11095903Ssowmini break; 11105903Ssowmini case DLD_PROP_AUTONEG: 11116512Ssowmini if (is_default) 11126512Ssowmini *(uint8_t *)pr_val = 1; 11136512Ssowmini else 11146512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg; 11155903Ssowmini break; 11166512Ssowmini case DLD_PROP_FLOWCTRL: 11176512Ssowmini if (pr_valsize < sizeof (fl)) 11185903Ssowmini return (EINVAL); 11196512Ssowmini if (is_default) { 11206512Ssowmini fl = LINK_FLOWCTRL_BI; 11216512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 11226512Ssowmini break; 11236512Ssowmini } 11246512Ssowmini 11255903Ssowmini if (bgep->param_link_rx_pause && 11265903Ssowmini !bgep->param_link_tx_pause) 11275903Ssowmini fl = LINK_FLOWCTRL_RX; 11285903Ssowmini 11295903Ssowmini if (!bgep->param_link_rx_pause && 11305903Ssowmini !bgep->param_link_tx_pause) 11315903Ssowmini fl = LINK_FLOWCTRL_NONE; 11325903Ssowmini 11335903Ssowmini if (!bgep->param_link_rx_pause && 11345903Ssowmini bgep->param_link_tx_pause) 11355903Ssowmini fl = LINK_FLOWCTRL_TX; 11365903Ssowmini 11375903Ssowmini if (bgep->param_link_rx_pause && 11385903Ssowmini bgep->param_link_tx_pause) 11395903Ssowmini fl = LINK_FLOWCTRL_BI; 11405903Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 11415903Ssowmini break; 11425903Ssowmini case DLD_PROP_ADV_1000FDX_CAP: 11436512Ssowmini if (is_default) 11446512Ssowmini *(uint8_t *)pr_val = 1; 11456512Ssowmini else 11466512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx; 11475903Ssowmini break; 11485903Ssowmini case DLD_PROP_EN_1000FDX_CAP: 11496512Ssowmini if (is_default) 11506512Ssowmini *(uint8_t *)pr_val = 1; 11516512Ssowmini else 11526512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx; 11535903Ssowmini break; 11545903Ssowmini case DLD_PROP_ADV_1000HDX_CAP: 11556512Ssowmini if (is_default) 11566512Ssowmini *(uint8_t *)pr_val = 1; 11576512Ssowmini else 11586512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx; 11595903Ssowmini break; 11605903Ssowmini case DLD_PROP_EN_1000HDX_CAP: 11616512Ssowmini if (is_default) 11626512Ssowmini *(uint8_t *)pr_val = 1; 11636512Ssowmini else 11646512Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx; 11655903Ssowmini break; 11665903Ssowmini case DLD_PROP_ADV_100FDX_CAP: 11676512Ssowmini if (is_default) { 11686512Ssowmini *(uint8_t *)pr_val = 11696512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11706512Ssowmini } else { 11716512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx; 11726512Ssowmini } 11735903Ssowmini break; 11745903Ssowmini case DLD_PROP_EN_100FDX_CAP: 11756512Ssowmini if (is_default) { 11766512Ssowmini *(uint8_t *)pr_val = 11776512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11786512Ssowmini } else { 11796512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx; 11806512Ssowmini } 11815903Ssowmini break; 11825903Ssowmini case DLD_PROP_ADV_100HDX_CAP: 11836512Ssowmini if (is_default) { 11846512Ssowmini *(uint8_t *)pr_val = 11856512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11866512Ssowmini } else { 11876512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx; 11886512Ssowmini } 11895903Ssowmini break; 11905903Ssowmini case DLD_PROP_EN_100HDX_CAP: 11916512Ssowmini if (is_default) { 11926512Ssowmini *(uint8_t *)pr_val = 11936512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 11946512Ssowmini } else { 11956512Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx; 11966512Ssowmini } 11975903Ssowmini break; 11985903Ssowmini case DLD_PROP_ADV_10FDX_CAP: 11996512Ssowmini if (is_default) { 12006512Ssowmini *(uint8_t *)pr_val = 12016512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12026512Ssowmini } else { 12036512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx; 12046512Ssowmini } 12055903Ssowmini break; 12065903Ssowmini case DLD_PROP_EN_10FDX_CAP: 12076512Ssowmini if (is_default) { 12086512Ssowmini *(uint8_t *)pr_val = 12096512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12106512Ssowmini } else { 12116512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx; 12126512Ssowmini } 12135903Ssowmini break; 12145903Ssowmini case DLD_PROP_ADV_10HDX_CAP: 12156512Ssowmini if (is_default) { 12166512Ssowmini *(uint8_t *)pr_val = 12176512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12186512Ssowmini } else { 12196512Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx; 12206512Ssowmini } 12215903Ssowmini break; 12225903Ssowmini case DLD_PROP_EN_10HDX_CAP: 12236512Ssowmini if (is_default) { 12246512Ssowmini *(uint8_t *)pr_val = 12256512Ssowmini ((flags & CHIP_FLAG_SERDES) ? 0 : 1); 12266512Ssowmini } else { 12276512Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx; 12286512Ssowmini } 12295903Ssowmini break; 12306512Ssowmini case DLD_PROP_ADV_100T4_CAP: 12316512Ssowmini case DLD_PROP_EN_100T4_CAP: 12326512Ssowmini *(uint8_t *)pr_val = 0; 12336512Ssowmini break; 12346512Ssowmini case DLD_PROP_PRIVATE: 12356512Ssowmini err = bge_get_priv_prop(bgep, pr_name, pr_flags, 12366512Ssowmini pr_valsize, pr_val); 12376512Ssowmini return (err); 12385903Ssowmini default: 12396512Ssowmini return (ENOTSUP); 12405903Ssowmini } 12415903Ssowmini return (0); 12425903Ssowmini } 12435903Ssowmini 12445903Ssowmini /* ARGSUSED */ 12455903Ssowmini static int 12465903Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, 12475903Ssowmini const void *pr_val) 12485903Ssowmini { 12495903Ssowmini int err = 0; 12505903Ssowmini long result; 12515903Ssowmini 12526512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 12536512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12546512Ssowmini if (result > 1 || result < 0) { 12556512Ssowmini err = EINVAL; 12566512Ssowmini } else { 12576512Ssowmini bgep->param_adv_pause = result; 12586512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12596512Ssowmini err = EINVAL; 12606512Ssowmini } 12616512Ssowmini return (err); 12626512Ssowmini } 12636512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 12646512Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12656512Ssowmini if (result > 1 || result < 0) { 12666512Ssowmini err = EINVAL; 12676512Ssowmini } else { 12686512Ssowmini bgep->param_adv_asym_pause = result; 12696512Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12706512Ssowmini err = EINVAL; 12716512Ssowmini } 12726512Ssowmini return (err); 12736512Ssowmini } 12745903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 12755903Ssowmini 12765903Ssowmini /* 12775903Ssowmini * on the Tx side, we need to update the h/w register for 12785903Ssowmini * real packet transmission per packet. The drain_max parameter 12795903Ssowmini * is used to reduce the register access. This parameter 12805903Ssowmini * controls the max number of packets that we will hold before 12815903Ssowmini * updating the bge h/w to trigger h/w transmit. The bge 12825903Ssowmini * chipset usually has a max of 512 Tx descriptors, thus 12835903Ssowmini * the upper bound on drain_max is 512. 12845903Ssowmini */ 12855903Ssowmini if (pr_val == NULL) { 12865903Ssowmini err = EINVAL; 12875903Ssowmini return (err); 12885903Ssowmini } 12895903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 12905903Ssowmini if (result > 512 || result < 1) 12915903Ssowmini err = EINVAL; 12925903Ssowmini else { 12935903Ssowmini bgep->param_drain_max = (uint32_t)result; 12945903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 12955903Ssowmini err = EINVAL; 12965903Ssowmini } 12975903Ssowmini return (err); 12985903Ssowmini } 12995903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 13005903Ssowmini 13015903Ssowmini if (pr_val == NULL) { 13025903Ssowmini err = EINVAL; 13035903Ssowmini return (err); 13045903Ssowmini } 13055903Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 13065903Ssowmini if (result > 7 || result < 0) 13075903Ssowmini err = EINVAL; 13085903Ssowmini else { 13095903Ssowmini bgep->param_msi_cnt = (uint32_t)result; 13105903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 13115903Ssowmini err = EINVAL; 13125903Ssowmini } 13135903Ssowmini return (err); 13145903Ssowmini } 13155903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 13166512Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 13175903Ssowmini return (EINVAL); 13185903Ssowmini 13195903Ssowmini bgep->chipid.rx_ticks_norm = result; 13205903Ssowmini return (0); 13215903Ssowmini } 13225903Ssowmini 13235903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 13245903Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) 13255903Ssowmini return (EINVAL); 13265903Ssowmini 13275903Ssowmini bgep->chipid.rx_count_norm = result; 13285903Ssowmini return (0); 13295903Ssowmini } 13306512Ssowmini return (ENOTSUP); 13315903Ssowmini } 13325903Ssowmini 13335903Ssowmini static int 13346512Ssowmini bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_flags, 13356512Ssowmini uint_t pr_valsize, void *pr_val) 13365903Ssowmini { 13376512Ssowmini int err = ENOTSUP; 13386512Ssowmini boolean_t is_default = (pr_flags & DLD_DEFAULT); 13396512Ssowmini int value; 13406512Ssowmini 13416512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 13426512Ssowmini value = (is_default? 1 : bge->param_adv_pause); 13436512Ssowmini err = 0; 13446512Ssowmini goto done; 13456512Ssowmini } 13466512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 13476512Ssowmini value = (is_default? 1 : bge->param_adv_asym_pause); 13486512Ssowmini err = 0; 13496512Ssowmini goto done; 13506512Ssowmini } 13515903Ssowmini if (strcmp(pr_name, "_drain_max") == 0) { 13526512Ssowmini value = (is_default? 64 : bge->param_drain_max); 13535903Ssowmini err = 0; 13545903Ssowmini goto done; 13555903Ssowmini } 13565903Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) { 13576512Ssowmini value = (is_default? 0 : bge->param_msi_cnt); 13585903Ssowmini err = 0; 13595903Ssowmini goto done; 13605903Ssowmini } 13615903Ssowmini 13625903Ssowmini if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { 13636512Ssowmini value = (is_default? bge_rx_ticks_norm : 13646512Ssowmini bge->chipid.rx_ticks_norm); 13655903Ssowmini err = 0; 13665903Ssowmini goto done; 13675903Ssowmini } 13685903Ssowmini 13695903Ssowmini if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { 13706512Ssowmini value = (is_default? bge_rx_count_norm : 13716512Ssowmini bge->chipid.rx_count_norm); 13725903Ssowmini err = 0; 13735903Ssowmini goto done; 13745903Ssowmini } 13755903Ssowmini 13765903Ssowmini done: 13776512Ssowmini if (err == 0) { 13786512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 13795903Ssowmini } 13805903Ssowmini return (err); 13815903Ssowmini } 13825903Ssowmini 13832331Skrgopi /* 13841369Sdduvall * Compute the index of the required bit in the multicast hash map. 13851369Sdduvall * This must mirror the way the hardware actually does it! 13861369Sdduvall * See Broadcom document 570X-PG102-R page 125. 13871369Sdduvall */ 13881369Sdduvall static uint32_t 13891369Sdduvall bge_hash_index(const uint8_t *mca) 13901369Sdduvall { 13911369Sdduvall uint32_t hash; 13921369Sdduvall 13931369Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 13941369Sdduvall 13951369Sdduvall return (hash); 13961369Sdduvall } 13971369Sdduvall 13981369Sdduvall /* 13991369Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 14001369Sdduvall */ 14011369Sdduvall static int 14021369Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 14031369Sdduvall { 14041369Sdduvall bge_t *bgep = arg; /* private device info */ 14051369Sdduvall uint32_t hash; 14061369Sdduvall uint32_t index; 14071369Sdduvall uint32_t word; 14081369Sdduvall uint32_t bit; 14091369Sdduvall uint8_t *refp; 14101369Sdduvall 14111369Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 14124588Sml149210 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 14131369Sdduvall 14141369Sdduvall /* 14151369Sdduvall * Precalculate all required masks, pointers etc ... 14161369Sdduvall */ 14171369Sdduvall hash = bge_hash_index(mca); 14181369Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 14191369Sdduvall word = index/32u; 14201369Sdduvall bit = 1 << (index % 32u); 14211369Sdduvall refp = &bgep->mcast_refs[index]; 14221369Sdduvall 14231369Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 14244588Sml149210 hash, index, word, bit, *refp)); 14251369Sdduvall 14261369Sdduvall /* 14271369Sdduvall * We must set the appropriate bit in the hash map (and the 14281369Sdduvall * corresponding h/w register) when the refcount goes from 0 14291369Sdduvall * to >0, and clear it when the last ref goes away (refcount 14301369Sdduvall * goes from >0 back to 0). If we change the hash map, we 14311369Sdduvall * must also update the chip's hardware map registers. 14321369Sdduvall */ 14331369Sdduvall mutex_enter(bgep->genlock); 14341865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 14351865Sdilpreet /* can happen during autorecovery */ 14361865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14371865Sdilpreet mutex_exit(bgep->genlock); 14381865Sdilpreet return (EIO); 14391865Sdilpreet } 14401369Sdduvall if (add) { 14411369Sdduvall if ((*refp)++ == 0) { 14421369Sdduvall bgep->mcast_hash[word] |= bit; 14431408Srandyf #ifdef BGE_IPMI_ASF 14441865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 14451408Srandyf #else 14461865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 14471408Srandyf #endif 14481865Sdilpreet (void) bge_check_acc_handle(bgep, 14491865Sdilpreet bgep->cfg_handle); 14501865Sdilpreet (void) bge_check_acc_handle(bgep, 14511865Sdilpreet bgep->io_handle); 14521865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 14531865Sdilpreet DDI_SERVICE_DEGRADED); 14541865Sdilpreet mutex_exit(bgep->genlock); 14551865Sdilpreet return (EIO); 14561865Sdilpreet } 14571369Sdduvall } 14581369Sdduvall } else { 14591369Sdduvall if (--(*refp) == 0) { 14601369Sdduvall bgep->mcast_hash[word] &= ~bit; 14611408Srandyf #ifdef BGE_IPMI_ASF 14621865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 14631408Srandyf #else 14641865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 14651408Srandyf #endif 14661865Sdilpreet (void) bge_check_acc_handle(bgep, 14671865Sdilpreet bgep->cfg_handle); 14681865Sdilpreet (void) bge_check_acc_handle(bgep, 14691865Sdilpreet bgep->io_handle); 14701865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 14711865Sdilpreet DDI_SERVICE_DEGRADED); 14721865Sdilpreet mutex_exit(bgep->genlock); 14731865Sdilpreet return (EIO); 14741865Sdilpreet } 14751369Sdduvall } 14761369Sdduvall } 14771369Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 14781865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 14791865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14801865Sdilpreet mutex_exit(bgep->genlock); 14811865Sdilpreet return (EIO); 14821865Sdilpreet } 14831865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 14841865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 14851865Sdilpreet mutex_exit(bgep->genlock); 14861865Sdilpreet return (EIO); 14871865Sdilpreet } 14881369Sdduvall mutex_exit(bgep->genlock); 14891369Sdduvall 14901369Sdduvall return (0); 14911369Sdduvall } 14921369Sdduvall 14931369Sdduvall /* 14941369Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 14951369Sdduvall * 14961369Sdduvall * Program the hardware to enable/disable promiscuous and/or 14971369Sdduvall * receive-all-multicast modes. 14981369Sdduvall */ 14991369Sdduvall static int 15001369Sdduvall bge_m_promisc(void *arg, boolean_t on) 15011369Sdduvall { 15021369Sdduvall bge_t *bgep = arg; 15031369Sdduvall 15041369Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 15051369Sdduvall 15061369Sdduvall /* 15071369Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 15081369Sdduvall */ 15091369Sdduvall mutex_enter(bgep->genlock); 15101865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 15111865Sdilpreet /* can happen during autorecovery */ 15121865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15131865Sdilpreet mutex_exit(bgep->genlock); 15141865Sdilpreet return (EIO); 15151865Sdilpreet } 15161369Sdduvall bgep->promisc = on; 15171408Srandyf #ifdef BGE_IPMI_ASF 15181865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 15191408Srandyf #else 15201865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 15211408Srandyf #endif 15221865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 15231865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 15241865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15251865Sdilpreet mutex_exit(bgep->genlock); 15261865Sdilpreet return (EIO); 15271865Sdilpreet } 15281369Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 15291865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 15301865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15311865Sdilpreet mutex_exit(bgep->genlock); 15321865Sdilpreet return (EIO); 15331865Sdilpreet } 15341865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 15351865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 15361865Sdilpreet mutex_exit(bgep->genlock); 15371865Sdilpreet return (EIO); 15381865Sdilpreet } 15391369Sdduvall mutex_exit(bgep->genlock); 15401369Sdduvall return (0); 15411369Sdduvall } 15421369Sdduvall 15432311Sseb /*ARGSUSED*/ 15442311Sseb static boolean_t 15452311Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 15462311Sseb { 15472331Skrgopi bge_t *bgep = arg; 15482331Skrgopi 15492311Sseb switch (cap) { 15502311Sseb case MAC_CAPAB_HCKSUM: { 15512311Sseb uint32_t *txflags = cap_data; 15522311Sseb 15532311Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 15542311Sseb break; 15552311Sseb } 15562331Skrgopi 15572311Sseb case MAC_CAPAB_POLL: 15582311Sseb /* 15592311Sseb * There's nothing for us to fill in, simply returning 15602311Sseb * B_TRUE stating that we support polling is sufficient. 15612311Sseb */ 15622311Sseb break; 15632331Skrgopi 15642331Skrgopi case MAC_CAPAB_MULTIADDRESS: { 15652331Skrgopi multiaddress_capab_t *mmacp = cap_data; 15662331Skrgopi 15672331Skrgopi mutex_enter(bgep->genlock); 15682406Skrgopi /* 15692406Skrgopi * The number of MAC addresses made available by 15702406Skrgopi * this capability is one less than the total as 15712406Skrgopi * the primary address in slot 0 is counted in 15722406Skrgopi * the total. 15732406Skrgopi */ 15742406Skrgopi mmacp->maddr_naddr = bgep->unicst_addr_total - 1; 15752331Skrgopi mmacp->maddr_naddrfree = bgep->unicst_addr_avail; 15762331Skrgopi /* No multiple factory addresses, set mma_flag to 0 */ 15772331Skrgopi mmacp->maddr_flag = 0; 15782331Skrgopi mmacp->maddr_handle = bgep; 15792331Skrgopi mmacp->maddr_add = bge_m_unicst_add; 15802331Skrgopi mmacp->maddr_remove = bge_m_unicst_remove; 15812331Skrgopi mmacp->maddr_modify = bge_m_unicst_modify; 15822331Skrgopi mmacp->maddr_get = bge_m_unicst_get; 15832331Skrgopi mmacp->maddr_reserve = NULL; 15842331Skrgopi mutex_exit(bgep->genlock); 15852331Skrgopi break; 15862331Skrgopi } 15872331Skrgopi 15882311Sseb default: 15892311Sseb return (B_FALSE); 15902311Sseb } 15912311Sseb return (B_TRUE); 15922311Sseb } 15932311Sseb 15941369Sdduvall /* 15951369Sdduvall * Loopback ioctl code 15961369Sdduvall */ 15971369Sdduvall 15981369Sdduvall static lb_property_t loopmodes[] = { 15991369Sdduvall { normal, "normal", BGE_LOOP_NONE }, 16001369Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 16011369Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 16021369Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 16031369Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 16041369Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 16051369Sdduvall }; 16061369Sdduvall 16071369Sdduvall static enum ioc_reply 16081369Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 16091369Sdduvall { 16101369Sdduvall /* 16111369Sdduvall * If the mode isn't being changed, there's nothing to do ... 16121369Sdduvall */ 16131369Sdduvall if (mode == bgep->param_loop_mode) 16141369Sdduvall return (IOC_ACK); 16151369Sdduvall 16161369Sdduvall /* 16171369Sdduvall * Validate the requested mode and prepare a suitable message 16181369Sdduvall * to explain the link down/up cycle that the change will 16191369Sdduvall * probably induce ... 16201369Sdduvall */ 16211369Sdduvall switch (mode) { 16221369Sdduvall default: 16231369Sdduvall return (IOC_INVAL); 16241369Sdduvall 16251369Sdduvall case BGE_LOOP_NONE: 16261369Sdduvall case BGE_LOOP_EXTERNAL_1000: 16271369Sdduvall case BGE_LOOP_EXTERNAL_100: 16281369Sdduvall case BGE_LOOP_EXTERNAL_10: 16291369Sdduvall case BGE_LOOP_INTERNAL_PHY: 16301369Sdduvall case BGE_LOOP_INTERNAL_MAC: 16311369Sdduvall break; 16321369Sdduvall } 16331369Sdduvall 16341369Sdduvall /* 16351369Sdduvall * All OK; tell the caller to reprogram 16361369Sdduvall * the PHY and/or MAC for the new mode ... 16371369Sdduvall */ 16381369Sdduvall bgep->param_loop_mode = mode; 16391369Sdduvall return (IOC_RESTART_ACK); 16401369Sdduvall } 16411369Sdduvall 16421369Sdduvall static enum ioc_reply 16431369Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 16441369Sdduvall { 16451369Sdduvall lb_info_sz_t *lbsp; 16461369Sdduvall lb_property_t *lbpp; 16471369Sdduvall uint32_t *lbmp; 16481369Sdduvall int cmd; 16491369Sdduvall 16501369Sdduvall _NOTE(ARGUNUSED(wq)) 16511369Sdduvall 16521369Sdduvall /* 16531369Sdduvall * Validate format of ioctl 16541369Sdduvall */ 16551369Sdduvall if (mp->b_cont == NULL) 16561369Sdduvall return (IOC_INVAL); 16571369Sdduvall 16581369Sdduvall cmd = iocp->ioc_cmd; 16591369Sdduvall switch (cmd) { 16601369Sdduvall default: 16611369Sdduvall /* NOTREACHED */ 16621369Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 16631369Sdduvall return (IOC_INVAL); 16641369Sdduvall 16651369Sdduvall case LB_GET_INFO_SIZE: 16661369Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 16671369Sdduvall return (IOC_INVAL); 16681369Sdduvall lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 16691369Sdduvall *lbsp = sizeof (loopmodes); 16701369Sdduvall return (IOC_REPLY); 16711369Sdduvall 16721369Sdduvall case LB_GET_INFO: 16731369Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 16741369Sdduvall return (IOC_INVAL); 16751369Sdduvall lbpp = (lb_property_t *)mp->b_cont->b_rptr; 16761369Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 16771369Sdduvall return (IOC_REPLY); 16781369Sdduvall 16791369Sdduvall case LB_GET_MODE: 16801369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 16811369Sdduvall return (IOC_INVAL); 16821369Sdduvall lbmp = (uint32_t *)mp->b_cont->b_rptr; 16831369Sdduvall *lbmp = bgep->param_loop_mode; 16841369Sdduvall return (IOC_REPLY); 16851369Sdduvall 16861369Sdduvall case LB_SET_MODE: 16871369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 16881369Sdduvall return (IOC_INVAL); 16891369Sdduvall lbmp = (uint32_t *)mp->b_cont->b_rptr; 16901369Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 16911369Sdduvall } 16921369Sdduvall } 16931369Sdduvall 16941369Sdduvall /* 16951369Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 16961369Sdduvall */ 16971369Sdduvall static void 16981369Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 16991369Sdduvall { 17001369Sdduvall bge_t *bgep = arg; 17011369Sdduvall struct iocblk *iocp; 17021369Sdduvall enum ioc_reply status; 17031369Sdduvall boolean_t need_privilege; 17041369Sdduvall int err; 17051369Sdduvall int cmd; 17061369Sdduvall 17071369Sdduvall /* 17081369Sdduvall * Validate the command before bothering with the mutex ... 17091369Sdduvall */ 17101369Sdduvall iocp = (struct iocblk *)mp->b_rptr; 17111369Sdduvall iocp->ioc_error = 0; 17121369Sdduvall need_privilege = B_TRUE; 17131369Sdduvall cmd = iocp->ioc_cmd; 17141369Sdduvall switch (cmd) { 17151369Sdduvall default: 17161369Sdduvall miocnak(wq, mp, 0, EINVAL); 17171369Sdduvall return; 17181369Sdduvall 17191369Sdduvall case BGE_MII_READ: 17201369Sdduvall case BGE_MII_WRITE: 17211369Sdduvall case BGE_SEE_READ: 17221369Sdduvall case BGE_SEE_WRITE: 17232675Szh199473 case BGE_FLASH_READ: 17242675Szh199473 case BGE_FLASH_WRITE: 17251369Sdduvall case BGE_DIAG: 17261369Sdduvall case BGE_PEEK: 17271369Sdduvall case BGE_POKE: 17281369Sdduvall case BGE_PHY_RESET: 17291369Sdduvall case BGE_SOFT_RESET: 17301369Sdduvall case BGE_HARD_RESET: 17311369Sdduvall break; 17321369Sdduvall 17331369Sdduvall case LB_GET_INFO_SIZE: 17341369Sdduvall case LB_GET_INFO: 17351369Sdduvall case LB_GET_MODE: 17361369Sdduvall need_privilege = B_FALSE; 17371369Sdduvall /* FALLTHRU */ 17381369Sdduvall case LB_SET_MODE: 17391369Sdduvall break; 17401369Sdduvall 17411369Sdduvall } 17421369Sdduvall 17431369Sdduvall if (need_privilege) { 17441369Sdduvall /* 17451369Sdduvall * Check for specific net_config privilege on Solaris 10+. 17461369Sdduvall */ 17472681Sgs150176 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 17481369Sdduvall if (err != 0) { 17491369Sdduvall miocnak(wq, mp, 0, err); 17501369Sdduvall return; 17511369Sdduvall } 17521369Sdduvall } 17531369Sdduvall 17541369Sdduvall mutex_enter(bgep->genlock); 17551865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 17561865Sdilpreet /* can happen during autorecovery */ 17571865Sdilpreet mutex_exit(bgep->genlock); 17581865Sdilpreet miocnak(wq, mp, 0, EIO); 17591865Sdilpreet return; 17601865Sdilpreet } 17611369Sdduvall 17621369Sdduvall switch (cmd) { 17631369Sdduvall default: 17641369Sdduvall _NOTE(NOTREACHED) 17651369Sdduvall status = IOC_INVAL; 17661369Sdduvall break; 17671369Sdduvall 17681369Sdduvall case BGE_MII_READ: 17691369Sdduvall case BGE_MII_WRITE: 17701369Sdduvall case BGE_SEE_READ: 17711369Sdduvall case BGE_SEE_WRITE: 17722675Szh199473 case BGE_FLASH_READ: 17732675Szh199473 case BGE_FLASH_WRITE: 17741369Sdduvall case BGE_DIAG: 17751369Sdduvall case BGE_PEEK: 17761369Sdduvall case BGE_POKE: 17771369Sdduvall case BGE_PHY_RESET: 17781369Sdduvall case BGE_SOFT_RESET: 17791369Sdduvall case BGE_HARD_RESET: 17801369Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 17811369Sdduvall break; 17821369Sdduvall 17831369Sdduvall case LB_GET_INFO_SIZE: 17841369Sdduvall case LB_GET_INFO: 17851369Sdduvall case LB_GET_MODE: 17861369Sdduvall case LB_SET_MODE: 17871369Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 17881369Sdduvall break; 17891369Sdduvall 17901369Sdduvall } 17911369Sdduvall 17921369Sdduvall /* 17931369Sdduvall * Do we need to reprogram the PHY and/or the MAC? 17941369Sdduvall * Do it now, while we still have the mutex. 17951369Sdduvall * 17961369Sdduvall * Note: update the PHY first, 'cos it controls the 17971369Sdduvall * speed/duplex parameters that the MAC code uses. 17981369Sdduvall */ 17991369Sdduvall switch (status) { 18001369Sdduvall case IOC_RESTART_REPLY: 18011369Sdduvall case IOC_RESTART_ACK: 18025903Ssowmini if (bge_reprogram(bgep) == IOC_INVAL) 18031865Sdilpreet status = IOC_INVAL; 18041369Sdduvall break; 18051369Sdduvall } 18061369Sdduvall 18071865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 18081865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 18091865Sdilpreet status = IOC_INVAL; 18101865Sdilpreet } 18111865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 18121865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 18131865Sdilpreet status = IOC_INVAL; 18141865Sdilpreet } 18151369Sdduvall mutex_exit(bgep->genlock); 18161369Sdduvall 18171369Sdduvall /* 18181369Sdduvall * Finally, decide how to reply 18191369Sdduvall */ 18201369Sdduvall switch (status) { 18211369Sdduvall default: 18221369Sdduvall case IOC_INVAL: 18231369Sdduvall /* 18241369Sdduvall * Error, reply with a NAK and EINVAL or the specified error 18251369Sdduvall */ 18261369Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 18274588Sml149210 EINVAL : iocp->ioc_error); 18281369Sdduvall break; 18291369Sdduvall 18301369Sdduvall case IOC_DONE: 18311369Sdduvall /* 18321369Sdduvall * OK, reply already sent 18331369Sdduvall */ 18341369Sdduvall break; 18351369Sdduvall 18361369Sdduvall case IOC_RESTART_ACK: 18371369Sdduvall case IOC_ACK: 18381369Sdduvall /* 18391369Sdduvall * OK, reply with an ACK 18401369Sdduvall */ 18411369Sdduvall miocack(wq, mp, 0, 0); 18421369Sdduvall break; 18431369Sdduvall 18441369Sdduvall case IOC_RESTART_REPLY: 18451369Sdduvall case IOC_REPLY: 18461369Sdduvall /* 18471369Sdduvall * OK, send prepared reply as ACK or NAK 18481369Sdduvall */ 18491369Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 18504588Sml149210 M_IOCACK : M_IOCNAK; 18511369Sdduvall qreply(wq, mp); 18521369Sdduvall break; 18531369Sdduvall } 18541369Sdduvall } 18551369Sdduvall 18561369Sdduvall static void 18575903Ssowmini bge_resources_add(bge_t *bgep, time_t time, uint_t pkt_cnt) 18581369Sdduvall { 18595903Ssowmini 18601369Sdduvall recv_ring_t *rrp; 18611369Sdduvall mac_rx_fifo_t mrf; 18621369Sdduvall int ring; 18631369Sdduvall 18641369Sdduvall /* 18651369Sdduvall * Register Rx rings as resources and save mac 18661369Sdduvall * resource id for future reference 18671369Sdduvall */ 18681369Sdduvall mrf.mrf_type = MAC_RX_FIFO; 18691369Sdduvall mrf.mrf_blank = bge_chip_blank; 18701369Sdduvall mrf.mrf_arg = (void *)bgep; 18715903Ssowmini mrf.mrf_normal_blank_time = time; 18725903Ssowmini mrf.mrf_normal_pkt_count = pkt_cnt; 18731369Sdduvall 18741369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ring++) { 18751369Sdduvall rrp = &bgep->recv[ring]; 18762311Sseb rrp->handle = mac_resource_add(bgep->mh, 18771369Sdduvall (mac_resource_t *)&mrf); 18781369Sdduvall } 18795903Ssowmini } 18805903Ssowmini 18815903Ssowmini static void 18825903Ssowmini bge_m_resources(void *arg) 18835903Ssowmini { 18845903Ssowmini bge_t *bgep = arg; 18855903Ssowmini 18865903Ssowmini mutex_enter(bgep->genlock); 18875903Ssowmini 18885903Ssowmini bge_resources_add(bgep, bgep->chipid.rx_ticks_norm, 18895903Ssowmini bgep->chipid.rx_count_norm); 18901369Sdduvall mutex_exit(bgep->genlock); 18911369Sdduvall } 18921369Sdduvall 18931369Sdduvall /* 18941369Sdduvall * ========== Per-instance setup/teardown code ========== 18951369Sdduvall */ 18961369Sdduvall 18971369Sdduvall #undef BGE_DBG 18981369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 18993334Sgs150176 /* 19003334Sgs150176 * Allocate an area of memory and a DMA handle for accessing it 19013334Sgs150176 */ 19023334Sgs150176 static int 19033334Sgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 19043334Sgs150176 uint_t dma_flags, dma_area_t *dma_p) 19053334Sgs150176 { 19063334Sgs150176 caddr_t va; 19073334Sgs150176 int err; 19083334Sgs150176 19093334Sgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 19104588Sml149210 (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 19113334Sgs150176 19123334Sgs150176 /* 19133334Sgs150176 * Allocate handle 19143334Sgs150176 */ 19153334Sgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 19164588Sml149210 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 19173334Sgs150176 if (err != DDI_SUCCESS) 19183334Sgs150176 return (DDI_FAILURE); 19193334Sgs150176 19203334Sgs150176 /* 19213334Sgs150176 * Allocate memory 19223334Sgs150176 */ 19233334Sgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 19244588Sml149210 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, 19254588Sml149210 &dma_p->acc_hdl); 19263334Sgs150176 if (err != DDI_SUCCESS) 19273334Sgs150176 return (DDI_FAILURE); 19283334Sgs150176 19293334Sgs150176 /* 19303334Sgs150176 * Bind the two together 19313334Sgs150176 */ 19323334Sgs150176 dma_p->mem_va = va; 19333334Sgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 19344588Sml149210 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 19354588Sml149210 &dma_p->cookie, &dma_p->ncookies); 19363334Sgs150176 19373334Sgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 19384588Sml149210 dma_p->alength, err, dma_p->ncookies)); 19393334Sgs150176 19403334Sgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 19413334Sgs150176 return (DDI_FAILURE); 19423334Sgs150176 19433334Sgs150176 dma_p->nslots = ~0U; 19443334Sgs150176 dma_p->size = ~0U; 19453334Sgs150176 dma_p->token = ~0U; 19463334Sgs150176 dma_p->offset = 0; 19473334Sgs150176 return (DDI_SUCCESS); 19483334Sgs150176 } 19493334Sgs150176 19503334Sgs150176 /* 19513334Sgs150176 * Free one allocated area of DMAable memory 19523334Sgs150176 */ 19533334Sgs150176 static void 19543334Sgs150176 bge_free_dma_mem(dma_area_t *dma_p) 19553334Sgs150176 { 19563334Sgs150176 if (dma_p->dma_hdl != NULL) { 19573334Sgs150176 if (dma_p->ncookies) { 19583334Sgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 19593334Sgs150176 dma_p->ncookies = 0; 19603334Sgs150176 } 19613334Sgs150176 ddi_dma_free_handle(&dma_p->dma_hdl); 19623334Sgs150176 dma_p->dma_hdl = NULL; 19633334Sgs150176 } 19643334Sgs150176 19653334Sgs150176 if (dma_p->acc_hdl != NULL) { 19663334Sgs150176 ddi_dma_mem_free(&dma_p->acc_hdl); 19673334Sgs150176 dma_p->acc_hdl = NULL; 19683334Sgs150176 } 19693334Sgs150176 } 19701369Sdduvall /* 19711369Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 19721369Sdduvall * updating the chunk descriptor accordingly. The size of the slice 19731369Sdduvall * is given by the product of the <qty> and <size> parameters. 19741369Sdduvall */ 19751369Sdduvall static void 19761369Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 19771369Sdduvall uint32_t qty, uint32_t size) 19781369Sdduvall { 19791369Sdduvall static uint32_t sequence = 0xbcd5704a; 19801369Sdduvall size_t totsize; 19811369Sdduvall 19821369Sdduvall totsize = qty*size; 19831369Sdduvall ASSERT(size >= 0); 19841369Sdduvall ASSERT(totsize <= chunk->alength); 19851369Sdduvall 19861369Sdduvall *slice = *chunk; 19871369Sdduvall slice->nslots = qty; 19881369Sdduvall slice->size = size; 19891369Sdduvall slice->alength = totsize; 19901369Sdduvall slice->token = ++sequence; 19911369Sdduvall 19921369Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 19931369Sdduvall chunk->alength -= totsize; 19941369Sdduvall chunk->offset += totsize; 19951369Sdduvall chunk->cookie.dmac_laddress += totsize; 19961369Sdduvall chunk->cookie.dmac_size -= totsize; 19971369Sdduvall } 19981369Sdduvall 19991369Sdduvall /* 20001369Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 20011369Sdduvall * the information in the <dma_area> descriptors that it contains 20021369Sdduvall * to set up all the other fields. This routine should be called 20031369Sdduvall * only once for each ring. 20041369Sdduvall */ 20051369Sdduvall static void 20061369Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 20071369Sdduvall { 20081369Sdduvall buff_ring_t *brp; 20091369Sdduvall bge_status_t *bsp; 20101369Sdduvall sw_rbd_t *srbdp; 20111369Sdduvall dma_area_t pbuf; 20121369Sdduvall uint32_t bufsize; 20131369Sdduvall uint32_t nslots; 20141369Sdduvall uint32_t slot; 20151369Sdduvall uint32_t split; 20161369Sdduvall 20171369Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 20181369Sdduvall NIC_MEM_SHADOW_BUFF_STD, 20191369Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 20201369Sdduvall NIC_MEM_SHADOW_BUFF_MINI 20211369Sdduvall }; 20221369Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 20231369Sdduvall RECV_STD_PROD_INDEX_REG, 20241369Sdduvall RECV_JUMBO_PROD_INDEX_REG, 20251369Sdduvall RECV_MINI_PROD_INDEX_REG 20261369Sdduvall }; 20271369Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 20281369Sdduvall STATUS_STD_BUFF_CONS_INDEX, 20291369Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 20301369Sdduvall STATUS_MINI_BUFF_CONS_INDEX 20311369Sdduvall }; 20321369Sdduvall 20331369Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 20344588Sml149210 (void *)bgep, ring)); 20351369Sdduvall 20361369Sdduvall brp = &bgep->buff[ring]; 20371369Sdduvall nslots = brp->desc.nslots; 20381369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 20391369Sdduvall bufsize = brp->buf[0].size; 20401369Sdduvall 20411369Sdduvall /* 20421369Sdduvall * Set up the copy of the h/w RCB 20431369Sdduvall * 20441369Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 20451369Sdduvall * field holds the number of slots), in a Receive Buffer Ring 20461369Sdduvall * this field indicates the size of each buffer in the ring. 20471369Sdduvall */ 20481369Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 20491369Sdduvall brp->hw_rcb.max_len = bufsize; 20501369Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 20511369Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 20521369Sdduvall 20531369Sdduvall /* 20541369Sdduvall * Other one-off initialisation of per-ring data 20551369Sdduvall */ 20561369Sdduvall brp->bgep = bgep; 20571369Sdduvall bsp = DMA_VPTR(bgep->status_block); 20581369Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 20591369Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 20601369Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 20611369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 20621369Sdduvall 20631369Sdduvall /* 20641369Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 20651369Sdduvall */ 20661369Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 20671369Sdduvall brp->sw_rbds = srbdp; 20681369Sdduvall 20691369Sdduvall /* 20701369Sdduvall * Now initialise each array element once and for all 20711369Sdduvall */ 20721369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 20731369Sdduvall pbuf = brp->buf[split]; 20741369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 20751369Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 20761369Sdduvall ASSERT(pbuf.alength == 0); 20771369Sdduvall } 20781369Sdduvall } 20791369Sdduvall 20801369Sdduvall /* 20811369Sdduvall * Clean up initialisation done above before the memory is freed 20821369Sdduvall */ 20831369Sdduvall static void 20841369Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 20851369Sdduvall { 20861369Sdduvall buff_ring_t *brp; 20871369Sdduvall sw_rbd_t *srbdp; 20881369Sdduvall 20891369Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 20904588Sml149210 (void *)bgep, ring)); 20911369Sdduvall 20921369Sdduvall brp = &bgep->buff[ring]; 20931369Sdduvall srbdp = brp->sw_rbds; 20941369Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 20951369Sdduvall 20961369Sdduvall mutex_destroy(brp->rf_lock); 20971369Sdduvall } 20981369Sdduvall 20991369Sdduvall /* 21001369Sdduvall * Initialise the specified Receive (Return) Ring, using the 21011369Sdduvall * information in the <dma_area> descriptors that it contains 21021369Sdduvall * to set up all the other fields. This routine should be called 21031369Sdduvall * only once for each ring. 21041369Sdduvall */ 21051369Sdduvall static void 21061369Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 21071369Sdduvall { 21081369Sdduvall recv_ring_t *rrp; 21091369Sdduvall bge_status_t *bsp; 21101369Sdduvall uint32_t nslots; 21111369Sdduvall 21121369Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 21134588Sml149210 (void *)bgep, ring)); 21141369Sdduvall 21151369Sdduvall /* 21161369Sdduvall * The chip architecture requires that receive return rings have 21171369Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 21181369Sdduvall */ 21191369Sdduvall rrp = &bgep->recv[ring]; 21201369Sdduvall nslots = rrp->desc.nslots; 21211369Sdduvall ASSERT(nslots == 0 || nslots == 512 || 21224588Sml149210 nslots == 1024 || nslots == 2048); 21231369Sdduvall 21241369Sdduvall /* 21251369Sdduvall * Set up the copy of the h/w RCB 21261369Sdduvall */ 21271369Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 21281369Sdduvall rrp->hw_rcb.max_len = nslots; 21291369Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21301369Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 21311369Sdduvall 21321369Sdduvall /* 21331369Sdduvall * Other one-off initialisation of per-ring data 21341369Sdduvall */ 21351369Sdduvall rrp->bgep = bgep; 21361369Sdduvall bsp = DMA_VPTR(bgep->status_block); 21371369Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 21381369Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 21391369Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 21401369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 21411369Sdduvall } 21421369Sdduvall 21431369Sdduvall 21441369Sdduvall /* 21451369Sdduvall * Clean up initialisation done above before the memory is freed 21461369Sdduvall */ 21471369Sdduvall static void 21481369Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 21491369Sdduvall { 21501369Sdduvall recv_ring_t *rrp; 21511369Sdduvall 21521369Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 21534588Sml149210 (void *)bgep, ring)); 21541369Sdduvall 21551369Sdduvall rrp = &bgep->recv[ring]; 21561369Sdduvall if (rrp->rx_softint) 21571369Sdduvall ddi_remove_softintr(rrp->rx_softint); 21581369Sdduvall mutex_destroy(rrp->rx_lock); 21591369Sdduvall } 21601369Sdduvall 21611369Sdduvall /* 21621369Sdduvall * Initialise the specified Send Ring, using the information in the 21631369Sdduvall * <dma_area> descriptors that it contains to set up all the other 21641369Sdduvall * fields. This routine should be called only once for each ring. 21651369Sdduvall */ 21661369Sdduvall static void 21671369Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 21681369Sdduvall { 21691369Sdduvall send_ring_t *srp; 21701369Sdduvall bge_status_t *bsp; 21711369Sdduvall sw_sbd_t *ssbdp; 21721369Sdduvall dma_area_t desc; 21731369Sdduvall dma_area_t pbuf; 21741369Sdduvall uint32_t nslots; 21751369Sdduvall uint32_t slot; 21761369Sdduvall uint32_t split; 21773334Sgs150176 sw_txbuf_t *txbuf; 21781369Sdduvall 21791369Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 21804588Sml149210 (void *)bgep, ring)); 21811369Sdduvall 21821369Sdduvall /* 21831369Sdduvall * The chip architecture requires that host-based send rings 21841369Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 21851369Sdduvall */ 21861369Sdduvall srp = &bgep->send[ring]; 21871369Sdduvall nslots = srp->desc.nslots; 21881369Sdduvall ASSERT(nslots == 0 || nslots == 512); 21891369Sdduvall 21901369Sdduvall /* 21911369Sdduvall * Set up the copy of the h/w RCB 21921369Sdduvall */ 21931369Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 21941369Sdduvall srp->hw_rcb.max_len = nslots; 21951369Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 21961369Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 21971369Sdduvall 21981369Sdduvall /* 21991369Sdduvall * Other one-off initialisation of per-ring data 22001369Sdduvall */ 22011369Sdduvall srp->bgep = bgep; 22021369Sdduvall bsp = DMA_VPTR(bgep->status_block); 22031369Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 22041369Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 22051369Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 22061369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22073334Sgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER, 22083334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 22093334Sgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER, 22103334Sgs150176 DDI_INTR_PRI(bgep->intr_pri)); 22111369Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 22121369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 22133334Sgs150176 if (nslots == 0) 22143334Sgs150176 return; 22151369Sdduvall 22161369Sdduvall /* 22171369Sdduvall * Allocate the array of s/w Send Buffer Descriptors 22181369Sdduvall */ 22191369Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 22203334Sgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP); 22213334Sgs150176 srp->txbuf_head = 22223334Sgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP); 22233334Sgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP); 22241369Sdduvall srp->sw_sbds = ssbdp; 22253334Sgs150176 srp->txbuf = txbuf; 22263334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 22273334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 22283334Sgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT) 22293334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO; 22303334Sgs150176 else 22313334Sgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY; 22323334Sgs150176 srp->tx_array = 1; 22331369Sdduvall 22341369Sdduvall /* 22353334Sgs150176 * Chunk tx desc area 22361369Sdduvall */ 22371369Sdduvall desc = srp->desc; 22383334Sgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) { 22393334Sgs150176 bge_slice_chunk(&ssbdp->desc, &desc, 1, 22403334Sgs150176 sizeof (bge_sbd_t)); 22413334Sgs150176 } 22423334Sgs150176 ASSERT(desc.alength == 0); 22433334Sgs150176 22443334Sgs150176 /* 22453334Sgs150176 * Chunk tx buffer area 22463334Sgs150176 */ 22471369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 22483334Sgs150176 pbuf = srp->buf[0][split]; 22493334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 22503334Sgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1, 22513334Sgs150176 bgep->chipid.snd_buff_size); 22523334Sgs150176 txbuf++; 22531369Sdduvall } 22541369Sdduvall ASSERT(pbuf.alength == 0); 22551369Sdduvall } 22561369Sdduvall } 22571369Sdduvall 22581369Sdduvall /* 22591369Sdduvall * Clean up initialisation done above before the memory is freed 22601369Sdduvall */ 22611369Sdduvall static void 22621369Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 22631369Sdduvall { 22641369Sdduvall send_ring_t *srp; 22653334Sgs150176 uint32_t array; 22663334Sgs150176 uint32_t split; 22673334Sgs150176 uint32_t nslots; 22681369Sdduvall 22691369Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 22704588Sml149210 (void *)bgep, ring)); 22711369Sdduvall 22721369Sdduvall srp = &bgep->send[ring]; 22733334Sgs150176 mutex_destroy(srp->tc_lock); 22743334Sgs150176 mutex_destroy(srp->freetxbuf_lock); 22753334Sgs150176 mutex_destroy(srp->txbuf_lock); 22761369Sdduvall mutex_destroy(srp->tx_lock); 22773334Sgs150176 nslots = srp->desc.nslots; 22783334Sgs150176 if (nslots == 0) 22793334Sgs150176 return; 22803334Sgs150176 22813334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 22823334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 22833334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 22843334Sgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds)); 22853334Sgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head)); 22863334Sgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf)); 22873334Sgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp)); 22883334Sgs150176 srp->sw_sbds = NULL; 22893334Sgs150176 srp->txbuf_head = NULL; 22903334Sgs150176 srp->txbuf = NULL; 22913334Sgs150176 srp->pktp = NULL; 22921369Sdduvall } 22931369Sdduvall 22941369Sdduvall /* 22951369Sdduvall * Initialise all transmit, receive, and buffer rings. 22961369Sdduvall */ 22971865Sdilpreet void 22981369Sdduvall bge_init_rings(bge_t *bgep) 22991369Sdduvall { 23003334Sgs150176 uint32_t ring; 23011369Sdduvall 23021369Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 23031369Sdduvall 23041369Sdduvall /* 23051369Sdduvall * Perform one-off initialisation of each ring ... 23061369Sdduvall */ 23071369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 23081369Sdduvall bge_init_send_ring(bgep, ring); 23091369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 23101369Sdduvall bge_init_recv_ring(bgep, ring); 23111369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 23121369Sdduvall bge_init_buff_ring(bgep, ring); 23131369Sdduvall } 23141369Sdduvall 23151369Sdduvall /* 23161369Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 23171369Sdduvall */ 23181865Sdilpreet void 23191369Sdduvall bge_fini_rings(bge_t *bgep) 23201369Sdduvall { 23213334Sgs150176 uint32_t ring; 23221369Sdduvall 23231369Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 23241369Sdduvall 23251369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 23261369Sdduvall bge_fini_buff_ring(bgep, ring); 23271369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 23281369Sdduvall bge_fini_recv_ring(bgep, ring); 23291369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 23301369Sdduvall bge_fini_send_ring(bgep, ring); 23311369Sdduvall } 23321369Sdduvall 23331369Sdduvall /* 23343334Sgs150176 * Called from the bge_m_stop() to free the tx buffers which are 23353334Sgs150176 * allocated from the tx process. 23361369Sdduvall */ 23373334Sgs150176 void 23383334Sgs150176 bge_free_txbuf_arrays(send_ring_t *srp) 23391369Sdduvall { 23403334Sgs150176 uint32_t array; 23413334Sgs150176 uint32_t split; 23423334Sgs150176 23433334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 23441369Sdduvall 23451369Sdduvall /* 23463334Sgs150176 * Free the extra tx buffer DMA area 23471369Sdduvall */ 23483334Sgs150176 for (array = 1; array < srp->tx_array; ++array) 23493334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) 23503334Sgs150176 bge_free_dma_mem(&srp->buf[array][split]); 23511369Sdduvall 23521369Sdduvall /* 23533334Sgs150176 * Restore initial tx buffer numbers 23541369Sdduvall */ 23553334Sgs150176 srp->tx_array = 1; 23563334Sgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM; 23573334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 23583334Sgs150176 srp->tx_flow = 0; 23593334Sgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp)); 23601369Sdduvall } 23611369Sdduvall 23621369Sdduvall /* 23633334Sgs150176 * Called from tx process to allocate more tx buffers 23641369Sdduvall */ 23653334Sgs150176 bge_queue_item_t * 23663334Sgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp) 23671369Sdduvall { 23683334Sgs150176 bge_queue_t *txbuf_queue; 23693334Sgs150176 bge_queue_item_t *txbuf_item_last; 23703334Sgs150176 bge_queue_item_t *txbuf_item; 23713334Sgs150176 bge_queue_item_t *txbuf_item_rtn; 23723334Sgs150176 sw_txbuf_t *txbuf; 23733334Sgs150176 dma_area_t area; 23743334Sgs150176 size_t txbuffsize; 23753334Sgs150176 uint32_t slot; 23763334Sgs150176 uint32_t array; 23773334Sgs150176 uint32_t split; 23783334Sgs150176 uint32_t err; 23793334Sgs150176 23803334Sgs150176 ASSERT(mutex_owned(srp->tx_lock)); 23813334Sgs150176 23823334Sgs150176 array = srp->tx_array; 23833334Sgs150176 if (array >= srp->tx_array_max) 23843334Sgs150176 return (NULL); 23853334Sgs150176 23863334Sgs150176 /* 23873334Sgs150176 * Allocate memory & handles for TX buffers 23883334Sgs150176 */ 23893334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 23903334Sgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0); 23913334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 23923334Sgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 23934588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 23944588Sml149210 &srp->buf[array][split]); 23953334Sgs150176 if (err != DDI_SUCCESS) { 23963334Sgs150176 /* Free the last already allocated OK chunks */ 23973334Sgs150176 for (slot = 0; slot <= split; ++slot) 23983334Sgs150176 bge_free_dma_mem(&srp->buf[array][slot]); 23993334Sgs150176 srp->tx_alloc_fail++; 24003334Sgs150176 return (NULL); 24011369Sdduvall } 24023334Sgs150176 } 24033334Sgs150176 24043334Sgs150176 /* 24053334Sgs150176 * Chunk tx buffer area 24063334Sgs150176 */ 24073334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 24083334Sgs150176 for (split = 0; split < BGE_SPLIT; ++split) { 24093334Sgs150176 area = srp->buf[array][split]; 24103334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) { 24113334Sgs150176 bge_slice_chunk(&txbuf->buf, &area, 1, 24123334Sgs150176 bgep->chipid.snd_buff_size); 24133334Sgs150176 txbuf++; 24143334Sgs150176 } 24151369Sdduvall } 24161369Sdduvall 24173334Sgs150176 /* 24183334Sgs150176 * Add above buffers to the tx buffer pop queue 24193334Sgs150176 */ 24203334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 24213334Sgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM; 24223334Sgs150176 txbuf_item_last = NULL; 24233334Sgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) { 24243334Sgs150176 txbuf_item->item = txbuf; 24253334Sgs150176 txbuf_item->next = txbuf_item_last; 24263334Sgs150176 txbuf_item_last = txbuf_item; 24273334Sgs150176 txbuf++; 24283334Sgs150176 txbuf_item++; 24291369Sdduvall } 24303334Sgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM; 24313334Sgs150176 txbuf_item_rtn = txbuf_item; 24323334Sgs150176 txbuf_item++; 24333334Sgs150176 txbuf_queue = srp->txbuf_pop_queue; 24343334Sgs150176 mutex_enter(txbuf_queue->lock); 24353334Sgs150176 txbuf_item->next = txbuf_queue->head; 24363334Sgs150176 txbuf_queue->head = txbuf_item_last; 24373334Sgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1; 24383334Sgs150176 mutex_exit(txbuf_queue->lock); 24393334Sgs150176 24403334Sgs150176 srp->tx_array++; 24413334Sgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM; 24423334Sgs150176 srp->tx_buffers_low = srp->tx_buffers / 4; 24433334Sgs150176 24443334Sgs150176 return (txbuf_item_rtn); 24451369Sdduvall } 24461369Sdduvall 24471369Sdduvall /* 24481369Sdduvall * This function allocates all the transmit and receive buffers 24493334Sgs150176 * and descriptors, in four chunks. 24501369Sdduvall */ 24511865Sdilpreet int 24521369Sdduvall bge_alloc_bufs(bge_t *bgep) 24531369Sdduvall { 24541369Sdduvall dma_area_t area; 24551369Sdduvall size_t rxbuffsize; 24561369Sdduvall size_t txbuffsize; 24571369Sdduvall size_t rxbuffdescsize; 24581369Sdduvall size_t rxdescsize; 24591369Sdduvall size_t txdescsize; 24603334Sgs150176 uint32_t ring; 24613334Sgs150176 uint32_t rx_rings = bgep->chipid.rx_rings; 24623334Sgs150176 uint32_t tx_rings = bgep->chipid.tx_rings; 24631369Sdduvall int split; 24641369Sdduvall int err; 24651369Sdduvall 24661369Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 24674588Sml149210 (void *)bgep)); 24681369Sdduvall 24691908Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size; 24701369Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 24711369Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 24721369Sdduvall 24733334Sgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size; 24741369Sdduvall txbuffsize *= tx_rings; 24751369Sdduvall 24761369Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 24771369Sdduvall rxdescsize *= sizeof (bge_rbd_t); 24781369Sdduvall 24791369Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 24801369Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 24811369Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 24821369Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 24831369Sdduvall 24841369Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 24851369Sdduvall txdescsize *= sizeof (bge_sbd_t); 24861369Sdduvall txdescsize += sizeof (bge_statistics_t); 24871369Sdduvall txdescsize += sizeof (bge_status_t); 24881369Sdduvall txdescsize += BGE_STATUS_PADDING; 24891369Sdduvall 24901369Sdduvall /* 24913907Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers 24923907Szh199473 */ 24933907Szh199473 if (bge_relaxed_ordering) 24943907Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING; 24953907Szh199473 24963907Szh199473 /* 24971369Sdduvall * Allocate memory & handles for RX buffers 24981369Sdduvall */ 24991369Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 25001369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25011369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 25024588Sml149210 &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 25034588Sml149210 &bgep->rx_buff[split]); 25041369Sdduvall if (err != DDI_SUCCESS) 25051369Sdduvall return (DDI_FAILURE); 25061369Sdduvall } 25071369Sdduvall 25081369Sdduvall /* 25091369Sdduvall * Allocate memory & handles for TX buffers 25101369Sdduvall */ 25111369Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 25121369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25131369Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 25144588Sml149210 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 25154588Sml149210 &bgep->tx_buff[split]); 25161369Sdduvall if (err != DDI_SUCCESS) 25171369Sdduvall return (DDI_FAILURE); 25181369Sdduvall } 25191369Sdduvall 25203907Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING; 25213907Szh199473 25221369Sdduvall /* 25231369Sdduvall * Allocate memory & handles for receive return rings 25241369Sdduvall */ 25251369Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 25261369Sdduvall for (split = 0; split < rx_rings; ++split) { 25271369Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 25284588Sml149210 &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 25294588Sml149210 &bgep->rx_desc[split]); 25301369Sdduvall if (err != DDI_SUCCESS) 25311369Sdduvall return (DDI_FAILURE); 25321369Sdduvall } 25331369Sdduvall 25341369Sdduvall /* 25351369Sdduvall * Allocate memory & handles for buffer (producer) descriptor rings 25361369Sdduvall */ 25371369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 25384588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 25391369Sdduvall if (err != DDI_SUCCESS) 25401369Sdduvall return (DDI_FAILURE); 25411369Sdduvall 25421369Sdduvall /* 25431369Sdduvall * Allocate memory & handles for TX descriptor rings, 25441369Sdduvall * status block, and statistics area 25451369Sdduvall */ 25461369Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 25474588Sml149210 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 25481369Sdduvall if (err != DDI_SUCCESS) 25491369Sdduvall return (DDI_FAILURE); 25501369Sdduvall 25511369Sdduvall /* 25521369Sdduvall * Now carve up each of the allocated areas ... 25531369Sdduvall */ 25541369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25551369Sdduvall area = bgep->rx_buff[split]; 25561369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 25574588Sml149210 &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 25584588Sml149210 bgep->chipid.std_buf_size); 25591369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 25604588Sml149210 &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 25614588Sml149210 bgep->chipid.recv_jumbo_size); 25621369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 25634588Sml149210 &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 25644588Sml149210 BGE_MINI_BUFF_SIZE); 25651369Sdduvall ASSERT(area.alength >= 0); 25661369Sdduvall } 25671369Sdduvall 25681369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 25691369Sdduvall area = bgep->tx_buff[split]; 25701369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 25713334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 25724588Sml149210 &area, BGE_SEND_BUF_NUM/BGE_SPLIT, 25734588Sml149210 bgep->chipid.snd_buff_size); 25741369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 25753334Sgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split], 25764588Sml149210 &area, 0, bgep->chipid.snd_buff_size); 25771369Sdduvall ASSERT(area.alength >= 0); 25781369Sdduvall } 25791369Sdduvall 25801369Sdduvall for (ring = 0; ring < rx_rings; ++ring) 25811369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 25824588Sml149210 bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 25831369Sdduvall 25841369Sdduvall area = bgep->rx_desc[rx_rings]; 25851369Sdduvall for (; ring < BGE_RECV_RINGS_MAX; ++ring) 25861369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 25874588Sml149210 0, sizeof (bge_rbd_t)); 25881369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 25894588Sml149210 BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 25901369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 25914588Sml149210 bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 25921369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 25934588Sml149210 BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 25941369Sdduvall ASSERT(area.alength == 0); 25951369Sdduvall 25961369Sdduvall area = bgep->tx_desc; 25971369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 25981369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 25994588Sml149210 BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 26001369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 26011369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 26024588Sml149210 0, sizeof (bge_sbd_t)); 26031369Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 26041369Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 26051369Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 26061369Sdduvall DMA_ZERO(bgep->status_block); 26071369Sdduvall 26081369Sdduvall return (DDI_SUCCESS); 26091369Sdduvall } 26101369Sdduvall 26111369Sdduvall /* 26121369Sdduvall * This routine frees the transmit and receive buffers and descriptors. 26131369Sdduvall * Make sure the chip is stopped before calling it! 26141369Sdduvall */ 26151865Sdilpreet void 26161369Sdduvall bge_free_bufs(bge_t *bgep) 26171369Sdduvall { 26181369Sdduvall int split; 26191369Sdduvall 26201369Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 26214588Sml149210 (void *)bgep)); 26221369Sdduvall 26231369Sdduvall bge_free_dma_mem(&bgep->tx_desc); 26241369Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 26251369Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 26261369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 26271369Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 26281369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 26291369Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 26301369Sdduvall } 26311369Sdduvall 26321369Sdduvall /* 26331369Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 26341369Sdduvall */ 26351369Sdduvall 26361369Sdduvall static void 26371369Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 26381369Sdduvall { 26391369Sdduvall struct ether_addr sysaddr; 26401369Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 26411369Sdduvall uchar_t *bytes; 26421369Sdduvall int *ints; 26431369Sdduvall uint_t nelts; 26441369Sdduvall int err; 26451369Sdduvall 26461369Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 26474588Sml149210 (void *)bgep)); 26481369Sdduvall 26491369Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 26504588Sml149210 cidp->hw_mac_addr, 26514588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 26524588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 26531369Sdduvall 26541369Sdduvall /* 26551369Sdduvall * The "vendor's factory-set address" may already have 26561369Sdduvall * been extracted from the chip, but if the property 26571369Sdduvall * "local-mac-address" is set we use that instead. It 26581369Sdduvall * will normally be set by OBP, but it could also be 26591369Sdduvall * specified in a .conf file(!) 26601369Sdduvall * 26611369Sdduvall * There doesn't seem to be a way to define byte-array 26621369Sdduvall * properties in a .conf, so we check whether it looks 26631369Sdduvall * like an array of 6 ints instead. 26641369Sdduvall * 26651369Sdduvall * Then, we check whether it looks like an array of 6 26661369Sdduvall * bytes (which it should, if OBP set it). If we can't 26671369Sdduvall * make sense of it either way, we'll ignore it. 26681369Sdduvall */ 26691369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 26704588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 26711369Sdduvall if (err == DDI_PROP_SUCCESS) { 26721369Sdduvall if (nelts == ETHERADDRL) { 26731369Sdduvall while (nelts--) 26741369Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 26752331Skrgopi cidp->vendor_addr.set = B_TRUE; 26761369Sdduvall } 26771369Sdduvall ddi_prop_free(ints); 26781369Sdduvall } 26791369Sdduvall 26801369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 26814588Sml149210 DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 26821369Sdduvall if (err == DDI_PROP_SUCCESS) { 26831369Sdduvall if (nelts == ETHERADDRL) { 26841369Sdduvall while (nelts--) 26851369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 26862331Skrgopi cidp->vendor_addr.set = B_TRUE; 26871369Sdduvall } 26881369Sdduvall ddi_prop_free(bytes); 26891369Sdduvall } 26901369Sdduvall 26911369Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 26924588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 26934588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 26941369Sdduvall 26951369Sdduvall /* 26961369Sdduvall * Look up the OBP property "local-mac-address?". Note that even 26971369Sdduvall * though its value is a string (which should be "true" or "false"), 26981369Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 26991369Sdduvall * the buffer first and then fetch the property as an untyped array; 27001369Sdduvall * this may or may not include a final NUL, but since there will 27011369Sdduvall * always be one left at the end of the buffer we can now treat it 27021369Sdduvall * as a string anyway. 27031369Sdduvall */ 27041369Sdduvall nelts = sizeof (propbuf); 27051369Sdduvall bzero(propbuf, nelts--); 27061369Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 27074588Sml149210 DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 27081369Sdduvall 27091369Sdduvall /* 27101369Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 27111369Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 27121369Sdduvall * 'local-mac-address? = false', use "the system address" instead 27131369Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 27141369Sdduvall */ 27152331Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0) 27161369Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 27171369Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 27182331Skrgopi cidp->vendor_addr.set = B_TRUE; 27191369Sdduvall } 27201369Sdduvall 27211369Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 27224588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27234588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27241369Sdduvall 27251369Sdduvall /* 27261369Sdduvall * Finally(!), if there's a valid "mac-address" property (created 27271369Sdduvall * if we netbooted from this interface), we must use this instead 27281369Sdduvall * of any of the above to ensure that the NFS/install server doesn't 27291369Sdduvall * get confused by the address changing as Solaris takes over! 27301369Sdduvall */ 27311369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 27324588Sml149210 DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 27331369Sdduvall if (err == DDI_PROP_SUCCESS) { 27341369Sdduvall if (nelts == ETHERADDRL) { 27351369Sdduvall while (nelts--) 27361369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 27372331Skrgopi cidp->vendor_addr.set = B_TRUE; 27381369Sdduvall } 27391369Sdduvall ddi_prop_free(bytes); 27401369Sdduvall } 27411369Sdduvall 27421369Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 27434588Sml149210 ether_sprintf((void *)cidp->vendor_addr.addr), 27444588Sml149210 cidp->vendor_addr.set ? "" : "not ")); 27451369Sdduvall } 27461369Sdduvall 27471865Sdilpreet 27481865Sdilpreet /*ARGSUSED*/ 27491865Sdilpreet int 27501865Sdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 27511865Sdilpreet { 27521865Sdilpreet ddi_fm_error_t de; 27531865Sdilpreet 27541865Sdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 27551865Sdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 27561865Sdilpreet return (de.fme_status); 27571865Sdilpreet } 27581865Sdilpreet 27591865Sdilpreet /*ARGSUSED*/ 27601865Sdilpreet int 27611865Sdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 27621865Sdilpreet { 27631865Sdilpreet ddi_fm_error_t de; 27641865Sdilpreet 27651865Sdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 27661865Sdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 27671865Sdilpreet return (de.fme_status); 27681865Sdilpreet } 27691865Sdilpreet 27701865Sdilpreet /* 27711865Sdilpreet * The IO fault service error handling callback function 27721865Sdilpreet */ 27731865Sdilpreet /*ARGSUSED*/ 27741865Sdilpreet static int 27751865Sdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 27761865Sdilpreet { 27771865Sdilpreet /* 27781865Sdilpreet * as the driver can always deal with an error in any dma or 27791865Sdilpreet * access handle, we can just return the fme_status value. 27801865Sdilpreet */ 27811865Sdilpreet pci_ereport_post(dip, err, NULL); 27821865Sdilpreet return (err->fme_status); 27831865Sdilpreet } 27841865Sdilpreet 27851865Sdilpreet static void 27861865Sdilpreet bge_fm_init(bge_t *bgep) 27871865Sdilpreet { 27881865Sdilpreet ddi_iblock_cookie_t iblk; 27891865Sdilpreet 27901865Sdilpreet /* Only register with IO Fault Services if we have some capability */ 27911865Sdilpreet if (bgep->fm_capabilities) { 27921865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 27931865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 27941865Sdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 27951865Sdilpreet 27961865Sdilpreet /* Register capabilities with IO Fault Services */ 27971865Sdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 27981865Sdilpreet 27991865Sdilpreet /* 28001865Sdilpreet * Initialize pci ereport capabilities if ereport capable 28011865Sdilpreet */ 28021865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 28031865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28041865Sdilpreet pci_ereport_setup(bgep->devinfo); 28051865Sdilpreet 28061865Sdilpreet /* 28071865Sdilpreet * Register error callback if error callback capable 28081865Sdilpreet */ 28091865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28101865Sdilpreet ddi_fm_handler_register(bgep->devinfo, 28114588Sml149210 bge_fm_error_cb, (void*) bgep); 28121865Sdilpreet } else { 28131865Sdilpreet /* 28141865Sdilpreet * These fields have to be cleared of FMA if there are no 28151865Sdilpreet * FMA capabilities at runtime. 28161865Sdilpreet */ 28171865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 28181865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 28191865Sdilpreet dma_attr.dma_attr_flags = 0; 28201865Sdilpreet } 28211865Sdilpreet } 28221865Sdilpreet 28231865Sdilpreet static void 28241865Sdilpreet bge_fm_fini(bge_t *bgep) 28251865Sdilpreet { 28261865Sdilpreet /* Only unregister FMA capabilities if we registered some */ 28271865Sdilpreet if (bgep->fm_capabilities) { 28281865Sdilpreet 28291865Sdilpreet /* 28301865Sdilpreet * Release any resources allocated by pci_ereport_setup() 28311865Sdilpreet */ 28321865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 28331865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28341865Sdilpreet pci_ereport_teardown(bgep->devinfo); 28351865Sdilpreet 28361865Sdilpreet /* 28371865Sdilpreet * Un-register error callback if error callback capable 28381865Sdilpreet */ 28391865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 28401865Sdilpreet ddi_fm_handler_unregister(bgep->devinfo); 28411865Sdilpreet 28421865Sdilpreet /* Unregister from IO Fault Services */ 28431865Sdilpreet ddi_fm_fini(bgep->devinfo); 28441865Sdilpreet } 28451865Sdilpreet } 28461865Sdilpreet 28471369Sdduvall static void 28481408Srandyf #ifdef BGE_IPMI_ASF 28491408Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 28501408Srandyf #else 28511369Sdduvall bge_unattach(bge_t *bgep) 28521408Srandyf #endif 28531369Sdduvall { 28541369Sdduvall BGE_TRACE(("bge_unattach($%p)", 28551369Sdduvall (void *)bgep)); 28561369Sdduvall 28571369Sdduvall /* 28581369Sdduvall * Flag that no more activity may be initiated 28591369Sdduvall */ 28601369Sdduvall bgep->progress &= ~PROGRESS_READY; 28611369Sdduvall 28621369Sdduvall /* 28631369Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 28641369Sdduvall * Clean up and free all BGE data structures 28651369Sdduvall */ 28665107Seota if (bgep->periodic_id != NULL) { 28675107Seota ddi_periodic_delete(bgep->periodic_id); 28685107Seota bgep->periodic_id = NULL; 28691369Sdduvall } 28701369Sdduvall if (bgep->progress & PROGRESS_KSTATS) 28711369Sdduvall bge_fini_kstats(bgep); 28721369Sdduvall if (bgep->progress & PROGRESS_PHY) 28731369Sdduvall bge_phys_reset(bgep); 28741369Sdduvall if (bgep->progress & PROGRESS_HWINT) { 28751369Sdduvall mutex_enter(bgep->genlock); 28761408Srandyf #ifdef BGE_IPMI_ASF 28771865Sdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 28781865Sdilpreet #else 28791865Sdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 28801865Sdilpreet #endif 28811865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28821865Sdilpreet DDI_SERVICE_UNAFFECTED); 28831865Sdilpreet #ifdef BGE_IPMI_ASF 28841408Srandyf if (bgep->asf_enabled) { 28851408Srandyf /* 28861408Srandyf * This register has been overlaid. We restore its 28871408Srandyf * initial value here. 28881408Srandyf */ 28891408Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 28901408Srandyf BGE_NIC_DATA_SIG); 28911408Srandyf } 28921408Srandyf #endif 28931865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 28941865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28951865Sdilpreet DDI_SERVICE_UNAFFECTED); 28961865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 28971865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 28981865Sdilpreet DDI_SERVICE_UNAFFECTED); 28991369Sdduvall mutex_exit(bgep->genlock); 29001369Sdduvall } 29011369Sdduvall if (bgep->progress & PROGRESS_INTR) { 29021865Sdilpreet bge_intr_disable(bgep); 29031369Sdduvall bge_fini_rings(bgep); 29041369Sdduvall } 29051865Sdilpreet if (bgep->progress & PROGRESS_HWINT) { 29061865Sdilpreet bge_rem_intrs(bgep); 29071865Sdilpreet rw_destroy(bgep->errlock); 29081865Sdilpreet mutex_destroy(bgep->softintrlock); 29091865Sdilpreet mutex_destroy(bgep->genlock); 29101865Sdilpreet } 29111369Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 29121369Sdduvall ddi_remove_softintr(bgep->factotum_id); 29131369Sdduvall if (bgep->progress & PROGRESS_RESCHED) 29143334Sgs150176 ddi_remove_softintr(bgep->drain_id); 29151865Sdilpreet if (bgep->progress & PROGRESS_BUFS) 29161865Sdilpreet bge_free_bufs(bgep); 29171369Sdduvall if (bgep->progress & PROGRESS_REGS) 29181369Sdduvall ddi_regs_map_free(&bgep->io_handle); 29191369Sdduvall if (bgep->progress & PROGRESS_CFG) 29201369Sdduvall pci_config_teardown(&bgep->cfg_handle); 29211369Sdduvall 29221865Sdilpreet bge_fm_fini(bgep); 29231865Sdilpreet 29241369Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 29253334Sgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t)); 29261369Sdduvall kmem_free(bgep, sizeof (*bgep)); 29271369Sdduvall } 29281369Sdduvall 29291369Sdduvall static int 29301369Sdduvall bge_resume(dev_info_t *devinfo) 29311369Sdduvall { 29321369Sdduvall bge_t *bgep; /* Our private data */ 29331369Sdduvall chip_id_t *cidp; 29341369Sdduvall chip_id_t chipid; 29351369Sdduvall 29361369Sdduvall bgep = ddi_get_driver_private(devinfo); 29371369Sdduvall if (bgep == NULL) 29381369Sdduvall return (DDI_FAILURE); 29391369Sdduvall 29401369Sdduvall /* 29411369Sdduvall * Refuse to resume if the data structures aren't consistent 29421369Sdduvall */ 29431369Sdduvall if (bgep->devinfo != devinfo) 29441369Sdduvall return (DDI_FAILURE); 29451369Sdduvall 29461408Srandyf #ifdef BGE_IPMI_ASF 29471408Srandyf /* 29481408Srandyf * Power management hasn't been supported in BGE now. If you 29491408Srandyf * want to implement it, please add the ASF/IPMI related 29501408Srandyf * code here. 29511408Srandyf */ 29521408Srandyf 29531408Srandyf #endif 29541408Srandyf 29551369Sdduvall /* 29561369Sdduvall * Read chip ID & set up config space command register(s) 29571369Sdduvall * Refuse to resume if the chip has changed its identity! 29581369Sdduvall */ 29591369Sdduvall cidp = &bgep->chipid; 29601865Sdilpreet mutex_enter(bgep->genlock); 29611369Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 29621865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 29631865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29641865Sdilpreet mutex_exit(bgep->genlock); 29651865Sdilpreet return (DDI_FAILURE); 29661865Sdilpreet } 29671865Sdilpreet mutex_exit(bgep->genlock); 29681369Sdduvall if (chipid.vendor != cidp->vendor) 29691369Sdduvall return (DDI_FAILURE); 29701369Sdduvall if (chipid.device != cidp->device) 29711369Sdduvall return (DDI_FAILURE); 29721369Sdduvall if (chipid.revision != cidp->revision) 29731369Sdduvall return (DDI_FAILURE); 29741369Sdduvall if (chipid.asic_rev != cidp->asic_rev) 29751369Sdduvall return (DDI_FAILURE); 29761369Sdduvall 29771369Sdduvall /* 29781369Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 29791369Sdduvall */ 29801369Sdduvall mutex_enter(bgep->genlock); 29811865Sdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 29821865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 29831865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 29841865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29851865Sdilpreet mutex_exit(bgep->genlock); 29861865Sdilpreet return (DDI_FAILURE); 29871865Sdilpreet } 29881865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 29891865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29901865Sdilpreet mutex_exit(bgep->genlock); 29911865Sdilpreet return (DDI_FAILURE); 29921865Sdilpreet } 29931865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 29941865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 29951865Sdilpreet mutex_exit(bgep->genlock); 29961865Sdilpreet return (DDI_FAILURE); 29971865Sdilpreet } 29981369Sdduvall mutex_exit(bgep->genlock); 29991369Sdduvall return (DDI_SUCCESS); 30001369Sdduvall } 30011369Sdduvall 30021369Sdduvall /* 30031369Sdduvall * attach(9E) -- Attach a device to the system 30041369Sdduvall * 30051369Sdduvall * Called once for each board successfully probed. 30061369Sdduvall */ 30071369Sdduvall static int 30081369Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 30091369Sdduvall { 30101369Sdduvall bge_t *bgep; /* Our private data */ 30112311Sseb mac_register_t *macp; 30121369Sdduvall chip_id_t *cidp; 30131369Sdduvall caddr_t regs; 30141369Sdduvall int instance; 30151369Sdduvall int err; 30161369Sdduvall int intr_types; 30171408Srandyf #ifdef BGE_IPMI_ASF 30181408Srandyf uint32_t mhcrValue; 30193918Sml149210 #ifdef __sparc 30203918Sml149210 uint16_t value16; 30213918Sml149210 #endif 30223918Sml149210 #ifdef BGE_NETCONSOLE 30233918Sml149210 int retval; 30243918Sml149210 #endif 30251408Srandyf #endif 30261369Sdduvall 30271369Sdduvall instance = ddi_get_instance(devinfo); 30281369Sdduvall 30291369Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 30304588Sml149210 (void *)devinfo, cmd, instance)); 30311369Sdduvall BGE_BRKPT(NULL, "bge_attach"); 30321369Sdduvall 30331369Sdduvall switch (cmd) { 30341369Sdduvall default: 30351369Sdduvall return (DDI_FAILURE); 30361369Sdduvall 30371369Sdduvall case DDI_RESUME: 30381369Sdduvall return (bge_resume(devinfo)); 30391369Sdduvall 30401369Sdduvall case DDI_ATTACH: 30411369Sdduvall break; 30421369Sdduvall } 30431369Sdduvall 30441369Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 30453334Sgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP); 30461369Sdduvall ddi_set_driver_private(devinfo, bgep); 30471369Sdduvall bgep->bge_guard = BGE_GUARD; 30481369Sdduvall bgep->devinfo = devinfo; 30495903Ssowmini bgep->param_drain_max = 64; 30505903Ssowmini bgep->param_msi_cnt = 0; 30515903Ssowmini bgep->param_loop_mode = 0; 30521369Sdduvall 30531369Sdduvall /* 30541369Sdduvall * Initialize more fields in BGE private data 30551369Sdduvall */ 30561369Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 30574588Sml149210 DDI_PROP_DONTPASS, debug_propname, bge_debug); 30581369Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 30594588Sml149210 BGE_DRIVER_NAME, instance); 30601369Sdduvall 30611369Sdduvall /* 30621865Sdilpreet * Initialize for fma support 30631865Sdilpreet */ 30641865Sdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 30651865Sdilpreet DDI_PROP_DONTPASS, fm_cap, 30661865Sdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 30671865Sdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 30681865Sdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 30691865Sdilpreet bge_fm_init(bgep); 30701865Sdilpreet 30711865Sdilpreet /* 30721369Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 30731369Sdduvall * a power of 2) and convert to a mask. This can be used to 30741369Sdduvall * determine whether a message buffer crosses a page boundary. 30751369Sdduvall * Note: in 2s complement binary notation, if X is a power of 30761369Sdduvall * 2, then -X has the representation "11...1100...00". 30771369Sdduvall */ 30781369Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 30791369Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 30801369Sdduvall bgep->pagemask = -bgep->pagemask; 30811369Sdduvall 30821369Sdduvall /* 30831369Sdduvall * Map config space registers 30841369Sdduvall * Read chip ID & set up config space command register(s) 30851369Sdduvall * 30861369Sdduvall * Note: this leaves the chip accessible by Memory Space 30871369Sdduvall * accesses, but with interrupts and Bus Mastering off. 30881369Sdduvall * This should ensure that nothing untoward will happen 30891369Sdduvall * if it has been left active by the (net-)bootloader. 30901369Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 30911369Sdduvall * and allow interrupts only when everything else is set up. 30921369Sdduvall */ 30931369Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 30941408Srandyf #ifdef BGE_IPMI_ASF 30953918Sml149210 #ifdef __sparc 30963918Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM); 30973918Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME); 30983918Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16); 30993918Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS | 31004588Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE | 31014588Sml149210 MHCR_MASK_INTERRUPT_MODE | 31024588Sml149210 MHCR_MASK_PCI_INT_OUTPUT | 31034588Sml149210 MHCR_CLEAR_INTERRUPT_INTA | 31044588Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP | 31054588Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP; 31063918Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue); 31073918Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG, 31084588Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) | 31094588Sml149210 MEMORY_ARBITER_ENABLE); 31103918Sml149210 #else 31111408Srandyf mhcrValue = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 31123918Sml149210 #endif 31131408Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 31141408Srandyf bgep->asf_wordswapped = B_TRUE; 31151408Srandyf } else { 31161408Srandyf bgep->asf_wordswapped = B_FALSE; 31171408Srandyf } 31181408Srandyf bge_asf_get_config(bgep); 31191408Srandyf #endif 31201369Sdduvall if (err != DDI_SUCCESS) { 31211369Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 31221369Sdduvall goto attach_fail; 31231369Sdduvall } 31241369Sdduvall bgep->progress |= PROGRESS_CFG; 31251369Sdduvall cidp = &bgep->chipid; 31261369Sdduvall bzero(cidp, sizeof (*cidp)); 31271369Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 31281865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 31291865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31301865Sdilpreet goto attach_fail; 31311865Sdilpreet } 31321369Sdduvall 31331408Srandyf #ifdef BGE_IPMI_ASF 31341408Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 31351408Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 31361408Srandyf bgep->asf_newhandshake = B_TRUE; 31371408Srandyf } else { 31381408Srandyf bgep->asf_newhandshake = B_FALSE; 31391408Srandyf } 31401408Srandyf #endif 31411408Srandyf 31421369Sdduvall /* 31431369Sdduvall * Update those parts of the chip ID derived from volatile 31441369Sdduvall * registers with the values seen by OBP (in case the chip 31451369Sdduvall * has been reset externally and therefore lost them). 31461369Sdduvall */ 31471369Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31484588Sml149210 DDI_PROP_DONTPASS, subven_propname, cidp->subven); 31491369Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31504588Sml149210 DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 31511369Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31524588Sml149210 DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 31531369Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31544588Sml149210 DDI_PROP_DONTPASS, latency_propname, cidp->latency); 31551369Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31564588Sml149210 DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 31571369Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31584588Sml149210 DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 31591369Sdduvall 31601369Sdduvall if (bge_jumbo_enable == B_TRUE) { 31611369Sdduvall cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 31624588Sml149210 DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 31631369Sdduvall if ((cidp->default_mtu < BGE_DEFAULT_MTU)|| 31644588Sml149210 (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 31651369Sdduvall cidp->default_mtu = BGE_DEFAULT_MTU; 31661369Sdduvall } 31671369Sdduvall } 31681369Sdduvall /* 31691369Sdduvall * Map operating registers 31701369Sdduvall */ 31711369Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 31724588Sml149210 ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 31731369Sdduvall if (err != DDI_SUCCESS) { 31741369Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 31751369Sdduvall goto attach_fail; 31761369Sdduvall } 31771369Sdduvall bgep->io_regs = regs; 31781369Sdduvall bgep->progress |= PROGRESS_REGS; 31791369Sdduvall 31801369Sdduvall /* 31811369Sdduvall * Characterise the device, so we know its requirements. 31821369Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 31831369Sdduvall */ 31841865Sdilpreet if (bge_chip_id_init(bgep) == EIO) { 31851865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 31861865Sdilpreet goto attach_fail; 31871865Sdilpreet } 31886512Ssowmini 31896512Ssowmini 31901369Sdduvall err = bge_alloc_bufs(bgep); 31911369Sdduvall if (err != DDI_SUCCESS) { 31921369Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 31931369Sdduvall goto attach_fail; 31941369Sdduvall } 31951865Sdilpreet bgep->progress |= PROGRESS_BUFS; 31961369Sdduvall 31971369Sdduvall /* 31981369Sdduvall * Add the softint handlers: 31991369Sdduvall * 32001369Sdduvall * Both of these handlers are used to avoid restrictions on the 32011369Sdduvall * context and/or mutexes required for some operations. In 32021369Sdduvall * particular, the hardware interrupt handler and its subfunctions 32031369Sdduvall * can detect a number of conditions that we don't want to handle 32041369Sdduvall * in that context or with that set of mutexes held. So, these 32051369Sdduvall * softints are triggered instead: 32061369Sdduvall * 32072135Szh199473 * the <resched> softint is triggered if we have previously 32081369Sdduvall * had to refuse to send a packet because of resource shortage 32091369Sdduvall * (we've run out of transmit buffers), but the send completion 32101369Sdduvall * interrupt handler has now detected that more buffers have 32111369Sdduvall * become available. 32121369Sdduvall * 32131369Sdduvall * the <factotum> is triggered if the h/w interrupt handler 32141369Sdduvall * sees the <link state changed> or <error> bits in the status 32151369Sdduvall * block. It's also triggered periodically to poll the link 32161369Sdduvall * state, just in case we aren't getting link status change 32171369Sdduvall * interrupts ... 32181369Sdduvall */ 32193334Sgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id, 32204588Sml149210 NULL, NULL, bge_send_drain, (caddr_t)bgep); 32211369Sdduvall if (err != DDI_SUCCESS) { 32221369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 32231369Sdduvall goto attach_fail; 32241369Sdduvall } 32251369Sdduvall bgep->progress |= PROGRESS_RESCHED; 32261369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 32274588Sml149210 NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 32281369Sdduvall if (err != DDI_SUCCESS) { 32291369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 32301369Sdduvall goto attach_fail; 32311369Sdduvall } 32321369Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 32331369Sdduvall 32341369Sdduvall /* Get supported interrupt types */ 32351369Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 32361369Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 32371369Sdduvall 32381369Sdduvall goto attach_fail; 32391369Sdduvall } 32401369Sdduvall 32412675Szh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x", 32424588Sml149210 bgep->ifname, intr_types)); 32431369Sdduvall 32441369Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 32451369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 32461369Sdduvall bge_error(bgep, "MSI registration failed, " 32471369Sdduvall "trying FIXED interrupt type\n"); 32481369Sdduvall } else { 32492675Szh199473 BGE_DEBUG(("%s: Using MSI interrupt type", 32504588Sml149210 bgep->ifname)); 32511369Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 32521865Sdilpreet bgep->progress |= PROGRESS_HWINT; 32531369Sdduvall } 32541369Sdduvall } 32551369Sdduvall 32561865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 32571369Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 32581369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 32591369Sdduvall bge_error(bgep, "FIXED interrupt " 32601369Sdduvall "registration failed\n"); 32611369Sdduvall goto attach_fail; 32621369Sdduvall } 32631369Sdduvall 32642675Szh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname)); 32651369Sdduvall 32661369Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 32671865Sdilpreet bgep->progress |= PROGRESS_HWINT; 32681369Sdduvall } 32691369Sdduvall 32701865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 32711369Sdduvall bge_error(bgep, "No interrupts registered\n"); 32721369Sdduvall goto attach_fail; 32731369Sdduvall } 32741369Sdduvall 32751369Sdduvall /* 32761369Sdduvall * Note that interrupts are not enabled yet as 32771865Sdilpreet * mutex locks are not initialized. Initialize mutex locks. 32781865Sdilpreet */ 32791865Sdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 32801865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32811865Sdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 32821865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32831865Sdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 32841865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 32851865Sdilpreet 32861865Sdilpreet /* 32871865Sdilpreet * Initialize rings. 32881369Sdduvall */ 32891369Sdduvall bge_init_rings(bgep); 32901369Sdduvall 32911369Sdduvall /* 32921369Sdduvall * Now that mutex locks are initialized, enable interrupts. 32931369Sdduvall */ 32941865Sdilpreet bge_intr_enable(bgep); 32951865Sdilpreet bgep->progress |= PROGRESS_INTR; 32961369Sdduvall 32971369Sdduvall /* 32981369Sdduvall * Initialise link state variables 32991369Sdduvall * Stop, reset & reinitialise the chip. 33001369Sdduvall * Initialise the (internal) PHY. 33011369Sdduvall */ 33021369Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 33031369Sdduvall 33041369Sdduvall mutex_enter(bgep->genlock); 33051369Sdduvall 33061369Sdduvall /* 33071369Sdduvall * Reset chip & rings to initial state; also reset address 33081369Sdduvall * filtering, promiscuity, loopback mode. 33091369Sdduvall */ 33101408Srandyf #ifdef BGE_IPMI_ASF 33113918Sml149210 #ifdef BGE_NETCONSOLE 33123918Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 33133918Sml149210 #else 33141865Sdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 33153918Sml149210 #endif 33161408Srandyf #else 33171865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 33181408Srandyf #endif 33191865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 33201865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 33211865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33221865Sdilpreet mutex_exit(bgep->genlock); 33231865Sdilpreet goto attach_fail; 33241865Sdilpreet } 33251369Sdduvall 33262675Szh199473 #ifdef BGE_IPMI_ASF 33272675Szh199473 if (bgep->asf_enabled) { 33282675Szh199473 bgep->asf_status = ASF_STAT_RUN_INIT; 33292675Szh199473 } 33302675Szh199473 #endif 33312675Szh199473 33321369Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 33331369Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 33341369Sdduvall bgep->promisc = B_FALSE; 33351369Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 33361865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 33371865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33381865Sdilpreet mutex_exit(bgep->genlock); 33391865Sdilpreet goto attach_fail; 33401865Sdilpreet } 33411865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 33421865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33431865Sdilpreet mutex_exit(bgep->genlock); 33441865Sdilpreet goto attach_fail; 33451865Sdilpreet } 33461369Sdduvall 33471369Sdduvall mutex_exit(bgep->genlock); 33481369Sdduvall 33491865Sdilpreet if (bge_phys_init(bgep) == EIO) { 33501865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 33511865Sdilpreet goto attach_fail; 33521865Sdilpreet } 33531369Sdduvall bgep->progress |= PROGRESS_PHY; 33541369Sdduvall 33551369Sdduvall /* 33566512Ssowmini * initialize NDD-tweakable parameters 33571369Sdduvall */ 33581369Sdduvall if (bge_nd_init(bgep)) { 33591369Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 33601369Sdduvall goto attach_fail; 33611369Sdduvall } 33621369Sdduvall bgep->progress |= PROGRESS_NDD; 33631369Sdduvall 33641369Sdduvall /* 33651369Sdduvall * Create & initialise named kstats 33661369Sdduvall */ 33671369Sdduvall bge_init_kstats(bgep, instance); 33681369Sdduvall bgep->progress |= PROGRESS_KSTATS; 33691369Sdduvall 33701369Sdduvall /* 33711369Sdduvall * Determine whether to override the chip's own MAC address 33721369Sdduvall */ 33731369Sdduvall bge_find_mac_address(bgep, cidp); 33742331Skrgopi ethaddr_copy(cidp->vendor_addr.addr, bgep->curr_addr[0].addr); 33752331Skrgopi bgep->curr_addr[0].set = B_TRUE; 33762331Skrgopi 33772406Skrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX; 33782406Skrgopi /* 33792406Skrgopi * Address available is one less than MAX 33802406Skrgopi * as primary address is not advertised 33812406Skrgopi * as a multiple MAC address. 33822406Skrgopi */ 33832331Skrgopi bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX - 1; 33841369Sdduvall 33852311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 33862311Sseb goto attach_fail; 33872311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 33882311Sseb macp->m_driver = bgep; 33891369Sdduvall macp->m_dip = devinfo; 33902331Skrgopi macp->m_src_addr = bgep->curr_addr[0].addr; 33912311Sseb macp->m_callbacks = &bge_m_callbacks; 33922311Sseb macp->m_min_sdu = 0; 33932311Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header); 33945895Syz147064 macp->m_margin = VLAN_TAGSZ; 33956512Ssowmini macp->m_priv_props = bge_priv_prop; 33966512Ssowmini macp->m_priv_prop_count = BGE_MAX_PRIV_PROPS; 33976512Ssowmini 33981369Sdduvall /* 33991369Sdduvall * Finally, we're ready to register ourselves with the MAC layer 34001369Sdduvall * interface; if this succeeds, we're all ready to start() 34011369Sdduvall */ 34022311Sseb err = mac_register(macp, &bgep->mh); 34032311Sseb mac_free(macp); 34042311Sseb if (err != 0) 34051369Sdduvall goto attach_fail; 34061369Sdduvall 34075107Seota /* 34085107Seota * Register a periodical handler. 34095107Seota * bge_chip_cyclic() is invoked in kernel context. 34105107Seota */ 34115107Seota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep, 34125107Seota BGE_CYCLIC_PERIOD, DDI_IPL_0); 34131369Sdduvall 34141369Sdduvall bgep->progress |= PROGRESS_READY; 34151369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 34163918Sml149210 #ifdef BGE_IPMI_ASF 34173918Sml149210 #ifdef BGE_NETCONSOLE 34183918Sml149210 if (bgep->asf_enabled) { 34193918Sml149210 mutex_enter(bgep->genlock); 34203918Sml149210 retval = bge_chip_start(bgep, B_TRUE); 34213918Sml149210 mutex_exit(bgep->genlock); 34223918Sml149210 if (retval != DDI_SUCCESS) 34233918Sml149210 goto attach_fail; 34243918Sml149210 } 34253918Sml149210 #endif 34263918Sml149210 #endif 34271369Sdduvall return (DDI_SUCCESS); 34281369Sdduvall 34291369Sdduvall attach_fail: 34301408Srandyf #ifdef BGE_IPMI_ASF 34312675Szh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN); 34321408Srandyf #else 34331369Sdduvall bge_unattach(bgep); 34341408Srandyf #endif 34351369Sdduvall return (DDI_FAILURE); 34361369Sdduvall } 34371369Sdduvall 34381369Sdduvall /* 34391369Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 34401369Sdduvall */ 34411369Sdduvall static int 34421369Sdduvall bge_suspend(bge_t *bgep) 34431369Sdduvall { 34441369Sdduvall /* 34451369Sdduvall * Stop processing and idle (powerdown) the PHY ... 34461369Sdduvall */ 34471369Sdduvall mutex_enter(bgep->genlock); 34481408Srandyf #ifdef BGE_IPMI_ASF 34491408Srandyf /* 34501408Srandyf * Power management hasn't been supported in BGE now. If you 34511408Srandyf * want to implement it, please add the ASF/IPMI related 34521408Srandyf * code here. 34531408Srandyf */ 34541408Srandyf #endif 34551369Sdduvall bge_stop(bgep); 34561865Sdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 34571865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 34581865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 34591865Sdilpreet mutex_exit(bgep->genlock); 34601865Sdilpreet return (DDI_FAILURE); 34611865Sdilpreet } 34621865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 34631865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 34641865Sdilpreet mutex_exit(bgep->genlock); 34651865Sdilpreet return (DDI_FAILURE); 34661865Sdilpreet } 34671369Sdduvall mutex_exit(bgep->genlock); 34681369Sdduvall 34691369Sdduvall return (DDI_SUCCESS); 34701369Sdduvall } 34711369Sdduvall 34721369Sdduvall /* 34731369Sdduvall * detach(9E) -- Detach a device from the system 34741369Sdduvall */ 34751369Sdduvall static int 34761369Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 34771369Sdduvall { 34781369Sdduvall bge_t *bgep; 34791408Srandyf #ifdef BGE_IPMI_ASF 34801408Srandyf uint_t asf_mode; 34811408Srandyf asf_mode = ASF_MODE_NONE; 34821408Srandyf #endif 34831369Sdduvall 34841369Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 34851369Sdduvall 34861369Sdduvall bgep = ddi_get_driver_private(devinfo); 34871369Sdduvall 34881369Sdduvall switch (cmd) { 34891369Sdduvall default: 34901369Sdduvall return (DDI_FAILURE); 34911369Sdduvall 34921369Sdduvall case DDI_SUSPEND: 34931369Sdduvall return (bge_suspend(bgep)); 34941369Sdduvall 34951369Sdduvall case DDI_DETACH: 34961369Sdduvall break; 34971369Sdduvall } 34981369Sdduvall 34991408Srandyf #ifdef BGE_IPMI_ASF 35001408Srandyf mutex_enter(bgep->genlock); 35012675Szh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) || 35024588Sml149210 (bgep->asf_status == ASF_STAT_RUN_INIT))) { 35031408Srandyf 35041408Srandyf bge_asf_update_status(bgep); 35052675Szh199473 if (bgep->asf_status == ASF_STAT_RUN) { 35062675Szh199473 bge_asf_stop_timer(bgep); 35072675Szh199473 } 35081408Srandyf bgep->asf_status = ASF_STAT_STOP; 35091408Srandyf 35101408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 35111408Srandyf 35121408Srandyf if (bgep->asf_pseudostop) { 35131408Srandyf bge_chip_stop(bgep, B_FALSE); 35141408Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 35151408Srandyf bgep->asf_pseudostop = B_FALSE; 35161408Srandyf } 35171408Srandyf 35181408Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 35191865Sdilpreet 35201865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 35211865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 35221865Sdilpreet DDI_SERVICE_UNAFFECTED); 35231865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 35241865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 35251865Sdilpreet DDI_SERVICE_UNAFFECTED); 35261408Srandyf } 35271408Srandyf mutex_exit(bgep->genlock); 35281408Srandyf #endif 35291408Srandyf 35301369Sdduvall /* 35311369Sdduvall * Unregister from the GLD subsystem. This can fail, in 35321369Sdduvall * particular if there are DLPI style-2 streams still open - 35331369Sdduvall * in which case we just return failure without shutting 35341369Sdduvall * down chip operations. 35351369Sdduvall */ 35362311Sseb if (mac_unregister(bgep->mh) != 0) 35371369Sdduvall return (DDI_FAILURE); 35381369Sdduvall 35391369Sdduvall /* 35401369Sdduvall * All activity stopped, so we can clean up & exit 35411369Sdduvall */ 35421408Srandyf #ifdef BGE_IPMI_ASF 35431408Srandyf bge_unattach(bgep, asf_mode); 35441408Srandyf #else 35451369Sdduvall bge_unattach(bgep); 35461408Srandyf #endif 35471369Sdduvall return (DDI_SUCCESS); 35481369Sdduvall } 35491369Sdduvall 35501369Sdduvall 35511369Sdduvall /* 35521369Sdduvall * ========== Module Loading Data & Entry Points ========== 35531369Sdduvall */ 35541369Sdduvall 35551369Sdduvall #undef BGE_DBG 35561369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 35571369Sdduvall 35581369Sdduvall DDI_DEFINE_STREAM_OPS(bge_dev_ops, nulldev, nulldev, bge_attach, bge_detach, 35591369Sdduvall nodev, NULL, D_MP, NULL); 35601369Sdduvall 35611369Sdduvall static struct modldrv bge_modldrv = { 35621369Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 35631369Sdduvall bge_ident, /* short description */ 35641369Sdduvall &bge_dev_ops /* driver specific ops */ 35651369Sdduvall }; 35661369Sdduvall 35671369Sdduvall static struct modlinkage modlinkage = { 35681369Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 35691369Sdduvall }; 35701369Sdduvall 35711369Sdduvall 35721369Sdduvall int 35731369Sdduvall _info(struct modinfo *modinfop) 35741369Sdduvall { 35751369Sdduvall return (mod_info(&modlinkage, modinfop)); 35761369Sdduvall } 35771369Sdduvall 35781369Sdduvall int 35791369Sdduvall _init(void) 35801369Sdduvall { 35811369Sdduvall int status; 35821369Sdduvall 35831369Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 35841369Sdduvall status = mod_install(&modlinkage); 35851369Sdduvall if (status == DDI_SUCCESS) 35861369Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 35871369Sdduvall else 35881369Sdduvall mac_fini_ops(&bge_dev_ops); 35891369Sdduvall return (status); 35901369Sdduvall } 35911369Sdduvall 35921369Sdduvall int 35931369Sdduvall _fini(void) 35941369Sdduvall { 35951369Sdduvall int status; 35961369Sdduvall 35971369Sdduvall status = mod_remove(&modlinkage); 35981369Sdduvall if (status == DDI_SUCCESS) { 35991369Sdduvall mac_fini_ops(&bge_dev_ops); 36001369Sdduvall mutex_destroy(bge_log_mutex); 36011369Sdduvall } 36021369Sdduvall return (status); 36031369Sdduvall } 36041369Sdduvall 36051369Sdduvall 36061369Sdduvall /* 36071369Sdduvall * bge_add_intrs: 36081369Sdduvall * 36091369Sdduvall * Register FIXED or MSI interrupts. 36101369Sdduvall */ 36111369Sdduvall static int 36121369Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 36131369Sdduvall { 36141369Sdduvall dev_info_t *dip = bgep->devinfo; 36151369Sdduvall int avail, actual, intr_size, count = 0; 36161369Sdduvall int i, flag, ret; 36171369Sdduvall 36182675Szh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type)); 36191369Sdduvall 36201369Sdduvall /* Get number of interrupts */ 36211369Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 36221369Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 36231369Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 36241369Sdduvall "count: %d", ret, count); 36251369Sdduvall 36261369Sdduvall return (DDI_FAILURE); 36271369Sdduvall } 36281369Sdduvall 36291369Sdduvall /* Get number of available interrupts */ 36301369Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 36311369Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 36321369Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 36331369Sdduvall "ret: %d, avail: %d\n", ret, avail); 36341369Sdduvall 36351369Sdduvall return (DDI_FAILURE); 36361369Sdduvall } 36371369Sdduvall 36381369Sdduvall if (avail < count) { 36392675Szh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d", 36402675Szh199473 bgep->ifname, count, avail)); 36411369Sdduvall } 36421369Sdduvall 36431369Sdduvall /* 36441369Sdduvall * BGE hardware generates only single MSI even though it claims 36451369Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 36461369Sdduvall */ 36471369Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 36481369Sdduvall count = 1; 36491369Sdduvall flag = DDI_INTR_ALLOC_STRICT; 36501369Sdduvall } else { 36511369Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 36521369Sdduvall } 36531369Sdduvall 36541369Sdduvall /* Allocate an array of interrupt handles */ 36551369Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 36561369Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 36571369Sdduvall 36581369Sdduvall /* Call ddi_intr_alloc() */ 36591369Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 36601369Sdduvall count, &actual, flag); 36611369Sdduvall 36621369Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 36631369Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 36641369Sdduvall 36651369Sdduvall kmem_free(bgep->htable, intr_size); 36661369Sdduvall return (DDI_FAILURE); 36671369Sdduvall } 36681369Sdduvall 36691369Sdduvall if (actual < count) { 36702675Szh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d", 36714588Sml149210 bgep->ifname, count, actual)); 36721369Sdduvall } 36731369Sdduvall 36741369Sdduvall bgep->intr_cnt = actual; 36751369Sdduvall 36761369Sdduvall /* 36771369Sdduvall * Get priority for first msi, assume remaining are all the same 36781369Sdduvall */ 36791369Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 36801369Sdduvall DDI_SUCCESS) { 36811369Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 36821369Sdduvall 36831369Sdduvall /* Free already allocated intr */ 36841369Sdduvall for (i = 0; i < actual; i++) { 36851369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 36861369Sdduvall } 36871369Sdduvall 36881369Sdduvall kmem_free(bgep->htable, intr_size); 36891369Sdduvall return (DDI_FAILURE); 36901369Sdduvall } 36911369Sdduvall 36921369Sdduvall /* Call ddi_intr_add_handler() */ 36931369Sdduvall for (i = 0; i < actual; i++) { 36941369Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 36951369Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 36961369Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 36971369Sdduvall "failed %d\n", ret); 36981369Sdduvall 36991369Sdduvall /* Free already allocated intr */ 37001369Sdduvall for (i = 0; i < actual; i++) { 37011369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 37021369Sdduvall } 37031369Sdduvall 37041369Sdduvall kmem_free(bgep->htable, intr_size); 37051369Sdduvall return (DDI_FAILURE); 37061369Sdduvall } 37071369Sdduvall } 37081369Sdduvall 37091369Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 37104588Sml149210 != DDI_SUCCESS) { 37111369Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 37121369Sdduvall 37131369Sdduvall for (i = 0; i < actual; i++) { 37141369Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 37151369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 37161369Sdduvall } 37171369Sdduvall 37181369Sdduvall kmem_free(bgep->htable, intr_size); 37191369Sdduvall return (DDI_FAILURE); 37201369Sdduvall } 37211369Sdduvall 37221369Sdduvall return (DDI_SUCCESS); 37231369Sdduvall } 37241369Sdduvall 37251369Sdduvall /* 37261369Sdduvall * bge_rem_intrs: 37271369Sdduvall * 37281369Sdduvall * Unregister FIXED or MSI interrupts 37291369Sdduvall */ 37301369Sdduvall static void 37311369Sdduvall bge_rem_intrs(bge_t *bgep) 37321369Sdduvall { 37331369Sdduvall int i; 37341369Sdduvall 37352675Szh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep)); 37361369Sdduvall 37371865Sdilpreet /* Call ddi_intr_remove_handler() */ 37381865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 37391865Sdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 37401865Sdilpreet (void) ddi_intr_free(bgep->htable[i]); 37411865Sdilpreet } 37421865Sdilpreet 37431865Sdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 37441865Sdilpreet } 37451865Sdilpreet 37461865Sdilpreet 37471865Sdilpreet void 37481865Sdilpreet bge_intr_enable(bge_t *bgep) 37491865Sdilpreet { 37501865Sdilpreet int i; 37511865Sdilpreet 37521865Sdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 37531865Sdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 37541865Sdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 37551865Sdilpreet } else { 37561865Sdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 37571865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 37581865Sdilpreet (void) ddi_intr_enable(bgep->htable[i]); 37591865Sdilpreet } 37601865Sdilpreet } 37611865Sdilpreet } 37621865Sdilpreet 37631865Sdilpreet 37641865Sdilpreet void 37651865Sdilpreet bge_intr_disable(bge_t *bgep) 37661865Sdilpreet { 37671865Sdilpreet int i; 37681865Sdilpreet 37691369Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 37701369Sdduvall /* Call ddi_intr_block_disable() */ 37711369Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 37721369Sdduvall } else { 37731369Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 37741369Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 37751369Sdduvall } 37761369Sdduvall } 37771369Sdduvall } 37785903Ssowmini 37795903Ssowmini int 37805903Ssowmini bge_reprogram(bge_t *bgep) 37815903Ssowmini { 37825903Ssowmini int status = 0; 37835903Ssowmini 37845903Ssowmini ASSERT(mutex_owned(bgep->genlock)); 37855903Ssowmini 37865903Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) { 37875903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 37885903Ssowmini status = IOC_INVAL; 37895903Ssowmini } 37905903Ssowmini #ifdef BGE_IPMI_ASF 37915903Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 37925903Ssowmini #else 37935903Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) { 37945903Ssowmini #endif 37955903Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 37965903Ssowmini status = IOC_INVAL; 37975903Ssowmini } 37985903Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI) 37995903Ssowmini bge_chip_msi_trig(bgep); 38005903Ssowmini return (status); 38015903Ssowmini } 3802