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 /* 231369Sdduvall * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 271369Sdduvall #pragma ident "%Z%%M% %I% %E% SMI" 281369Sdduvall 291369Sdduvall #include "sys/bge_impl2.h" 301369Sdduvall #include <sys/sdt.h> 311369Sdduvall 321369Sdduvall /* 331369Sdduvall * This is the string displayed by modinfo, etc. 341369Sdduvall * Make sure you keep the version ID up to date! 351369Sdduvall */ 361611Szh199473 static char bge_ident[] = "BCM579x driver v0.51"; 371369Sdduvall 381369Sdduvall /* 391369Sdduvall * Property names 401369Sdduvall */ 411369Sdduvall static char debug_propname[] = "bge-debug-flags"; 421369Sdduvall static char clsize_propname[] = "cache-line-size"; 431369Sdduvall static char latency_propname[] = "latency-timer"; 441369Sdduvall static char localmac_boolname[] = "local-mac-address?"; 451369Sdduvall static char localmac_propname[] = "local-mac-address"; 461369Sdduvall static char macaddr_propname[] = "mac-address"; 471369Sdduvall static char subdev_propname[] = "subsystem-id"; 481369Sdduvall static char subven_propname[] = "subsystem-vendor-id"; 491369Sdduvall static char rxrings_propname[] = "bge-rx-rings"; 501369Sdduvall static char txrings_propname[] = "bge-tx-rings"; 51*1865Sdilpreet static char fm_cap[] = "fm-capable"; 521369Sdduvall static char default_mtu[] = "default-mtu"; 531369Sdduvall 541369Sdduvall static int bge_add_intrs(bge_t *, int); 551369Sdduvall static void bge_rem_intrs(bge_t *); 561369Sdduvall 571369Sdduvall /* 581369Sdduvall * Describes the chip's DMA engine 591369Sdduvall */ 601369Sdduvall static ddi_dma_attr_t dma_attr = { 611369Sdduvall DMA_ATTR_V0, /* dma_attr version */ 621369Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */ 631369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 641369Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 651369Sdduvall 0x0000000000000001ull, /* dma_attr_align */ 661369Sdduvall 0x00000FFF, /* dma_attr_burstsizes */ 671369Sdduvall 0x00000001, /* dma_attr_minxfer */ 681369Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */ 691369Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */ 701369Sdduvall 1, /* dma_attr_sgllen */ 711369Sdduvall 0x00000001, /* dma_attr_granular */ 72*1865Sdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */ 731369Sdduvall }; 741369Sdduvall 751369Sdduvall /* 761369Sdduvall * PIO access attributes for registers 771369Sdduvall */ 781369Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = { 791369Sdduvall DDI_DEVICE_ATTR_V0, 801369Sdduvall DDI_NEVERSWAP_ACC, 81*1865Sdilpreet DDI_STRICTORDER_ACC, 82*1865Sdilpreet DDI_FLAGERR_ACC 831369Sdduvall }; 841369Sdduvall 851369Sdduvall /* 861369Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped. 871369Sdduvall */ 881369Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = { 891369Sdduvall DDI_DEVICE_ATTR_V0, 901369Sdduvall DDI_NEVERSWAP_ACC, 91*1865Sdilpreet DDI_STRICTORDER_ACC, 92*1865Sdilpreet DDI_FLAGERR_ACC 931369Sdduvall }; 941369Sdduvall 951369Sdduvall /* 961369Sdduvall * DMA access attributes for data: NOT to be byte swapped. 971369Sdduvall */ 981369Sdduvall static ddi_device_acc_attr_t bge_data_accattr = { 991369Sdduvall DDI_DEVICE_ATTR_V0, 1001369Sdduvall DDI_NEVERSWAP_ACC, 1011369Sdduvall DDI_STRICTORDER_ACC 1021369Sdduvall }; 1031369Sdduvall 1041369Sdduvall static ether_addr_t bge_broadcast_addr = { 1051369Sdduvall 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1061369Sdduvall }; 1071369Sdduvall 1081369Sdduvall /* 1091369Sdduvall * Versions of the O/S up to Solaris 8 didn't support network booting 1101369Sdduvall * from any network interface except the first (NET0). Patching this 1111369Sdduvall * flag to a non-zero value will tell the driver to work around this 1121369Sdduvall * limitation by creating an extra (internal) pathname node. To do 1131369Sdduvall * this, just add a line like the following to the CLIENT'S etc/system 1141369Sdduvall * file ON THE ROOT FILESYSTEM SERVER before booting the client: 1151369Sdduvall * 1161369Sdduvall * set bge:bge_net1_boot_support = 1; 1171369Sdduvall */ 1181369Sdduvall static uint32_t bge_net1_boot_support = 1; 1191369Sdduvall 1201369Sdduvall /* 1211369Sdduvall * ========== Transmit and receive ring reinitialisation ========== 1221369Sdduvall */ 1231369Sdduvall 1241369Sdduvall /* 1251369Sdduvall * These <reinit> routines each reset the specified ring to an initial 1261369Sdduvall * state, assuming that the corresponding <init> routine has already 1271369Sdduvall * been called exactly once. 1281369Sdduvall */ 1291369Sdduvall 1301369Sdduvall static void 1311369Sdduvall bge_reinit_send_ring(send_ring_t *srp) 1321369Sdduvall { 1331369Sdduvall /* 1341369Sdduvall * Reinitialise control variables ... 1351369Sdduvall */ 1361369Sdduvall ASSERT(srp->tx_flow == 0); 1371369Sdduvall srp->tx_next = 0; 1381369Sdduvall srp->tx_free = srp->desc.nslots; 1391369Sdduvall 1401369Sdduvall ASSERT(mutex_owned(srp->tc_lock)); 1411369Sdduvall srp->tc_next = 0; 1421369Sdduvall 1431369Sdduvall /* 1441369Sdduvall * Zero and sync all the h/w Send Buffer Descriptors 1451369Sdduvall */ 1461369Sdduvall DMA_ZERO(srp->desc); 1471369Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 1481369Sdduvall } 1491369Sdduvall 1501369Sdduvall static void 1511369Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp) 1521369Sdduvall { 1531369Sdduvall /* 1541369Sdduvall * Reinitialise control variables ... 1551369Sdduvall */ 1561369Sdduvall rrp->rx_next = 0; 1571369Sdduvall } 1581369Sdduvall 1591369Sdduvall static void 1601369Sdduvall bge_reinit_buff_ring(buff_ring_t *brp, uint64_t ring) 1611369Sdduvall { 1621369Sdduvall bge_rbd_t *hw_rbd_p; 1631369Sdduvall sw_rbd_t *srbdp; 1641369Sdduvall uint32_t bufsize; 1651369Sdduvall uint32_t nslots; 1661369Sdduvall uint32_t slot; 1671369Sdduvall 1681369Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = { 1691369Sdduvall RBD_FLAG_STD_RING, 1701369Sdduvall RBD_FLAG_JUMBO_RING, 1711369Sdduvall RBD_FLAG_MINI_RING 1721369Sdduvall }; 1731369Sdduvall 1741369Sdduvall /* 1751369Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors 1761369Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>, 1771369Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>) 1781369Sdduvall * should be zeroed, and so don't need to be set up specifically 1791369Sdduvall * once the whole area has been cleared. 1801369Sdduvall */ 1811369Sdduvall DMA_ZERO(brp->desc); 1821369Sdduvall 1831369Sdduvall hw_rbd_p = DMA_VPTR(brp->desc); 1841369Sdduvall nslots = brp->desc.nslots; 1851369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 1861369Sdduvall bufsize = brp->buf[0].size; 1871369Sdduvall srbdp = brp->sw_rbds; 1881369Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) { 1891369Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress; 1901369Sdduvall hw_rbd_p->index = slot; 1911369Sdduvall hw_rbd_p->len = bufsize; 1921369Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token; 1931369Sdduvall hw_rbd_p->flags |= ring_type_flag[ring]; 1941369Sdduvall } 1951369Sdduvall 1961369Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV); 1971369Sdduvall 1981369Sdduvall /* 1991369Sdduvall * Finally, reinitialise the ring control variables ... 2001369Sdduvall */ 2011369Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0; 2021369Sdduvall } 2031369Sdduvall 2041369Sdduvall /* 2051369Sdduvall * Reinitialize all rings 2061369Sdduvall */ 2071369Sdduvall static void 2081369Sdduvall bge_reinit_rings(bge_t *bgep) 2091369Sdduvall { 2101369Sdduvall uint64_t ring; 2111369Sdduvall 2121369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 2131369Sdduvall 2141369Sdduvall /* 2151369Sdduvall * Send Rings ... 2161369Sdduvall */ 2171369Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) 2181369Sdduvall bge_reinit_send_ring(&bgep->send[ring]); 2191369Sdduvall 2201369Sdduvall /* 2211369Sdduvall * Receive Return Rings ... 2221369Sdduvall */ 2231369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring) 2241369Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]); 2251369Sdduvall 2261369Sdduvall /* 2271369Sdduvall * Receive Producer Rings ... 2281369Sdduvall */ 2291369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring) 2301369Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring); 2311369Sdduvall } 2321369Sdduvall 2331369Sdduvall /* 2341369Sdduvall * ========== Internal state management entry points ========== 2351369Sdduvall */ 2361369Sdduvall 2371369Sdduvall #undef BGE_DBG 2381369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 2391369Sdduvall 2401369Sdduvall /* 2411369Sdduvall * These routines provide all the functionality required by the 2421369Sdduvall * corresponding GLD entry points, but don't update the GLD state 2431369Sdduvall * so they can be called internally without disturbing our record 2441369Sdduvall * of what GLD thinks we should be doing ... 2451369Sdduvall */ 2461369Sdduvall 2471369Sdduvall /* 2481369Sdduvall * bge_reset() -- reset h/w & rings to initial state 2491369Sdduvall */ 250*1865Sdilpreet static int 2511408Srandyf #ifdef BGE_IPMI_ASF 2521408Srandyf bge_reset(bge_t *bgep, uint_t asf_mode) 2531408Srandyf #else 2541369Sdduvall bge_reset(bge_t *bgep) 2551408Srandyf #endif 2561369Sdduvall { 2571369Sdduvall uint64_t ring; 258*1865Sdilpreet int retval; 2591369Sdduvall 2601369Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep)); 2611369Sdduvall 2621369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 2631369Sdduvall 2641369Sdduvall /* 2651369Sdduvall * Grab all the other mutexes in the world (this should 2661369Sdduvall * ensure no other threads are manipulating driver state) 2671369Sdduvall */ 2681369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 2691369Sdduvall mutex_enter(bgep->recv[ring].rx_lock); 2701369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 2711369Sdduvall mutex_enter(bgep->buff[ring].rf_lock); 2721369Sdduvall rw_enter(bgep->errlock, RW_WRITER); 2731369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 2741369Sdduvall mutex_enter(bgep->send[ring].tc_lock); 2751369Sdduvall 2761408Srandyf #ifdef BGE_IPMI_ASF 277*1865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode); 2781408Srandyf #else 279*1865Sdilpreet retval = bge_chip_reset(bgep, B_TRUE); 2801408Srandyf #endif 2811369Sdduvall bge_reinit_rings(bgep); 2821369Sdduvall 2831369Sdduvall /* 2841369Sdduvall * Free the world ... 2851369Sdduvall */ 2861369Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; ) 2871369Sdduvall mutex_exit(bgep->send[ring].tc_lock); 2881369Sdduvall rw_exit(bgep->errlock); 2891369Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; ) 2901369Sdduvall mutex_exit(bgep->buff[ring].rf_lock); 2911369Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; ) 2921369Sdduvall mutex_exit(bgep->recv[ring].rx_lock); 2931369Sdduvall 2941369Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep)); 295*1865Sdilpreet return (retval); 2961369Sdduvall } 2971369Sdduvall 2981369Sdduvall /* 2991369Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings 3001369Sdduvall */ 3011369Sdduvall static void 3021369Sdduvall bge_stop(bge_t *bgep) 3031369Sdduvall { 3041369Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep)); 3051369Sdduvall 3061369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3071369Sdduvall 3081408Srandyf #ifdef BGE_IPMI_ASF 3091408Srandyf if (bgep->asf_enabled) { 3101408Srandyf bgep->asf_pseudostop = B_TRUE; 3111408Srandyf } else { 3121408Srandyf #endif 3131408Srandyf bge_chip_stop(bgep, B_FALSE); 3141408Srandyf #ifdef BGE_IPMI_ASF 3151408Srandyf } 3161408Srandyf #endif 3171369Sdduvall 3181369Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep)); 3191369Sdduvall } 3201369Sdduvall 3211369Sdduvall /* 3221369Sdduvall * bge_start() -- start transmitting/receiving 3231369Sdduvall */ 324*1865Sdilpreet static int 3251369Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys) 3261369Sdduvall { 327*1865Sdilpreet int retval; 328*1865Sdilpreet 3291369Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys)); 3301369Sdduvall 3311369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3321369Sdduvall 3331369Sdduvall /* 3341369Sdduvall * Start chip processing, including enabling interrupts 3351369Sdduvall */ 336*1865Sdilpreet retval = bge_chip_start(bgep, reset_phys); 3371369Sdduvall 3381369Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys)); 339*1865Sdilpreet return (retval); 3401369Sdduvall } 3411369Sdduvall 3421369Sdduvall /* 3431369Sdduvall * bge_restart - restart transmitting/receiving after error or suspend 3441369Sdduvall */ 345*1865Sdilpreet int 3461369Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys) 3471369Sdduvall { 348*1865Sdilpreet int retval = DDI_SUCCESS; 3491369Sdduvall ASSERT(mutex_owned(bgep->genlock)); 3501369Sdduvall 3511408Srandyf #ifdef BGE_IPMI_ASF 3521408Srandyf if (bgep->asf_enabled) { 353*1865Sdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS) 354*1865Sdilpreet retval = DDI_FAILURE; 3551408Srandyf } else 356*1865Sdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS) 357*1865Sdilpreet retval = DDI_FAILURE; 3581408Srandyf #else 359*1865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) 360*1865Sdilpreet retval = DDI_FAILURE; 3611408Srandyf #endif 3621369Sdduvall if (bgep->bge_mac_state == BGE_MAC_STARTED) { 363*1865Sdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS) 364*1865Sdilpreet retval = DDI_FAILURE; 3651369Sdduvall bgep->watchdog = 0; 3661369Sdduvall ddi_trigger_softintr(bgep->resched_id); 3671369Sdduvall } 3681369Sdduvall 3691369Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys)); 370*1865Sdilpreet return (retval); 3711369Sdduvall } 3721369Sdduvall 3731369Sdduvall 3741369Sdduvall /* 3751369Sdduvall * ========== Nemo-required management entry points ========== 3761369Sdduvall */ 3771369Sdduvall 3781369Sdduvall #undef BGE_DBG 3791369Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */ 3801369Sdduvall 3811369Sdduvall /* 3821369Sdduvall * bge_m_stop() -- stop transmitting/receiving 3831369Sdduvall */ 3841369Sdduvall static void 3851369Sdduvall bge_m_stop(void *arg) 3861369Sdduvall { 3871369Sdduvall bge_t *bgep = arg; /* private device info */ 3881369Sdduvall 3891369Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg)); 3901369Sdduvall 3911369Sdduvall /* 3921369Sdduvall * Just stop processing, then record new GLD state 3931369Sdduvall */ 3941369Sdduvall mutex_enter(bgep->genlock); 395*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 396*1865Sdilpreet /* can happen during autorecovery */ 397*1865Sdilpreet mutex_exit(bgep->genlock); 398*1865Sdilpreet return; 399*1865Sdilpreet } 400*1865Sdilpreet 4011369Sdduvall bgep->link_up_msg = bgep->link_down_msg = " (stopped)"; 4021369Sdduvall bge_stop(bgep); 4031369Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED; 4041369Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg)); 405*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 406*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED); 4071369Sdduvall mutex_exit(bgep->genlock); 4081369Sdduvall } 4091369Sdduvall 4101369Sdduvall /* 4111369Sdduvall * bge_m_start() -- start transmitting/receiving 4121369Sdduvall */ 4131369Sdduvall static int 4141369Sdduvall bge_m_start(void *arg) 4151369Sdduvall { 4161369Sdduvall bge_t *bgep = arg; /* private device info */ 4171369Sdduvall 4181369Sdduvall BGE_TRACE(("bge_m_start($%p)", arg)); 4191369Sdduvall 4201369Sdduvall /* 4211369Sdduvall * Start processing and record new GLD state 4221369Sdduvall */ 4231369Sdduvall mutex_enter(bgep->genlock); 424*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 425*1865Sdilpreet /* can happen during autorecovery */ 426*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 427*1865Sdilpreet mutex_exit(bgep->genlock); 428*1865Sdilpreet return (EIO); 429*1865Sdilpreet } 4301408Srandyf #ifdef BGE_IPMI_ASF 4311408Srandyf if (bgep->asf_enabled) { 4321408Srandyf if ((bgep->asf_status == ASF_STAT_RUN) && 4331408Srandyf (bgep->asf_pseudostop)) { 4341408Srandyf 4351408Srandyf bgep->link_up_msg = bgep->link_down_msg 4361408Srandyf = " (initialized)"; 4371408Srandyf bgep->bge_mac_state = BGE_MAC_STARTED; 4381408Srandyf mutex_exit(bgep->genlock); 4391408Srandyf return (0); 4401408Srandyf } 4411408Srandyf } 442*1865Sdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) { 4431408Srandyf #else 444*1865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 4451408Srandyf #endif 446*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 447*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 448*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 449*1865Sdilpreet mutex_exit(bgep->genlock); 450*1865Sdilpreet return (EIO); 451*1865Sdilpreet } 4521369Sdduvall bgep->link_up_msg = bgep->link_down_msg = " (initialized)"; 453*1865Sdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) { 454*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 455*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 456*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 457*1865Sdilpreet mutex_exit(bgep->genlock); 458*1865Sdilpreet return (EIO); 459*1865Sdilpreet } 4601369Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED; 4611369Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg)); 4621408Srandyf 463*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 464*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 465*1865Sdilpreet mutex_exit(bgep->genlock); 466*1865Sdilpreet return (EIO); 467*1865Sdilpreet } 468*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 469*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 470*1865Sdilpreet mutex_exit(bgep->genlock); 471*1865Sdilpreet return (EIO); 472*1865Sdilpreet } 4731408Srandyf #ifdef BGE_IPMI_ASF 4741408Srandyf if (bgep->asf_enabled) { 4751408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 4761408Srandyf /* start ASF heart beat */ 4771408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 4781408Srandyf (void *)bgep, 4791408Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 4801408Srandyf bgep->asf_status = ASF_STAT_RUN; 4811408Srandyf } 4821408Srandyf } 4831408Srandyf #endif 4841369Sdduvall mutex_exit(bgep->genlock); 4851369Sdduvall 4861369Sdduvall return (0); 4871369Sdduvall } 4881369Sdduvall 4891369Sdduvall /* 4901369Sdduvall * bge_m_unicst_set() -- set the physical network address 4911369Sdduvall */ 4921369Sdduvall static int 4931369Sdduvall bge_m_unicst(void *arg, const uint8_t *macaddr) 4941369Sdduvall { 4951369Sdduvall bge_t *bgep = arg; /* private device info */ 4961369Sdduvall 4971369Sdduvall BGE_TRACE(("bge_m_unicst_set($%p, %s)", arg, 4981369Sdduvall ether_sprintf((void *)macaddr))); 4991369Sdduvall 5001369Sdduvall /* 5011369Sdduvall * Remember the new current address in the driver state 5021369Sdduvall * Sync the chip's idea of the address too ... 5031369Sdduvall */ 5041369Sdduvall mutex_enter(bgep->genlock); 505*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 506*1865Sdilpreet /* can happen during autorecovery */ 507*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 508*1865Sdilpreet mutex_exit(bgep->genlock); 509*1865Sdilpreet return (EIO); 510*1865Sdilpreet } 5111369Sdduvall ethaddr_copy(macaddr, bgep->curr_addr.addr); 5121408Srandyf #ifdef BGE_IPMI_ASF 513*1865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 514*1865Sdilpreet #else 515*1865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 516*1865Sdilpreet #endif 517*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 518*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 519*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 520*1865Sdilpreet mutex_exit(bgep->genlock); 521*1865Sdilpreet return (EIO); 522*1865Sdilpreet } 523*1865Sdilpreet #ifdef BGE_IPMI_ASF 5241408Srandyf if (bgep->asf_enabled) { 5251408Srandyf /* 5261408Srandyf * The above bge_chip_sync() function wrote the ethernet MAC 5271408Srandyf * addresses registers which destroyed the IPMI/ASF sideband. 5281408Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work. 5291408Srandyf */ 5301408Srandyf if (bgep->asf_status == ASF_STAT_RUN) { 5311408Srandyf /* 5321408Srandyf * We must stop ASF heart beat before bge_chip_stop(), 5331408Srandyf * otherwise some computers (ex. IBM HS20 blade server) 5341408Srandyf * may crash. 5351408Srandyf */ 5361408Srandyf bge_asf_update_status(bgep); 5371408Srandyf bge_asf_stop_timer(bgep); 5381408Srandyf bgep->asf_status = ASF_STAT_STOP; 5391408Srandyf 5401408Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET); 5411408Srandyf } 542*1865Sdilpreet bge_chip_stop(bgep, B_FALSE); 5431408Srandyf 544*1865Sdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) { 545*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 546*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 547*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 548*1865Sdilpreet DDI_SERVICE_DEGRADED); 549*1865Sdilpreet mutex_exit(bgep->genlock); 550*1865Sdilpreet return (EIO); 551*1865Sdilpreet } 552*1865Sdilpreet 5531408Srandyf /* 5541408Srandyf * Start our ASF heartbeat counter as soon as possible. 5551408Srandyf */ 5561408Srandyf if (bgep->asf_status != ASF_STAT_RUN) { 5571408Srandyf /* start ASF heart beat */ 5581408Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat, 5591408Srandyf (void *)bgep, 5601408Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL)); 5611408Srandyf bgep->asf_status = ASF_STAT_RUN; 5621408Srandyf } 5631408Srandyf } 5641408Srandyf #endif 5651369Sdduvall BGE_DEBUG(("bge_m_unicst_set($%p) done", arg)); 566*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 567*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 568*1865Sdilpreet mutex_exit(bgep->genlock); 569*1865Sdilpreet return (EIO); 570*1865Sdilpreet } 571*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 572*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 573*1865Sdilpreet mutex_exit(bgep->genlock); 574*1865Sdilpreet return (EIO); 575*1865Sdilpreet } 5761369Sdduvall mutex_exit(bgep->genlock); 5771369Sdduvall 5781369Sdduvall return (0); 5791369Sdduvall } 5801369Sdduvall 5811369Sdduvall /* 5821369Sdduvall * Compute the index of the required bit in the multicast hash map. 5831369Sdduvall * This must mirror the way the hardware actually does it! 5841369Sdduvall * See Broadcom document 570X-PG102-R page 125. 5851369Sdduvall */ 5861369Sdduvall static uint32_t 5871369Sdduvall bge_hash_index(const uint8_t *mca) 5881369Sdduvall { 5891369Sdduvall uint32_t hash; 5901369Sdduvall 5911369Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table); 5921369Sdduvall 5931369Sdduvall return (hash); 5941369Sdduvall } 5951369Sdduvall 5961369Sdduvall /* 5971369Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address 5981369Sdduvall */ 5991369Sdduvall static int 6001369Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 6011369Sdduvall { 6021369Sdduvall bge_t *bgep = arg; /* private device info */ 6031369Sdduvall uint32_t hash; 6041369Sdduvall uint32_t index; 6051369Sdduvall uint32_t word; 6061369Sdduvall uint32_t bit; 6071369Sdduvall uint8_t *refp; 6081369Sdduvall 6091369Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg, 6101369Sdduvall (add) ? "add" : "remove", ether_sprintf((void *)mca))); 6111369Sdduvall 6121369Sdduvall /* 6131369Sdduvall * Precalculate all required masks, pointers etc ... 6141369Sdduvall */ 6151369Sdduvall hash = bge_hash_index(mca); 6161369Sdduvall index = hash % BGE_HASH_TABLE_SIZE; 6171369Sdduvall word = index/32u; 6181369Sdduvall bit = 1 << (index % 32u); 6191369Sdduvall refp = &bgep->mcast_refs[index]; 6201369Sdduvall 6211369Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d", 6221369Sdduvall hash, index, word, bit, *refp)); 6231369Sdduvall 6241369Sdduvall /* 6251369Sdduvall * We must set the appropriate bit in the hash map (and the 6261369Sdduvall * corresponding h/w register) when the refcount goes from 0 6271369Sdduvall * to >0, and clear it when the last ref goes away (refcount 6281369Sdduvall * goes from >0 back to 0). If we change the hash map, we 6291369Sdduvall * must also update the chip's hardware map registers. 6301369Sdduvall */ 6311369Sdduvall mutex_enter(bgep->genlock); 632*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 633*1865Sdilpreet /* can happen during autorecovery */ 634*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 635*1865Sdilpreet mutex_exit(bgep->genlock); 636*1865Sdilpreet return (EIO); 637*1865Sdilpreet } 6381369Sdduvall if (add) { 6391369Sdduvall if ((*refp)++ == 0) { 6401369Sdduvall bgep->mcast_hash[word] |= bit; 6411408Srandyf #ifdef BGE_IPMI_ASF 642*1865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 6431408Srandyf #else 644*1865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6451408Srandyf #endif 646*1865Sdilpreet (void) bge_check_acc_handle(bgep, 647*1865Sdilpreet bgep->cfg_handle); 648*1865Sdilpreet (void) bge_check_acc_handle(bgep, 649*1865Sdilpreet bgep->io_handle); 650*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 651*1865Sdilpreet DDI_SERVICE_DEGRADED); 652*1865Sdilpreet mutex_exit(bgep->genlock); 653*1865Sdilpreet return (EIO); 654*1865Sdilpreet } 6551369Sdduvall } 6561369Sdduvall } else { 6571369Sdduvall if (--(*refp) == 0) { 6581369Sdduvall bgep->mcast_hash[word] &= ~bit; 6591408Srandyf #ifdef BGE_IPMI_ASF 660*1865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 6611408Srandyf #else 662*1865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 6631408Srandyf #endif 664*1865Sdilpreet (void) bge_check_acc_handle(bgep, 665*1865Sdilpreet bgep->cfg_handle); 666*1865Sdilpreet (void) bge_check_acc_handle(bgep, 667*1865Sdilpreet bgep->io_handle); 668*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 669*1865Sdilpreet DDI_SERVICE_DEGRADED); 670*1865Sdilpreet mutex_exit(bgep->genlock); 671*1865Sdilpreet return (EIO); 672*1865Sdilpreet } 6731369Sdduvall } 6741369Sdduvall } 6751369Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg)); 676*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 677*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 678*1865Sdilpreet mutex_exit(bgep->genlock); 679*1865Sdilpreet return (EIO); 680*1865Sdilpreet } 681*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 682*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 683*1865Sdilpreet mutex_exit(bgep->genlock); 684*1865Sdilpreet return (EIO); 685*1865Sdilpreet } 6861369Sdduvall mutex_exit(bgep->genlock); 6871369Sdduvall 6881369Sdduvall return (0); 6891369Sdduvall } 6901369Sdduvall 6911369Sdduvall /* 6921369Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board 6931369Sdduvall * 6941369Sdduvall * Program the hardware to enable/disable promiscuous and/or 6951369Sdduvall * receive-all-multicast modes. 6961369Sdduvall */ 6971369Sdduvall static int 6981369Sdduvall bge_m_promisc(void *arg, boolean_t on) 6991369Sdduvall { 7001369Sdduvall bge_t *bgep = arg; 7011369Sdduvall 7021369Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on)); 7031369Sdduvall 7041369Sdduvall /* 7051369Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w 7061369Sdduvall */ 7071369Sdduvall mutex_enter(bgep->genlock); 708*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 709*1865Sdilpreet /* can happen during autorecovery */ 710*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 711*1865Sdilpreet mutex_exit(bgep->genlock); 712*1865Sdilpreet return (EIO); 713*1865Sdilpreet } 7141369Sdduvall bgep->promisc = on; 7151408Srandyf #ifdef BGE_IPMI_ASF 716*1865Sdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { 7171408Srandyf #else 718*1865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 7191408Srandyf #endif 720*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 721*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 722*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 723*1865Sdilpreet mutex_exit(bgep->genlock); 724*1865Sdilpreet return (EIO); 725*1865Sdilpreet } 7261369Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg)); 727*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 728*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 729*1865Sdilpreet mutex_exit(bgep->genlock); 730*1865Sdilpreet return (EIO); 731*1865Sdilpreet } 732*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 733*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 734*1865Sdilpreet mutex_exit(bgep->genlock); 735*1865Sdilpreet return (EIO); 736*1865Sdilpreet } 7371369Sdduvall mutex_exit(bgep->genlock); 7381369Sdduvall return (0); 7391369Sdduvall } 7401369Sdduvall 7411369Sdduvall /* 7421369Sdduvall * Loopback ioctl code 7431369Sdduvall */ 7441369Sdduvall 7451369Sdduvall static lb_property_t loopmodes[] = { 7461369Sdduvall { normal, "normal", BGE_LOOP_NONE }, 7471369Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 }, 7481369Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 }, 7491369Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 }, 7501369Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY }, 7511369Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC } 7521369Sdduvall }; 7531369Sdduvall 7541369Sdduvall static enum ioc_reply 7551369Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode) 7561369Sdduvall { 7571369Sdduvall const char *msg; 7581369Sdduvall 7591369Sdduvall /* 7601369Sdduvall * If the mode isn't being changed, there's nothing to do ... 7611369Sdduvall */ 7621369Sdduvall if (mode == bgep->param_loop_mode) 7631369Sdduvall return (IOC_ACK); 7641369Sdduvall 7651369Sdduvall /* 7661369Sdduvall * Validate the requested mode and prepare a suitable message 7671369Sdduvall * to explain the link down/up cycle that the change will 7681369Sdduvall * probably induce ... 7691369Sdduvall */ 7701369Sdduvall switch (mode) { 7711369Sdduvall default: 7721369Sdduvall return (IOC_INVAL); 7731369Sdduvall 7741369Sdduvall case BGE_LOOP_NONE: 7751369Sdduvall msg = " (loopback disabled)"; 7761369Sdduvall break; 7771369Sdduvall 7781369Sdduvall case BGE_LOOP_EXTERNAL_1000: 7791369Sdduvall case BGE_LOOP_EXTERNAL_100: 7801369Sdduvall case BGE_LOOP_EXTERNAL_10: 7811369Sdduvall msg = " (external loopback selected)"; 7821369Sdduvall break; 7831369Sdduvall 7841369Sdduvall case BGE_LOOP_INTERNAL_PHY: 7851369Sdduvall msg = " (PHY internal loopback selected)"; 7861369Sdduvall break; 7871369Sdduvall 7881369Sdduvall case BGE_LOOP_INTERNAL_MAC: 7891369Sdduvall msg = " (MAC internal loopback selected)"; 7901369Sdduvall break; 7911369Sdduvall } 7921369Sdduvall 7931369Sdduvall /* 7941369Sdduvall * All OK; tell the caller to reprogram 7951369Sdduvall * the PHY and/or MAC for the new mode ... 7961369Sdduvall */ 7971369Sdduvall bgep->link_down_msg = bgep->link_up_msg = msg; 7981369Sdduvall bgep->param_loop_mode = mode; 7991369Sdduvall return (IOC_RESTART_ACK); 8001369Sdduvall } 8011369Sdduvall 8021369Sdduvall static enum ioc_reply 8031369Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) 8041369Sdduvall { 8051369Sdduvall lb_info_sz_t *lbsp; 8061369Sdduvall lb_property_t *lbpp; 8071369Sdduvall uint32_t *lbmp; 8081369Sdduvall int cmd; 8091369Sdduvall 8101369Sdduvall _NOTE(ARGUNUSED(wq)) 8111369Sdduvall 8121369Sdduvall /* 8131369Sdduvall * Validate format of ioctl 8141369Sdduvall */ 8151369Sdduvall if (mp->b_cont == NULL) 8161369Sdduvall return (IOC_INVAL); 8171369Sdduvall 8181369Sdduvall cmd = iocp->ioc_cmd; 8191369Sdduvall switch (cmd) { 8201369Sdduvall default: 8211369Sdduvall /* NOTREACHED */ 8221369Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd); 8231369Sdduvall return (IOC_INVAL); 8241369Sdduvall 8251369Sdduvall case LB_GET_INFO_SIZE: 8261369Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t)) 8271369Sdduvall return (IOC_INVAL); 8281369Sdduvall lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 8291369Sdduvall *lbsp = sizeof (loopmodes); 8301369Sdduvall return (IOC_REPLY); 8311369Sdduvall 8321369Sdduvall case LB_GET_INFO: 8331369Sdduvall if (iocp->ioc_count != sizeof (loopmodes)) 8341369Sdduvall return (IOC_INVAL); 8351369Sdduvall lbpp = (lb_property_t *)mp->b_cont->b_rptr; 8361369Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes)); 8371369Sdduvall return (IOC_REPLY); 8381369Sdduvall 8391369Sdduvall case LB_GET_MODE: 8401369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 8411369Sdduvall return (IOC_INVAL); 8421369Sdduvall lbmp = (uint32_t *)mp->b_cont->b_rptr; 8431369Sdduvall *lbmp = bgep->param_loop_mode; 8441369Sdduvall return (IOC_REPLY); 8451369Sdduvall 8461369Sdduvall case LB_SET_MODE: 8471369Sdduvall if (iocp->ioc_count != sizeof (uint32_t)) 8481369Sdduvall return (IOC_INVAL); 8491369Sdduvall lbmp = (uint32_t *)mp->b_cont->b_rptr; 8501369Sdduvall return (bge_set_loop_mode(bgep, *lbmp)); 8511369Sdduvall } 8521369Sdduvall } 8531369Sdduvall 8541369Sdduvall /* 8551369Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones. 8561369Sdduvall */ 8571369Sdduvall static void 8581369Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 8591369Sdduvall { 8601369Sdduvall bge_t *bgep = arg; 8611369Sdduvall struct iocblk *iocp; 8621369Sdduvall enum ioc_reply status; 8631369Sdduvall boolean_t need_privilege; 8641369Sdduvall int err; 8651369Sdduvall int cmd; 8661369Sdduvall 8671369Sdduvall /* 8681369Sdduvall * Validate the command before bothering with the mutex ... 8691369Sdduvall */ 8701369Sdduvall iocp = (struct iocblk *)mp->b_rptr; 8711369Sdduvall iocp->ioc_error = 0; 8721369Sdduvall need_privilege = B_TRUE; 8731369Sdduvall cmd = iocp->ioc_cmd; 8741369Sdduvall switch (cmd) { 8751369Sdduvall default: 8761369Sdduvall miocnak(wq, mp, 0, EINVAL); 8771369Sdduvall return; 8781369Sdduvall 8791369Sdduvall case BGE_MII_READ: 8801369Sdduvall case BGE_MII_WRITE: 8811369Sdduvall case BGE_SEE_READ: 8821369Sdduvall case BGE_SEE_WRITE: 8831369Sdduvall case BGE_DIAG: 8841369Sdduvall case BGE_PEEK: 8851369Sdduvall case BGE_POKE: 8861369Sdduvall case BGE_PHY_RESET: 8871369Sdduvall case BGE_SOFT_RESET: 8881369Sdduvall case BGE_HARD_RESET: 8891369Sdduvall break; 8901369Sdduvall 8911369Sdduvall case LB_GET_INFO_SIZE: 8921369Sdduvall case LB_GET_INFO: 8931369Sdduvall case LB_GET_MODE: 8941369Sdduvall need_privilege = B_FALSE; 8951369Sdduvall /* FALLTHRU */ 8961369Sdduvall case LB_SET_MODE: 8971369Sdduvall break; 8981369Sdduvall 8991369Sdduvall case ND_GET: 9001369Sdduvall need_privilege = B_FALSE; 9011369Sdduvall /* FALLTHRU */ 9021369Sdduvall case ND_SET: 9031369Sdduvall break; 9041369Sdduvall } 9051369Sdduvall 9061369Sdduvall if (need_privilege) { 9071369Sdduvall /* 9081369Sdduvall * Check for specific net_config privilege on Solaris 10+. 9091369Sdduvall * Otherwise just check for root access ... 9101369Sdduvall */ 9111369Sdduvall if (secpolicy_net_config != NULL) 9121369Sdduvall err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 9131369Sdduvall else 9141369Sdduvall err = drv_priv(iocp->ioc_cr); 9151369Sdduvall if (err != 0) { 9161369Sdduvall miocnak(wq, mp, 0, err); 9171369Sdduvall return; 9181369Sdduvall } 9191369Sdduvall } 9201369Sdduvall 9211369Sdduvall mutex_enter(bgep->genlock); 922*1865Sdilpreet if (!(bgep->progress & PROGRESS_INTR)) { 923*1865Sdilpreet /* can happen during autorecovery */ 924*1865Sdilpreet mutex_exit(bgep->genlock); 925*1865Sdilpreet miocnak(wq, mp, 0, EIO); 926*1865Sdilpreet return; 927*1865Sdilpreet } 9281369Sdduvall 9291369Sdduvall switch (cmd) { 9301369Sdduvall default: 9311369Sdduvall _NOTE(NOTREACHED) 9321369Sdduvall status = IOC_INVAL; 9331369Sdduvall break; 9341369Sdduvall 9351369Sdduvall case BGE_MII_READ: 9361369Sdduvall case BGE_MII_WRITE: 9371369Sdduvall case BGE_SEE_READ: 9381369Sdduvall case BGE_SEE_WRITE: 9391369Sdduvall case BGE_DIAG: 9401369Sdduvall case BGE_PEEK: 9411369Sdduvall case BGE_POKE: 9421369Sdduvall case BGE_PHY_RESET: 9431369Sdduvall case BGE_SOFT_RESET: 9441369Sdduvall case BGE_HARD_RESET: 9451369Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp); 9461369Sdduvall break; 9471369Sdduvall 9481369Sdduvall case LB_GET_INFO_SIZE: 9491369Sdduvall case LB_GET_INFO: 9501369Sdduvall case LB_GET_MODE: 9511369Sdduvall case LB_SET_MODE: 9521369Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp); 9531369Sdduvall break; 9541369Sdduvall 9551369Sdduvall case ND_GET: 9561369Sdduvall case ND_SET: 9571369Sdduvall status = bge_nd_ioctl(bgep, wq, mp, iocp); 9581369Sdduvall break; 9591369Sdduvall } 9601369Sdduvall 9611369Sdduvall /* 9621369Sdduvall * Do we need to reprogram the PHY and/or the MAC? 9631369Sdduvall * Do it now, while we still have the mutex. 9641369Sdduvall * 9651369Sdduvall * Note: update the PHY first, 'cos it controls the 9661369Sdduvall * speed/duplex parameters that the MAC code uses. 9671369Sdduvall */ 9681369Sdduvall switch (status) { 9691369Sdduvall case IOC_RESTART_REPLY: 9701369Sdduvall case IOC_RESTART_ACK: 971*1865Sdilpreet if (bge_phys_update(bgep) != DDI_SUCCESS) { 972*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 973*1865Sdilpreet DDI_SERVICE_DEGRADED); 974*1865Sdilpreet status = IOC_INVAL; 975*1865Sdilpreet } 9761408Srandyf #ifdef BGE_IPMI_ASF 977*1865Sdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) { 9781408Srandyf #else 979*1865Sdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) { 9801408Srandyf #endif 981*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 982*1865Sdilpreet DDI_SERVICE_DEGRADED); 983*1865Sdilpreet status = IOC_INVAL; 984*1865Sdilpreet } 9851369Sdduvall if (bgep->intr_type == DDI_INTR_TYPE_MSI) 9861369Sdduvall bge_chip_msi_trig(bgep); 9871369Sdduvall break; 9881369Sdduvall } 9891369Sdduvall 990*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 991*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 992*1865Sdilpreet status = IOC_INVAL; 993*1865Sdilpreet } 994*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 995*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 996*1865Sdilpreet status = IOC_INVAL; 997*1865Sdilpreet } 9981369Sdduvall mutex_exit(bgep->genlock); 9991369Sdduvall 10001369Sdduvall /* 10011369Sdduvall * Finally, decide how to reply 10021369Sdduvall */ 10031369Sdduvall switch (status) { 10041369Sdduvall default: 10051369Sdduvall case IOC_INVAL: 10061369Sdduvall /* 10071369Sdduvall * Error, reply with a NAK and EINVAL or the specified error 10081369Sdduvall */ 10091369Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 10101369Sdduvall EINVAL : iocp->ioc_error); 10111369Sdduvall break; 10121369Sdduvall 10131369Sdduvall case IOC_DONE: 10141369Sdduvall /* 10151369Sdduvall * OK, reply already sent 10161369Sdduvall */ 10171369Sdduvall break; 10181369Sdduvall 10191369Sdduvall case IOC_RESTART_ACK: 10201369Sdduvall case IOC_ACK: 10211369Sdduvall /* 10221369Sdduvall * OK, reply with an ACK 10231369Sdduvall */ 10241369Sdduvall miocack(wq, mp, 0, 0); 10251369Sdduvall break; 10261369Sdduvall 10271369Sdduvall case IOC_RESTART_REPLY: 10281369Sdduvall case IOC_REPLY: 10291369Sdduvall /* 10301369Sdduvall * OK, send prepared reply as ACK or NAK 10311369Sdduvall */ 10321369Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ? 10331369Sdduvall M_IOCACK : M_IOCNAK; 10341369Sdduvall qreply(wq, mp); 10351369Sdduvall break; 10361369Sdduvall } 10371369Sdduvall } 10381369Sdduvall 10391369Sdduvall static void 10401369Sdduvall bge_m_resources(void *arg) 10411369Sdduvall { 10421369Sdduvall bge_t *bgep = arg; 10431369Sdduvall recv_ring_t *rrp; 10441369Sdduvall mac_rx_fifo_t mrf; 10451369Sdduvall int ring; 10461369Sdduvall 10471369Sdduvall mutex_enter(bgep->genlock); 10481369Sdduvall 10491369Sdduvall /* 10501369Sdduvall * Register Rx rings as resources and save mac 10511369Sdduvall * resource id for future reference 10521369Sdduvall */ 10531369Sdduvall mrf.mrf_type = MAC_RX_FIFO; 10541369Sdduvall mrf.mrf_blank = bge_chip_blank; 10551369Sdduvall mrf.mrf_arg = (void *)bgep; 10561369Sdduvall mrf.mrf_normal_blank_time = bge_rx_ticks_norm; 10571369Sdduvall mrf.mrf_normal_pkt_count = bge_rx_count_norm; 10581369Sdduvall 10591369Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ring++) { 10601369Sdduvall rrp = &bgep->recv[ring]; 10611369Sdduvall rrp->handle = mac_resource_add(bgep->macp, 10621369Sdduvall (mac_resource_t *)&mrf); 10631369Sdduvall } 10641369Sdduvall 10651369Sdduvall mutex_exit(bgep->genlock); 10661369Sdduvall } 10671369Sdduvall 10681369Sdduvall /* 10691369Sdduvall * ========== Per-instance setup/teardown code ========== 10701369Sdduvall */ 10711369Sdduvall 10721369Sdduvall #undef BGE_DBG 10731369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 10741369Sdduvall 10751369Sdduvall /* 10761369Sdduvall * Utility routine to carve a slice off a chunk of allocated memory, 10771369Sdduvall * updating the chunk descriptor accordingly. The size of the slice 10781369Sdduvall * is given by the product of the <qty> and <size> parameters. 10791369Sdduvall */ 10801369Sdduvall static void 10811369Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 10821369Sdduvall uint32_t qty, uint32_t size) 10831369Sdduvall { 10841369Sdduvall static uint32_t sequence = 0xbcd5704a; 10851369Sdduvall size_t totsize; 10861369Sdduvall 10871369Sdduvall totsize = qty*size; 10881369Sdduvall ASSERT(size >= 0); 10891369Sdduvall ASSERT(totsize <= chunk->alength); 10901369Sdduvall 10911369Sdduvall *slice = *chunk; 10921369Sdduvall slice->nslots = qty; 10931369Sdduvall slice->size = size; 10941369Sdduvall slice->alength = totsize; 10951369Sdduvall slice->token = ++sequence; 10961369Sdduvall 10971369Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 10981369Sdduvall chunk->alength -= totsize; 10991369Sdduvall chunk->offset += totsize; 11001369Sdduvall chunk->cookie.dmac_laddress += totsize; 11011369Sdduvall chunk->cookie.dmac_size -= totsize; 11021369Sdduvall } 11031369Sdduvall 11041369Sdduvall /* 11051369Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using 11061369Sdduvall * the information in the <dma_area> descriptors that it contains 11071369Sdduvall * to set up all the other fields. This routine should be called 11081369Sdduvall * only once for each ring. 11091369Sdduvall */ 11101369Sdduvall static void 11111369Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring) 11121369Sdduvall { 11131369Sdduvall buff_ring_t *brp; 11141369Sdduvall bge_status_t *bsp; 11151369Sdduvall sw_rbd_t *srbdp; 11161369Sdduvall dma_area_t pbuf; 11171369Sdduvall uint32_t bufsize; 11181369Sdduvall uint32_t nslots; 11191369Sdduvall uint32_t slot; 11201369Sdduvall uint32_t split; 11211369Sdduvall 11221369Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = { 11231369Sdduvall NIC_MEM_SHADOW_BUFF_STD, 11241369Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO, 11251369Sdduvall NIC_MEM_SHADOW_BUFF_MINI 11261369Sdduvall }; 11271369Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = { 11281369Sdduvall RECV_STD_PROD_INDEX_REG, 11291369Sdduvall RECV_JUMBO_PROD_INDEX_REG, 11301369Sdduvall RECV_MINI_PROD_INDEX_REG 11311369Sdduvall }; 11321369Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = { 11331369Sdduvall STATUS_STD_BUFF_CONS_INDEX, 11341369Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX, 11351369Sdduvall STATUS_MINI_BUFF_CONS_INDEX 11361369Sdduvall }; 11371369Sdduvall 11381369Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)", 11391369Sdduvall (void *)bgep, ring)); 11401369Sdduvall 11411369Sdduvall brp = &bgep->buff[ring]; 11421369Sdduvall nslots = brp->desc.nslots; 11431369Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT); 11441369Sdduvall bufsize = brp->buf[0].size; 11451369Sdduvall 11461369Sdduvall /* 11471369Sdduvall * Set up the copy of the h/w RCB 11481369Sdduvall * 11491369Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len 11501369Sdduvall * field holds the number of slots), in a Receive Buffer Ring 11511369Sdduvall * this field indicates the size of each buffer in the ring. 11521369Sdduvall */ 11531369Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress; 11541369Sdduvall brp->hw_rcb.max_len = bufsize; 11551369Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 11561369Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring]; 11571369Sdduvall 11581369Sdduvall /* 11591369Sdduvall * Other one-off initialisation of per-ring data 11601369Sdduvall */ 11611369Sdduvall brp->bgep = bgep; 11621369Sdduvall bsp = DMA_VPTR(bgep->status_block); 11631369Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]]; 11641369Sdduvall brp->chip_mbx_reg = mailbox_regs[ring]; 11651369Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER, 11661369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 11671369Sdduvall 11681369Sdduvall /* 11691369Sdduvall * Allocate the array of s/w Receive Buffer Descriptors 11701369Sdduvall */ 11711369Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP); 11721369Sdduvall brp->sw_rbds = srbdp; 11731369Sdduvall 11741369Sdduvall /* 11751369Sdduvall * Now initialise each array element once and for all 11761369Sdduvall */ 11771369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 11781369Sdduvall pbuf = brp->buf[split]; 11791369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot) 11801369Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize); 11811369Sdduvall ASSERT(pbuf.alength == 0); 11821369Sdduvall } 11831369Sdduvall } 11841369Sdduvall 11851369Sdduvall /* 11861369Sdduvall * Clean up initialisation done above before the memory is freed 11871369Sdduvall */ 11881369Sdduvall static void 11891369Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring) 11901369Sdduvall { 11911369Sdduvall buff_ring_t *brp; 11921369Sdduvall sw_rbd_t *srbdp; 11931369Sdduvall 11941369Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)", 11951369Sdduvall (void *)bgep, ring)); 11961369Sdduvall 11971369Sdduvall brp = &bgep->buff[ring]; 11981369Sdduvall srbdp = brp->sw_rbds; 11991369Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp)); 12001369Sdduvall 12011369Sdduvall mutex_destroy(brp->rf_lock); 12021369Sdduvall } 12031369Sdduvall 12041369Sdduvall /* 12051369Sdduvall * Initialise the specified Receive (Return) Ring, using the 12061369Sdduvall * information in the <dma_area> descriptors that it contains 12071369Sdduvall * to set up all the other fields. This routine should be called 12081369Sdduvall * only once for each ring. 12091369Sdduvall */ 12101369Sdduvall static void 12111369Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring) 12121369Sdduvall { 12131369Sdduvall recv_ring_t *rrp; 12141369Sdduvall bge_status_t *bsp; 12151369Sdduvall uint32_t nslots; 12161369Sdduvall 12171369Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)", 12181369Sdduvall (void *)bgep, ring)); 12191369Sdduvall 12201369Sdduvall /* 12211369Sdduvall * The chip architecture requires that receive return rings have 12221369Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103. 12231369Sdduvall */ 12241369Sdduvall rrp = &bgep->recv[ring]; 12251369Sdduvall nslots = rrp->desc.nslots; 12261369Sdduvall ASSERT(nslots == 0 || nslots == 512 || 12271369Sdduvall nslots == 1024 || nslots == 2048); 12281369Sdduvall 12291369Sdduvall /* 12301369Sdduvall * Set up the copy of the h/w RCB 12311369Sdduvall */ 12321369Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress; 12331369Sdduvall rrp->hw_rcb.max_len = nslots; 12341369Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 12351369Sdduvall rrp->hw_rcb.nic_ring_addr = 0; 12361369Sdduvall 12371369Sdduvall /* 12381369Sdduvall * Other one-off initialisation of per-ring data 12391369Sdduvall */ 12401369Sdduvall rrp->bgep = bgep; 12411369Sdduvall bsp = DMA_VPTR(bgep->status_block); 12421369Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring); 12431369Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring); 12441369Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER, 12451369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 12461369Sdduvall } 12471369Sdduvall 12481369Sdduvall 12491369Sdduvall /* 12501369Sdduvall * Clean up initialisation done above before the memory is freed 12511369Sdduvall */ 12521369Sdduvall static void 12531369Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring) 12541369Sdduvall { 12551369Sdduvall recv_ring_t *rrp; 12561369Sdduvall 12571369Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)", 12581369Sdduvall (void *)bgep, ring)); 12591369Sdduvall 12601369Sdduvall rrp = &bgep->recv[ring]; 12611369Sdduvall if (rrp->rx_softint) 12621369Sdduvall ddi_remove_softintr(rrp->rx_softint); 12631369Sdduvall mutex_destroy(rrp->rx_lock); 12641369Sdduvall } 12651369Sdduvall 12661369Sdduvall /* 12671369Sdduvall * Initialise the specified Send Ring, using the information in the 12681369Sdduvall * <dma_area> descriptors that it contains to set up all the other 12691369Sdduvall * fields. This routine should be called only once for each ring. 12701369Sdduvall */ 12711369Sdduvall static void 12721369Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring) 12731369Sdduvall { 12741369Sdduvall send_ring_t *srp; 12751369Sdduvall bge_status_t *bsp; 12761369Sdduvall sw_sbd_t *ssbdp; 12771369Sdduvall dma_area_t desc; 12781369Sdduvall dma_area_t pbuf; 12791369Sdduvall uint32_t nslots; 12801369Sdduvall uint32_t slot; 12811369Sdduvall uint32_t split; 12821369Sdduvall 12831369Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)", 12841369Sdduvall (void *)bgep, ring)); 12851369Sdduvall 12861369Sdduvall /* 12871369Sdduvall * The chip architecture requires that host-based send rings 12881369Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56. 12891369Sdduvall */ 12901369Sdduvall srp = &bgep->send[ring]; 12911369Sdduvall nslots = srp->desc.nslots; 12921369Sdduvall ASSERT(nslots == 0 || nslots == 512); 12931369Sdduvall 12941369Sdduvall /* 12951369Sdduvall * Set up the copy of the h/w RCB 12961369Sdduvall */ 12971369Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress; 12981369Sdduvall srp->hw_rcb.max_len = nslots; 12991369Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED; 13001369Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots); 13011369Sdduvall 13021369Sdduvall /* 13031369Sdduvall * Other one-off initialisation of per-ring data 13041369Sdduvall */ 13051369Sdduvall srp->bgep = bgep; 13061369Sdduvall bsp = DMA_VPTR(bgep->status_block); 13071369Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring); 13081369Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring); 13091369Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 13101369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 13111369Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 13121369Sdduvall DDI_INTR_PRI(bgep->intr_pri)); 13131369Sdduvall 13141369Sdduvall /* 13151369Sdduvall * Allocate the array of s/w Send Buffer Descriptors 13161369Sdduvall */ 13171369Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 13181369Sdduvall srp->sw_sbds = ssbdp; 13191369Sdduvall 13201369Sdduvall /* 13211369Sdduvall * Now initialise each array element once and for all 13221369Sdduvall */ 13231369Sdduvall desc = srp->desc; 13241369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 13251369Sdduvall pbuf = srp->buf[split]; 13261369Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++ssbdp, ++slot) { 13271369Sdduvall bge_slice_chunk(&ssbdp->desc, &desc, 1, 13281369Sdduvall sizeof (bge_sbd_t)); 13291369Sdduvall bge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 13301369Sdduvall bgep->chipid.snd_buff_size); 13311369Sdduvall } 13321369Sdduvall ASSERT(pbuf.alength == 0); 13331369Sdduvall } 13341369Sdduvall ASSERT(desc.alength == 0); 13351369Sdduvall } 13361369Sdduvall 13371369Sdduvall /* 13381369Sdduvall * Clean up initialisation done above before the memory is freed 13391369Sdduvall */ 13401369Sdduvall static void 13411369Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring) 13421369Sdduvall { 13431369Sdduvall send_ring_t *srp; 13441369Sdduvall sw_sbd_t *ssbdp; 13451369Sdduvall 13461369Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)", 13471369Sdduvall (void *)bgep, ring)); 13481369Sdduvall 13491369Sdduvall srp = &bgep->send[ring]; 13501369Sdduvall ssbdp = srp->sw_sbds; 13511369Sdduvall kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 13521369Sdduvall 13531369Sdduvall mutex_destroy(srp->tx_lock); 13541369Sdduvall mutex_destroy(srp->tc_lock); 13551369Sdduvall } 13561369Sdduvall 13571369Sdduvall /* 13581369Sdduvall * Initialise all transmit, receive, and buffer rings. 13591369Sdduvall */ 1360*1865Sdilpreet void 13611369Sdduvall bge_init_rings(bge_t *bgep) 13621369Sdduvall { 13631369Sdduvall uint64_t ring; 13641369Sdduvall 13651369Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep)); 13661369Sdduvall 13671369Sdduvall /* 13681369Sdduvall * Perform one-off initialisation of each ring ... 13691369Sdduvall */ 13701369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 13711369Sdduvall bge_init_send_ring(bgep, ring); 13721369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 13731369Sdduvall bge_init_recv_ring(bgep, ring); 13741369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 13751369Sdduvall bge_init_buff_ring(bgep, ring); 13761369Sdduvall } 13771369Sdduvall 13781369Sdduvall /* 13791369Sdduvall * Undo the work of bge_init_rings() above before the memory is freed 13801369Sdduvall */ 1381*1865Sdilpreet void 13821369Sdduvall bge_fini_rings(bge_t *bgep) 13831369Sdduvall { 13841369Sdduvall uint64_t ring; 13851369Sdduvall 13861369Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep)); 13871369Sdduvall 13881369Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring) 13891369Sdduvall bge_fini_buff_ring(bgep, ring); 13901369Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring) 13911369Sdduvall bge_fini_recv_ring(bgep, ring); 13921369Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring) 13931369Sdduvall bge_fini_send_ring(bgep, ring); 13941369Sdduvall } 13951369Sdduvall 13961369Sdduvall /* 13971369Sdduvall * Allocate an area of memory and a DMA handle for accessing it 13981369Sdduvall */ 13991369Sdduvall static int 14001369Sdduvall bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p, 14011369Sdduvall uint_t dma_flags, dma_area_t *dma_p) 14021369Sdduvall { 14031369Sdduvall caddr_t va; 14041369Sdduvall int err; 14051369Sdduvall 14061369Sdduvall BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 14071369Sdduvall (void *)bgep, memsize, attr_p, dma_flags, dma_p)); 14081369Sdduvall 14091369Sdduvall /* 14101369Sdduvall * Allocate handle 14111369Sdduvall */ 14121369Sdduvall err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr, 14131369Sdduvall DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 14141369Sdduvall if (err != DDI_SUCCESS) 14151369Sdduvall return (DDI_FAILURE); 14161369Sdduvall 14171369Sdduvall /* 14181369Sdduvall * Allocate memory 14191369Sdduvall */ 14201369Sdduvall err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 14211369Sdduvall dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 14221369Sdduvall DDI_DMA_SLEEP, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 14231369Sdduvall if (err != DDI_SUCCESS) 14241369Sdduvall return (DDI_FAILURE); 14251369Sdduvall 14261369Sdduvall /* 14271369Sdduvall * Bind the two together 14281369Sdduvall */ 14291369Sdduvall dma_p->mem_va = va; 14301369Sdduvall err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 14311369Sdduvall va, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 14321369Sdduvall &dma_p->cookie, &dma_p->ncookies); 14331369Sdduvall 14341369Sdduvall BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies", 14351369Sdduvall dma_p->alength, err, dma_p->ncookies)); 14361369Sdduvall 14371369Sdduvall if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 14381369Sdduvall return (DDI_FAILURE); 14391369Sdduvall 14401369Sdduvall dma_p->nslots = ~0U; 14411369Sdduvall dma_p->size = ~0U; 14421369Sdduvall dma_p->token = ~0U; 14431369Sdduvall dma_p->offset = 0; 14441369Sdduvall return (DDI_SUCCESS); 14451369Sdduvall } 14461369Sdduvall 14471369Sdduvall /* 14481369Sdduvall * Free one allocated area of DMAable memory 14491369Sdduvall */ 14501369Sdduvall static void 14511369Sdduvall bge_free_dma_mem(dma_area_t *dma_p) 14521369Sdduvall { 14531369Sdduvall if (dma_p->dma_hdl != NULL) { 14541369Sdduvall if (dma_p->ncookies) { 14551369Sdduvall (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 14561369Sdduvall dma_p->ncookies = 0; 14571369Sdduvall } 14581369Sdduvall ddi_dma_free_handle(&dma_p->dma_hdl); 14591369Sdduvall dma_p->dma_hdl = NULL; 14601369Sdduvall } 14611369Sdduvall 14621369Sdduvall if (dma_p->acc_hdl != NULL) { 14631369Sdduvall ddi_dma_mem_free(&dma_p->acc_hdl); 14641369Sdduvall dma_p->acc_hdl = NULL; 14651369Sdduvall } 14661369Sdduvall } 14671369Sdduvall 14681369Sdduvall /* 14691369Sdduvall * This function allocates all the transmit and receive buffers 14701369Sdduvall * and descriptors, in four chunks (or one, if MONOLITHIC). 14711369Sdduvall */ 1472*1865Sdilpreet int 14731369Sdduvall bge_alloc_bufs(bge_t *bgep) 14741369Sdduvall { 14751369Sdduvall dma_area_t area; 14761369Sdduvall size_t rxbuffsize; 14771369Sdduvall size_t txbuffsize; 14781369Sdduvall size_t rxbuffdescsize; 14791369Sdduvall size_t rxdescsize; 14801369Sdduvall size_t txdescsize; 14811369Sdduvall uint64_t ring; 14821369Sdduvall uint64_t rx_rings = bgep->chipid.rx_rings; 14831369Sdduvall uint64_t tx_rings = bgep->chipid.tx_rings; 14841369Sdduvall int split; 14851369Sdduvall int err; 14861369Sdduvall 14871369Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)", 14881369Sdduvall (void *)bgep)); 14891369Sdduvall 14901369Sdduvall rxbuffsize = BGE_STD_SLOTS_USED*BGE_STD_BUFF_SIZE; 14911369Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size; 14921369Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE; 14931369Sdduvall 14941369Sdduvall txbuffsize = BGE_SEND_SLOTS_USED*bgep->chipid.snd_buff_size; 14951369Sdduvall txbuffsize *= tx_rings; 14961369Sdduvall 14971369Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots; 14981369Sdduvall rxdescsize *= sizeof (bge_rbd_t); 14991369Sdduvall 15001369Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED; 15011369Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots; 15021369Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED; 15031369Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t); 15041369Sdduvall 15051369Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED; 15061369Sdduvall txdescsize *= sizeof (bge_sbd_t); 15071369Sdduvall txdescsize += sizeof (bge_statistics_t); 15081369Sdduvall txdescsize += sizeof (bge_status_t); 15091369Sdduvall txdescsize += BGE_STATUS_PADDING; 15101369Sdduvall 15111369Sdduvall #if BGE_MONOLITHIC 15121369Sdduvall 15131369Sdduvall err = bge_alloc_dma_mem(bgep, 15141369Sdduvall rxbuffsize+txbuffsize+rxbuffdescsize+rxdescsize+txdescsize, 15151369Sdduvall &bge_data_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &area); 15161369Sdduvall if (err != DDI_SUCCESS) 15171369Sdduvall return (DDI_FAILURE); 15181369Sdduvall 15191369Sdduvall BGE_DEBUG(("allocated range $%p-$%p (0x%lx-0x%lx)", 15201369Sdduvall DMA_VPTR(area), 15211369Sdduvall (caddr_t)DMA_VPTR(area)+area.alength, 15221369Sdduvall area.cookie.dmac_laddress, 15231369Sdduvall area.cookie.dmac_laddress+area.alength)); 15241369Sdduvall 15251369Sdduvall bge_slice_chunk(&bgep->rx_buff[0], &area, 1, rxbuffsize); 15261369Sdduvall bge_slice_chunk(&bgep->tx_buff[0], &area, 1, txbuffsize); 15271369Sdduvall bge_slice_chunk(&bgep->rx_desc[0], &area, 1, rxdescsize); 15281369Sdduvall bge_slice_chunk(&bgep->tx_desc, &area, 1, txdescsize); 15291369Sdduvall 15301369Sdduvall #else 15311369Sdduvall /* 15321369Sdduvall * Allocate memory & handles for RX buffers 15331369Sdduvall */ 15341369Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0); 15351369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 15361369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT, 15371369Sdduvall &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE, 15381369Sdduvall &bgep->rx_buff[split]); 15391369Sdduvall if (err != DDI_SUCCESS) 15401369Sdduvall return (DDI_FAILURE); 15411369Sdduvall } 15421369Sdduvall 15431369Sdduvall /* 15441369Sdduvall * Allocate memory & handles for TX buffers 15451369Sdduvall */ 15461369Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0); 15471369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 15481369Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT, 15491369Sdduvall &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE, 15501369Sdduvall &bgep->tx_buff[split]); 15511369Sdduvall if (err != DDI_SUCCESS) 15521369Sdduvall return (DDI_FAILURE); 15531369Sdduvall } 15541369Sdduvall 15551369Sdduvall /* 15561369Sdduvall * Allocate memory & handles for receive return rings 15571369Sdduvall */ 15581369Sdduvall ASSERT((rxdescsize % rx_rings) == 0); 15591369Sdduvall for (split = 0; split < rx_rings; ++split) { 15601369Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings, 15611369Sdduvall &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 15621369Sdduvall &bgep->rx_desc[split]); 15631369Sdduvall if (err != DDI_SUCCESS) 15641369Sdduvall return (DDI_FAILURE); 15651369Sdduvall } 15661369Sdduvall 15671369Sdduvall /* 15681369Sdduvall * Allocate memory & handles for buffer (producer) descriptor rings 15691369Sdduvall */ 15701369Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr, 15711369Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]); 15721369Sdduvall if (err != DDI_SUCCESS) 15731369Sdduvall return (DDI_FAILURE); 15741369Sdduvall 15751369Sdduvall /* 15761369Sdduvall * Allocate memory & handles for TX descriptor rings, 15771369Sdduvall * status block, and statistics area 15781369Sdduvall */ 15791369Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr, 15801369Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc); 15811369Sdduvall if (err != DDI_SUCCESS) 15821369Sdduvall return (DDI_FAILURE); 15831369Sdduvall 15841369Sdduvall #endif /* BGE_MONOLITHIC */ 15851369Sdduvall 15861369Sdduvall /* 15871369Sdduvall * Now carve up each of the allocated areas ... 15881369Sdduvall */ 15891369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 15901369Sdduvall area = bgep->rx_buff[split]; 15911369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split], 15921369Sdduvall &area, BGE_STD_SLOTS_USED/BGE_SPLIT, 15931369Sdduvall BGE_STD_BUFF_SIZE); 15941369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split], 15951369Sdduvall &area, bgep->chipid.jumbo_slots/BGE_SPLIT, 15961369Sdduvall bgep->chipid.recv_jumbo_size); 15971369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split], 15981369Sdduvall &area, BGE_MINI_SLOTS_USED/BGE_SPLIT, 15991369Sdduvall BGE_MINI_BUFF_SIZE); 16001369Sdduvall ASSERT(area.alength >= 0); 16011369Sdduvall } 16021369Sdduvall 16031369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) { 16041369Sdduvall area = bgep->tx_buff[split]; 16051369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 16061369Sdduvall bge_slice_chunk(&bgep->send[ring].buf[split], 16071369Sdduvall &area, BGE_SEND_SLOTS_USED/BGE_SPLIT, 16081369Sdduvall bgep->chipid.snd_buff_size); 16091369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 16101369Sdduvall bge_slice_chunk(&bgep->send[ring].buf[split], 16111369Sdduvall &area, 0/BGE_SPLIT, 16121369Sdduvall bgep->chipid.snd_buff_size); 16131369Sdduvall ASSERT(area.alength >= 0); 16141369Sdduvall } 16151369Sdduvall 16161369Sdduvall for (ring = 0; ring < rx_rings; ++ring) 16171369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring], 16181369Sdduvall bgep->chipid.recv_slots, sizeof (bge_rbd_t)); 16191369Sdduvall 16201369Sdduvall area = bgep->rx_desc[rx_rings]; 16211369Sdduvall for (; ring < BGE_RECV_RINGS_MAX; ++ring) 16221369Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area, 16231369Sdduvall 0, sizeof (bge_rbd_t)); 16241369Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area, 16251369Sdduvall BGE_STD_SLOTS_USED, sizeof (bge_rbd_t)); 16261369Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area, 16271369Sdduvall bgep->chipid.jumbo_slots, sizeof (bge_rbd_t)); 16281369Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area, 16291369Sdduvall BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t)); 16301369Sdduvall ASSERT(area.alength == 0); 16311369Sdduvall 16321369Sdduvall area = bgep->tx_desc; 16331369Sdduvall for (ring = 0; ring < tx_rings; ++ring) 16341369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 16351369Sdduvall BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t)); 16361369Sdduvall for (; ring < BGE_SEND_RINGS_MAX; ++ring) 16371369Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area, 16381369Sdduvall 0, sizeof (bge_sbd_t)); 16391369Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t)); 16401369Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t)); 16411369Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING); 16421369Sdduvall DMA_ZERO(bgep->status_block); 16431369Sdduvall 16441369Sdduvall return (DDI_SUCCESS); 16451369Sdduvall } 16461369Sdduvall 16471369Sdduvall /* 16481369Sdduvall * This routine frees the transmit and receive buffers and descriptors. 16491369Sdduvall * Make sure the chip is stopped before calling it! 16501369Sdduvall */ 1651*1865Sdilpreet void 16521369Sdduvall bge_free_bufs(bge_t *bgep) 16531369Sdduvall { 16541369Sdduvall int split; 16551369Sdduvall 16561369Sdduvall BGE_TRACE(("bge_free_bufs($%p)", 16571369Sdduvall (void *)bgep)); 16581369Sdduvall 16591369Sdduvall #if BGE_MONOLITHIC 16601369Sdduvall bge_free_dma_mem(&bgep->rx_buff[0]); 16611369Sdduvall #else 16621369Sdduvall bge_free_dma_mem(&bgep->tx_desc); 16631369Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split) 16641369Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]); 16651369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 16661369Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]); 16671369Sdduvall for (split = 0; split < BGE_SPLIT; ++split) 16681369Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]); 16691369Sdduvall #endif /* BGE_MONOLITHIC */ 16701369Sdduvall } 16711369Sdduvall 16721369Sdduvall /* 16731369Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface 16741369Sdduvall */ 16751369Sdduvall 16761369Sdduvall static void 16771369Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp) 16781369Sdduvall { 16791369Sdduvall struct ether_addr sysaddr; 16801369Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */ 16811369Sdduvall uchar_t *bytes; 16821369Sdduvall int *ints; 16831369Sdduvall uint_t nelts; 16841369Sdduvall int err; 16851369Sdduvall 16861369Sdduvall BGE_TRACE(("bge_find_mac_address($%p)", 16871369Sdduvall (void *)bgep)); 16881369Sdduvall 16891369Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)", 16901369Sdduvall cidp->hw_mac_addr, 16911369Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 16921369Sdduvall cidp->vendor_addr.set ? "" : "not ")); 16931369Sdduvall 16941369Sdduvall /* 16951369Sdduvall * The "vendor's factory-set address" may already have 16961369Sdduvall * been extracted from the chip, but if the property 16971369Sdduvall * "local-mac-address" is set we use that instead. It 16981369Sdduvall * will normally be set by OBP, but it could also be 16991369Sdduvall * specified in a .conf file(!) 17001369Sdduvall * 17011369Sdduvall * There doesn't seem to be a way to define byte-array 17021369Sdduvall * properties in a .conf, so we check whether it looks 17031369Sdduvall * like an array of 6 ints instead. 17041369Sdduvall * 17051369Sdduvall * Then, we check whether it looks like an array of 6 17061369Sdduvall * bytes (which it should, if OBP set it). If we can't 17071369Sdduvall * make sense of it either way, we'll ignore it. 17081369Sdduvall */ 17091369Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo, 17101369Sdduvall DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts); 17111369Sdduvall if (err == DDI_PROP_SUCCESS) { 17121369Sdduvall if (nelts == ETHERADDRL) { 17131369Sdduvall while (nelts--) 17141369Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts]; 17151369Sdduvall cidp->vendor_addr.set = 1; 17161369Sdduvall } 17171369Sdduvall ddi_prop_free(ints); 17181369Sdduvall } 17191369Sdduvall 17201369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 17211369Sdduvall DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts); 17221369Sdduvall if (err == DDI_PROP_SUCCESS) { 17231369Sdduvall if (nelts == ETHERADDRL) { 17241369Sdduvall while (nelts--) 17251369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 17261369Sdduvall cidp->vendor_addr.set = 1; 17271369Sdduvall } 17281369Sdduvall ddi_prop_free(bytes); 17291369Sdduvall } 17301369Sdduvall 17311369Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)", 17321369Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 17331369Sdduvall cidp->vendor_addr.set ? "" : "not ")); 17341369Sdduvall 17351369Sdduvall /* 17361369Sdduvall * Look up the OBP property "local-mac-address?". Note that even 17371369Sdduvall * though its value is a string (which should be "true" or "false"), 17381369Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero 17391369Sdduvall * the buffer first and then fetch the property as an untyped array; 17401369Sdduvall * this may or may not include a final NUL, but since there will 17411369Sdduvall * always be one left at the end of the buffer we can now treat it 17421369Sdduvall * as a string anyway. 17431369Sdduvall */ 17441369Sdduvall nelts = sizeof (propbuf); 17451369Sdduvall bzero(propbuf, nelts--); 17461369Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo, 17471369Sdduvall DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts); 17481369Sdduvall 17491369Sdduvall /* 17501369Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM) 17511369Sdduvall * or the OBP or .conf property, OR if the user has foolishly set 17521369Sdduvall * 'local-mac-address? = false', use "the system address" instead 17531369Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM). 17541369Sdduvall */ 17551369Sdduvall if (cidp->vendor_addr.set == 0 || strcmp(propbuf, "false") == 0) 17561369Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) { 17571369Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr); 17581369Sdduvall cidp->vendor_addr.set = 1; 17591369Sdduvall } 17601369Sdduvall 17611369Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)", 17621369Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 17631369Sdduvall cidp->vendor_addr.set ? "" : "not ")); 17641369Sdduvall 17651369Sdduvall /* 17661369Sdduvall * Finally(!), if there's a valid "mac-address" property (created 17671369Sdduvall * if we netbooted from this interface), we must use this instead 17681369Sdduvall * of any of the above to ensure that the NFS/install server doesn't 17691369Sdduvall * get confused by the address changing as Solaris takes over! 17701369Sdduvall */ 17711369Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo, 17721369Sdduvall DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts); 17731369Sdduvall if (err == DDI_PROP_SUCCESS) { 17741369Sdduvall if (nelts == ETHERADDRL) { 17751369Sdduvall while (nelts--) 17761369Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts]; 17771369Sdduvall cidp->vendor_addr.set = 1; 17781369Sdduvall } 17791369Sdduvall ddi_prop_free(bytes); 17801369Sdduvall } 17811369Sdduvall 17821369Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)", 17831369Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr), 17841369Sdduvall cidp->vendor_addr.set ? "" : "not ")); 17851369Sdduvall } 17861369Sdduvall 1787*1865Sdilpreet 1788*1865Sdilpreet /*ARGSUSED*/ 1789*1865Sdilpreet int 1790*1865Sdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle) 1791*1865Sdilpreet { 1792*1865Sdilpreet ddi_fm_error_t de; 1793*1865Sdilpreet 1794*1865Sdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 1795*1865Sdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 1796*1865Sdilpreet return (de.fme_status); 1797*1865Sdilpreet } 1798*1865Sdilpreet 1799*1865Sdilpreet /*ARGSUSED*/ 1800*1865Sdilpreet int 1801*1865Sdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle) 1802*1865Sdilpreet { 1803*1865Sdilpreet ddi_fm_error_t de; 1804*1865Sdilpreet 1805*1865Sdilpreet ASSERT(bgep->progress & PROGRESS_BUFS); 1806*1865Sdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 1807*1865Sdilpreet return (de.fme_status); 1808*1865Sdilpreet } 1809*1865Sdilpreet 1810*1865Sdilpreet /* 1811*1865Sdilpreet * The IO fault service error handling callback function 1812*1865Sdilpreet */ 1813*1865Sdilpreet /*ARGSUSED*/ 1814*1865Sdilpreet static int 1815*1865Sdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 1816*1865Sdilpreet { 1817*1865Sdilpreet /* 1818*1865Sdilpreet * as the driver can always deal with an error in any dma or 1819*1865Sdilpreet * access handle, we can just return the fme_status value. 1820*1865Sdilpreet */ 1821*1865Sdilpreet pci_ereport_post(dip, err, NULL); 1822*1865Sdilpreet return (err->fme_status); 1823*1865Sdilpreet } 1824*1865Sdilpreet 1825*1865Sdilpreet static void 1826*1865Sdilpreet bge_fm_init(bge_t *bgep) 1827*1865Sdilpreet { 1828*1865Sdilpreet ddi_iblock_cookie_t iblk; 1829*1865Sdilpreet 1830*1865Sdilpreet /* Only register with IO Fault Services if we have some capability */ 1831*1865Sdilpreet if (bgep->fm_capabilities) { 1832*1865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 1833*1865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 1834*1865Sdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR; 1835*1865Sdilpreet 1836*1865Sdilpreet /* Register capabilities with IO Fault Services */ 1837*1865Sdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk); 1838*1865Sdilpreet 1839*1865Sdilpreet /* 1840*1865Sdilpreet * Initialize pci ereport capabilities if ereport capable 1841*1865Sdilpreet */ 1842*1865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 1843*1865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 1844*1865Sdilpreet pci_ereport_setup(bgep->devinfo); 1845*1865Sdilpreet 1846*1865Sdilpreet /* 1847*1865Sdilpreet * Register error callback if error callback capable 1848*1865Sdilpreet */ 1849*1865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 1850*1865Sdilpreet ddi_fm_handler_register(bgep->devinfo, 1851*1865Sdilpreet bge_fm_error_cb, (void*) bgep); 1852*1865Sdilpreet } else { 1853*1865Sdilpreet /* 1854*1865Sdilpreet * These fields have to be cleared of FMA if there are no 1855*1865Sdilpreet * FMA capabilities at runtime. 1856*1865Sdilpreet */ 1857*1865Sdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 1858*1865Sdilpreet bge_desc_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 1859*1865Sdilpreet dma_attr.dma_attr_flags = 0; 1860*1865Sdilpreet } 1861*1865Sdilpreet } 1862*1865Sdilpreet 1863*1865Sdilpreet static void 1864*1865Sdilpreet bge_fm_fini(bge_t *bgep) 1865*1865Sdilpreet { 1866*1865Sdilpreet /* Only unregister FMA capabilities if we registered some */ 1867*1865Sdilpreet if (bgep->fm_capabilities) { 1868*1865Sdilpreet 1869*1865Sdilpreet /* 1870*1865Sdilpreet * Release any resources allocated by pci_ereport_setup() 1871*1865Sdilpreet */ 1872*1865Sdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) || 1873*1865Sdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 1874*1865Sdilpreet pci_ereport_teardown(bgep->devinfo); 1875*1865Sdilpreet 1876*1865Sdilpreet /* 1877*1865Sdilpreet * Un-register error callback if error callback capable 1878*1865Sdilpreet */ 1879*1865Sdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities)) 1880*1865Sdilpreet ddi_fm_handler_unregister(bgep->devinfo); 1881*1865Sdilpreet 1882*1865Sdilpreet /* Unregister from IO Fault Services */ 1883*1865Sdilpreet ddi_fm_fini(bgep->devinfo); 1884*1865Sdilpreet } 1885*1865Sdilpreet } 1886*1865Sdilpreet 18871369Sdduvall static void 18881408Srandyf #ifdef BGE_IPMI_ASF 18891408Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode) 18901408Srandyf #else 18911369Sdduvall bge_unattach(bge_t *bgep) 18921408Srandyf #endif 18931369Sdduvall { 18941369Sdduvall mac_t *macp; 18951369Sdduvall 18961369Sdduvall BGE_TRACE(("bge_unattach($%p)", 18971369Sdduvall (void *)bgep)); 18981369Sdduvall 18991369Sdduvall /* 19001369Sdduvall * Flag that no more activity may be initiated 19011369Sdduvall */ 19021369Sdduvall bgep->progress &= ~PROGRESS_READY; 19031369Sdduvall 19041369Sdduvall /* 19051369Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered). 19061369Sdduvall * Clean up and free all BGE data structures 19071369Sdduvall */ 19081369Sdduvall if (bgep->cyclic_id) { 19091369Sdduvall mutex_enter(&cpu_lock); 19101369Sdduvall cyclic_remove(bgep->cyclic_id); 19111369Sdduvall mutex_exit(&cpu_lock); 19121369Sdduvall } 19131369Sdduvall if (bgep->progress & PROGRESS_KSTATS) 19141369Sdduvall bge_fini_kstats(bgep); 19151369Sdduvall if (bgep->progress & PROGRESS_NDD) 19161369Sdduvall bge_nd_cleanup(bgep); 19171369Sdduvall if (bgep->progress & PROGRESS_PHY) 19181369Sdduvall bge_phys_reset(bgep); 19191369Sdduvall if (bgep->progress & PROGRESS_HWINT) { 19201369Sdduvall mutex_enter(bgep->genlock); 19211408Srandyf #ifdef BGE_IPMI_ASF 1922*1865Sdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS) 1923*1865Sdilpreet #else 1924*1865Sdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS) 1925*1865Sdilpreet #endif 1926*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 1927*1865Sdilpreet DDI_SERVICE_UNAFFECTED); 1928*1865Sdilpreet #ifdef BGE_IPMI_ASF 19291408Srandyf if (bgep->asf_enabled) { 19301408Srandyf /* 19311408Srandyf * This register has been overlaid. We restore its 19321408Srandyf * initial value here. 19331408Srandyf */ 19341408Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR, 19351408Srandyf BGE_NIC_DATA_SIG); 19361408Srandyf } 19371408Srandyf #endif 1938*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 1939*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 1940*1865Sdilpreet DDI_SERVICE_UNAFFECTED); 1941*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 1942*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 1943*1865Sdilpreet DDI_SERVICE_UNAFFECTED); 19441369Sdduvall mutex_exit(bgep->genlock); 19451369Sdduvall } 19461369Sdduvall if (bgep->progress & PROGRESS_INTR) { 1947*1865Sdilpreet bge_intr_disable(bgep); 19481369Sdduvall bge_fini_rings(bgep); 19491369Sdduvall } 1950*1865Sdilpreet if (bgep->progress & PROGRESS_HWINT) { 1951*1865Sdilpreet bge_rem_intrs(bgep); 1952*1865Sdilpreet rw_destroy(bgep->errlock); 1953*1865Sdilpreet mutex_destroy(bgep->softintrlock); 1954*1865Sdilpreet mutex_destroy(bgep->genlock); 1955*1865Sdilpreet } 19561369Sdduvall if (bgep->progress & PROGRESS_FACTOTUM) 19571369Sdduvall ddi_remove_softintr(bgep->factotum_id); 19581369Sdduvall if (bgep->progress & PROGRESS_RESCHED) 19591369Sdduvall ddi_remove_softintr(bgep->resched_id); 1960*1865Sdilpreet if (bgep->progress & PROGRESS_BUFS) 1961*1865Sdilpreet bge_free_bufs(bgep); 19621369Sdduvall if (bgep->progress & PROGRESS_REGS) 19631369Sdduvall ddi_regs_map_free(&bgep->io_handle); 19641369Sdduvall if (bgep->progress & PROGRESS_CFG) 19651369Sdduvall pci_config_teardown(&bgep->cfg_handle); 19661369Sdduvall 1967*1865Sdilpreet bge_fm_fini(bgep); 1968*1865Sdilpreet 19691369Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL); 19701369Sdduvall macp = bgep->macp; 19711369Sdduvall kmem_free(macp, sizeof (*macp)); 19721369Sdduvall kmem_free(bgep, sizeof (*bgep)); 19731369Sdduvall } 19741369Sdduvall 19751369Sdduvall static int 19761369Sdduvall bge_resume(dev_info_t *devinfo) 19771369Sdduvall { 19781369Sdduvall bge_t *bgep; /* Our private data */ 19791369Sdduvall chip_id_t *cidp; 19801369Sdduvall chip_id_t chipid; 19811369Sdduvall 19821369Sdduvall bgep = ddi_get_driver_private(devinfo); 19831369Sdduvall if (bgep == NULL) 19841369Sdduvall return (DDI_FAILURE); 19851369Sdduvall 19861369Sdduvall /* 19871369Sdduvall * Refuse to resume if the data structures aren't consistent 19881369Sdduvall */ 19891369Sdduvall if (bgep->devinfo != devinfo) 19901369Sdduvall return (DDI_FAILURE); 19911369Sdduvall 19921408Srandyf #ifdef BGE_IPMI_ASF 19931408Srandyf /* 19941408Srandyf * Power management hasn't been supported in BGE now. If you 19951408Srandyf * want to implement it, please add the ASF/IPMI related 19961408Srandyf * code here. 19971408Srandyf */ 19981408Srandyf 19991408Srandyf #endif 20001408Srandyf 20011369Sdduvall /* 20021369Sdduvall * Read chip ID & set up config space command register(s) 20031369Sdduvall * Refuse to resume if the chip has changed its identity! 20041369Sdduvall */ 20051369Sdduvall cidp = &bgep->chipid; 2006*1865Sdilpreet mutex_enter(bgep->genlock); 20071369Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE); 2008*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 2009*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2010*1865Sdilpreet mutex_exit(bgep->genlock); 2011*1865Sdilpreet return (DDI_FAILURE); 2012*1865Sdilpreet } 2013*1865Sdilpreet mutex_exit(bgep->genlock); 20141369Sdduvall if (chipid.vendor != cidp->vendor) 20151369Sdduvall return (DDI_FAILURE); 20161369Sdduvall if (chipid.device != cidp->device) 20171369Sdduvall return (DDI_FAILURE); 20181369Sdduvall if (chipid.revision != cidp->revision) 20191369Sdduvall return (DDI_FAILURE); 20201369Sdduvall if (chipid.asic_rev != cidp->asic_rev) 20211369Sdduvall return (DDI_FAILURE); 20221369Sdduvall 20231369Sdduvall /* 20241369Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling 20251369Sdduvall */ 20261369Sdduvall mutex_enter(bgep->genlock); 2027*1865Sdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) { 2028*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 2029*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 2030*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2031*1865Sdilpreet mutex_exit(bgep->genlock); 2032*1865Sdilpreet return (DDI_FAILURE); 2033*1865Sdilpreet } 2034*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 2035*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2036*1865Sdilpreet mutex_exit(bgep->genlock); 2037*1865Sdilpreet return (DDI_FAILURE); 2038*1865Sdilpreet } 2039*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 2040*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2041*1865Sdilpreet mutex_exit(bgep->genlock); 2042*1865Sdilpreet return (DDI_FAILURE); 2043*1865Sdilpreet } 20441369Sdduvall mutex_exit(bgep->genlock); 20451369Sdduvall return (DDI_SUCCESS); 20461369Sdduvall } 20471369Sdduvall 20481369Sdduvall static uint8_t ether_brdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 20491369Sdduvall 20501369Sdduvall /* 20511369Sdduvall * attach(9E) -- Attach a device to the system 20521369Sdduvall * 20531369Sdduvall * Called once for each board successfully probed. 20541369Sdduvall */ 20551369Sdduvall static int 20561369Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 20571369Sdduvall { 20581369Sdduvall bge_t *bgep; /* Our private data */ 20591369Sdduvall mac_t *macp; 20601369Sdduvall chip_id_t *cidp; 20611369Sdduvall cyc_handler_t cychand; 20621369Sdduvall cyc_time_t cyctime; 20631369Sdduvall caddr_t regs; 20641369Sdduvall int instance; 20651369Sdduvall int err; 20661369Sdduvall mac_info_t *mip; 20671369Sdduvall int intr_types; 20681408Srandyf #ifdef BGE_IPMI_ASF 20691408Srandyf uint32_t mhcrValue; 20701408Srandyf #endif 20711369Sdduvall 20721369Sdduvall instance = ddi_get_instance(devinfo); 20731369Sdduvall 20741369Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d", 20751369Sdduvall (void *)devinfo, cmd, instance)); 20761369Sdduvall BGE_BRKPT(NULL, "bge_attach"); 20771369Sdduvall 20781369Sdduvall switch (cmd) { 20791369Sdduvall default: 20801369Sdduvall return (DDI_FAILURE); 20811369Sdduvall 20821369Sdduvall case DDI_RESUME: 20831369Sdduvall return (bge_resume(devinfo)); 20841369Sdduvall 20851369Sdduvall case DDI_ATTACH: 20861369Sdduvall break; 20871369Sdduvall } 20881369Sdduvall 20891369Sdduvall /* 20901369Sdduvall * Allocate mac_t and BGE private structures, and 20911369Sdduvall * cross-link them so that given either one of these or 20921369Sdduvall * the devinfo the others can be derived. 20931369Sdduvall */ 20941369Sdduvall macp = kmem_zalloc(sizeof (*macp), KM_SLEEP); 20951369Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP); 20961369Sdduvall ddi_set_driver_private(devinfo, bgep); 20971369Sdduvall bgep->bge_guard = BGE_GUARD; 20981369Sdduvall bgep->devinfo = devinfo; 20991369Sdduvall bgep->macp = macp; 21001369Sdduvall macp->m_driver = bgep; 21011369Sdduvall 21021369Sdduvall /* 21031369Sdduvall * Initialize more fields in BGE private data 21041369Sdduvall */ 21051369Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21061369Sdduvall DDI_PROP_DONTPASS, debug_propname, bge_debug); 21071369Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d", 21081369Sdduvall BGE_DRIVER_NAME, instance); 21091369Sdduvall 21101369Sdduvall /* 2111*1865Sdilpreet * Initialize for fma support 2112*1865Sdilpreet */ 2113*1865Sdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 2114*1865Sdilpreet DDI_PROP_DONTPASS, fm_cap, 2115*1865Sdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 2116*1865Sdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 2117*1865Sdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities)); 2118*1865Sdilpreet bge_fm_init(bgep); 2119*1865Sdilpreet 2120*1865Sdilpreet /* 21211369Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be 21221369Sdduvall * a power of 2) and convert to a mask. This can be used to 21231369Sdduvall * determine whether a message buffer crosses a page boundary. 21241369Sdduvall * Note: in 2s complement binary notation, if X is a power of 21251369Sdduvall * 2, then -X has the representation "11...1100...00". 21261369Sdduvall */ 21271369Sdduvall bgep->pagemask = dvma_pagesize(devinfo); 21281369Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask)); 21291369Sdduvall bgep->pagemask = -bgep->pagemask; 21301369Sdduvall 21311369Sdduvall /* 21321369Sdduvall * Map config space registers 21331369Sdduvall * Read chip ID & set up config space command register(s) 21341369Sdduvall * 21351369Sdduvall * Note: this leaves the chip accessible by Memory Space 21361369Sdduvall * accesses, but with interrupts and Bus Mastering off. 21371369Sdduvall * This should ensure that nothing untoward will happen 21381369Sdduvall * if it has been left active by the (net-)bootloader. 21391369Sdduvall * We'll re-enable Bus Mastering once we've reset the chip, 21401369Sdduvall * and allow interrupts only when everything else is set up. 21411369Sdduvall */ 21421369Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle); 21431408Srandyf #ifdef BGE_IPMI_ASF 21441408Srandyf mhcrValue = pci_config_get32(bgep->cfg_handle, PCI_CONF_BGE_MHCR); 21451408Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) { 21461408Srandyf bgep->asf_wordswapped = B_TRUE; 21471408Srandyf } else { 21481408Srandyf bgep->asf_wordswapped = B_FALSE; 21491408Srandyf } 21501408Srandyf bge_asf_get_config(bgep); 21511408Srandyf #endif 21521369Sdduvall if (err != DDI_SUCCESS) { 21531369Sdduvall bge_problem(bgep, "pci_config_setup() failed"); 21541369Sdduvall goto attach_fail; 21551369Sdduvall } 21561369Sdduvall bgep->progress |= PROGRESS_CFG; 21571369Sdduvall cidp = &bgep->chipid; 21581369Sdduvall bzero(cidp, sizeof (*cidp)); 21591369Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE); 2160*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 2161*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2162*1865Sdilpreet goto attach_fail; 2163*1865Sdilpreet } 21641369Sdduvall 21651408Srandyf #ifdef BGE_IPMI_ASF 21661408Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) || 21671408Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) { 21681408Srandyf bgep->asf_newhandshake = B_TRUE; 21691408Srandyf } else { 21701408Srandyf bgep->asf_newhandshake = B_FALSE; 21711408Srandyf } 21721408Srandyf #endif 21731408Srandyf 21741369Sdduvall /* 21751369Sdduvall * Update those parts of the chip ID derived from volatile 21761369Sdduvall * registers with the values seen by OBP (in case the chip 21771369Sdduvall * has been reset externally and therefore lost them). 21781369Sdduvall */ 21791369Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21801369Sdduvall DDI_PROP_DONTPASS, subven_propname, cidp->subven); 21811369Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21821369Sdduvall DDI_PROP_DONTPASS, subdev_propname, cidp->subdev); 21831369Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21841369Sdduvall DDI_PROP_DONTPASS, clsize_propname, cidp->clsize); 21851369Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21861369Sdduvall DDI_PROP_DONTPASS, latency_propname, cidp->latency); 21871369Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21881369Sdduvall DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings); 21891369Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21901369Sdduvall DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings); 21911369Sdduvall 21921369Sdduvall if (bge_jumbo_enable == B_TRUE) { 21931369Sdduvall cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 21941369Sdduvall DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU); 21951369Sdduvall if ((cidp->default_mtu < BGE_DEFAULT_MTU)|| 21961369Sdduvall (cidp->default_mtu > BGE_MAXIMUM_MTU)) { 21971369Sdduvall cidp->default_mtu = BGE_DEFAULT_MTU; 21981369Sdduvall } 21991369Sdduvall } 22001369Sdduvall /* 22011369Sdduvall * Map operating registers 22021369Sdduvall */ 22031369Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER, 22041369Sdduvall ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle); 22051369Sdduvall if (err != DDI_SUCCESS) { 22061369Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed"); 22071369Sdduvall goto attach_fail; 22081369Sdduvall } 22091369Sdduvall bgep->io_regs = regs; 22101369Sdduvall bgep->progress |= PROGRESS_REGS; 22111369Sdduvall 22121369Sdduvall /* 22131369Sdduvall * Characterise the device, so we know its requirements. 22141369Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers. 22151369Sdduvall */ 2216*1865Sdilpreet if (bge_chip_id_init(bgep) == EIO) { 2217*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2218*1865Sdilpreet goto attach_fail; 2219*1865Sdilpreet } 22201369Sdduvall err = bge_alloc_bufs(bgep); 22211369Sdduvall if (err != DDI_SUCCESS) { 22221369Sdduvall bge_problem(bgep, "DMA buffer allocation failed"); 22231369Sdduvall goto attach_fail; 22241369Sdduvall } 2225*1865Sdilpreet bgep->progress |= PROGRESS_BUFS; 22261369Sdduvall 22271369Sdduvall /* 22281369Sdduvall * Add the softint handlers: 22291369Sdduvall * 22301369Sdduvall * Both of these handlers are used to avoid restrictions on the 22311369Sdduvall * context and/or mutexes required for some operations. In 22321369Sdduvall * particular, the hardware interrupt handler and its subfunctions 22331369Sdduvall * can detect a number of conditions that we don't want to handle 22341369Sdduvall * in that context or with that set of mutexes held. So, these 22351369Sdduvall * softints are triggered instead: 22361369Sdduvall * 22371369Sdduvall * the <resched> softint is triggered if if we have previously 22381369Sdduvall * had to refuse to send a packet because of resource shortage 22391369Sdduvall * (we've run out of transmit buffers), but the send completion 22401369Sdduvall * interrupt handler has now detected that more buffers have 22411369Sdduvall * become available. 22421369Sdduvall * 22431369Sdduvall * the <factotum> is triggered if the h/w interrupt handler 22441369Sdduvall * sees the <link state changed> or <error> bits in the status 22451369Sdduvall * block. It's also triggered periodically to poll the link 22461369Sdduvall * state, just in case we aren't getting link status change 22471369Sdduvall * interrupts ... 22481369Sdduvall */ 22491369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->resched_id, 22501369Sdduvall NULL, NULL, bge_reschedule, (caddr_t)bgep); 22511369Sdduvall if (err != DDI_SUCCESS) { 22521369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 22531369Sdduvall goto attach_fail; 22541369Sdduvall } 22551369Sdduvall bgep->progress |= PROGRESS_RESCHED; 22561369Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id, 22571369Sdduvall NULL, NULL, bge_chip_factotum, (caddr_t)bgep); 22581369Sdduvall if (err != DDI_SUCCESS) { 22591369Sdduvall bge_problem(bgep, "ddi_add_softintr() failed"); 22601369Sdduvall goto attach_fail; 22611369Sdduvall } 22621369Sdduvall bgep->progress |= PROGRESS_FACTOTUM; 22631369Sdduvall 22641369Sdduvall /* Get supported interrupt types */ 22651369Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) { 22661369Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n"); 22671369Sdduvall 22681369Sdduvall goto attach_fail; 22691369Sdduvall } 22701369Sdduvall 22711369Sdduvall bge_log(bgep, "ddi_intr_get_supported_types() returned: %x", 22721369Sdduvall intr_types); 22731369Sdduvall 22741369Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) { 22751369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 22761369Sdduvall bge_error(bgep, "MSI registration failed, " 22771369Sdduvall "trying FIXED interrupt type\n"); 22781369Sdduvall } else { 22791369Sdduvall bge_log(bgep, "Using MSI interrupt type\n"); 22801369Sdduvall 22811369Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI; 2282*1865Sdilpreet bgep->progress |= PROGRESS_HWINT; 22831369Sdduvall } 22841369Sdduvall } 22851369Sdduvall 2286*1865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT) && 22871369Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) { 22881369Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 22891369Sdduvall bge_error(bgep, "FIXED interrupt " 22901369Sdduvall "registration failed\n"); 22911369Sdduvall goto attach_fail; 22921369Sdduvall } 22931369Sdduvall 22941369Sdduvall bge_log(bgep, "Using FIXED interrupt type\n"); 22951369Sdduvall 22961369Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED; 2297*1865Sdilpreet bgep->progress |= PROGRESS_HWINT; 22981369Sdduvall } 22991369Sdduvall 2300*1865Sdilpreet if (!(bgep->progress & PROGRESS_HWINT)) { 23011369Sdduvall bge_error(bgep, "No interrupts registered\n"); 23021369Sdduvall goto attach_fail; 23031369Sdduvall } 23041369Sdduvall 23051369Sdduvall /* 23061369Sdduvall * Note that interrupts are not enabled yet as 2307*1865Sdilpreet * mutex locks are not initialized. Initialize mutex locks. 2308*1865Sdilpreet */ 2309*1865Sdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER, 2310*1865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 2311*1865Sdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER, 2312*1865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 2313*1865Sdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER, 2314*1865Sdilpreet DDI_INTR_PRI(bgep->intr_pri)); 2315*1865Sdilpreet 2316*1865Sdilpreet /* 2317*1865Sdilpreet * Initialize rings. 23181369Sdduvall */ 23191369Sdduvall bge_init_rings(bgep); 23201369Sdduvall 23211369Sdduvall /* 23221369Sdduvall * Now that mutex locks are initialized, enable interrupts. 23231369Sdduvall */ 2324*1865Sdilpreet bge_intr_enable(bgep); 2325*1865Sdilpreet bgep->progress |= PROGRESS_INTR; 23261369Sdduvall 23271369Sdduvall /* 23281369Sdduvall * Initialise link state variables 23291369Sdduvall * Stop, reset & reinitialise the chip. 23301369Sdduvall * Initialise the (internal) PHY. 23311369Sdduvall */ 23321369Sdduvall bgep->link_state = LINK_STATE_UNKNOWN; 23331369Sdduvall bgep->link_up_msg = bgep->link_down_msg = " (initialized)"; 23341369Sdduvall 23351369Sdduvall mutex_enter(bgep->genlock); 23361369Sdduvall 23371369Sdduvall /* 23381369Sdduvall * Reset chip & rings to initial state; also reset address 23391369Sdduvall * filtering, promiscuity, loopback mode. 23401369Sdduvall */ 23411408Srandyf #ifdef BGE_IPMI_ASF 2342*1865Sdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) { 23431408Srandyf #else 2344*1865Sdilpreet if (bge_reset(bgep) != DDI_SUCCESS) { 23451408Srandyf #endif 2346*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle); 2347*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 2348*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2349*1865Sdilpreet mutex_exit(bgep->genlock); 2350*1865Sdilpreet goto attach_fail; 2351*1865Sdilpreet } 23521369Sdduvall 23531369Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash)); 23541369Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs)); 23551369Sdduvall bgep->promisc = B_FALSE; 23561369Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE; 2357*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) { 2358*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2359*1865Sdilpreet mutex_exit(bgep->genlock); 2360*1865Sdilpreet goto attach_fail; 2361*1865Sdilpreet } 2362*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 2363*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2364*1865Sdilpreet mutex_exit(bgep->genlock); 2365*1865Sdilpreet goto attach_fail; 2366*1865Sdilpreet } 23671369Sdduvall 23681369Sdduvall mutex_exit(bgep->genlock); 23691369Sdduvall 2370*1865Sdilpreet if (bge_phys_init(bgep) == EIO) { 2371*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); 2372*1865Sdilpreet goto attach_fail; 2373*1865Sdilpreet } 23741369Sdduvall bgep->progress |= PROGRESS_PHY; 23751369Sdduvall 23761369Sdduvall /* 23771369Sdduvall * Register NDD-tweakable parameters 23781369Sdduvall */ 23791369Sdduvall if (bge_nd_init(bgep)) { 23801369Sdduvall bge_problem(bgep, "bge_nd_init() failed"); 23811369Sdduvall goto attach_fail; 23821369Sdduvall } 23831369Sdduvall bgep->progress |= PROGRESS_NDD; 23841369Sdduvall 23851369Sdduvall /* 23861369Sdduvall * Create & initialise named kstats 23871369Sdduvall */ 23881369Sdduvall bge_init_kstats(bgep, instance); 23891369Sdduvall bgep->progress |= PROGRESS_KSTATS; 23901369Sdduvall 23911369Sdduvall /* 23921369Sdduvall * Determine whether to override the chip's own MAC address 23931369Sdduvall */ 23941369Sdduvall bge_find_mac_address(bgep, cidp); 23951369Sdduvall ethaddr_copy(cidp->vendor_addr.addr, bgep->curr_addr.addr); 23961369Sdduvall bgep->curr_addr.set = 1; 23971369Sdduvall 23981369Sdduvall /* 23991369Sdduvall * Initialize pointers to device specific functions which 24001369Sdduvall * will be used by the generic layer. 24011369Sdduvall */ 24021369Sdduvall mip = &(macp->m_info); 24031369Sdduvall mip->mi_media = DL_ETHER; 24041369Sdduvall mip->mi_sdu_min = 0; 24051369Sdduvall mip->mi_sdu_max = cidp->ethmax_size - sizeof (struct ether_header); 24061369Sdduvall mip->mi_poll = DL_CAPAB_POLL; 24071369Sdduvall 24081611Szh199473 /* 24091611Szh199473 * Workaround for Incorrect pseudo-header checksum calculation. 24101611Szh199473 * Use partial checksum offload for all affected chips. 24111611Szh199473 */ 24121611Szh199473 if (DEVICE_5704_SERIES_CHIPSETS(bgep)) 24131611Szh199473 mip->mi_cksum = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; 24141611Szh199473 else 24151611Szh199473 mip->mi_cksum = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 24161611Szh199473 24171369Sdduvall mip->mi_addr_length = ETHERADDRL; 24181369Sdduvall bcopy(ether_brdcst, mip->mi_brdcst_addr, ETHERADDRL); 24191369Sdduvall bcopy(bgep->curr_addr.addr, mip->mi_unicst_addr, ETHERADDRL); 24201369Sdduvall 24211369Sdduvall MAC_STAT_MIB(mip->mi_stat); 24221369Sdduvall mip->mi_stat[MAC_STAT_UNKNOWNS] = B_FALSE; 24231369Sdduvall MAC_STAT_ETHER(mip->mi_stat); 24241369Sdduvall mip->mi_stat[MAC_STAT_SQE_ERRORS] = B_FALSE; 24251369Sdduvall mip->mi_stat[MAC_STAT_MACRCV_ERRORS] = B_FALSE; 24261369Sdduvall if (!(bgep->chipid.flags & CHIP_FLAG_SERDES)) 24271369Sdduvall MAC_STAT_MII(mip->mi_stat); 24281369Sdduvall 24291369Sdduvall macp->m_stat = bge_m_stat; 24301369Sdduvall macp->m_stop = bge_m_stop; 24311369Sdduvall macp->m_start = bge_m_start; 24321369Sdduvall macp->m_unicst = bge_m_unicst; 24331369Sdduvall macp->m_multicst = bge_m_multicst; 24341369Sdduvall macp->m_promisc = bge_m_promisc; 24351369Sdduvall macp->m_tx = bge_m_tx; 24361369Sdduvall macp->m_resources = bge_m_resources; 24371369Sdduvall macp->m_ioctl = bge_m_ioctl; 24381369Sdduvall 24391369Sdduvall macp->m_dip = devinfo; 24401369Sdduvall macp->m_ident = MAC_IDENT; 24411369Sdduvall 24421369Sdduvall /* 24431369Sdduvall * Finally, we're ready to register ourselves with the MAC layer 24441369Sdduvall * interface; if this succeeds, we're all ready to start() 24451369Sdduvall */ 24461369Sdduvall if (mac_register(macp) != 0) 24471369Sdduvall goto attach_fail; 24481369Sdduvall 24491369Sdduvall cychand.cyh_func = bge_chip_cyclic; 24501369Sdduvall cychand.cyh_arg = bgep; 24511369Sdduvall cychand.cyh_level = CY_LOCK_LEVEL; 24521369Sdduvall cyctime.cyt_when = 0; 24531369Sdduvall cyctime.cyt_interval = BGE_CYCLIC_PERIOD; 24541369Sdduvall mutex_enter(&cpu_lock); 24551369Sdduvall bgep->cyclic_id = cyclic_add(&cychand, &cyctime); 24561369Sdduvall mutex_exit(&cpu_lock); 24571369Sdduvall 24581369Sdduvall bgep->progress |= PROGRESS_READY; 24591369Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD); 24601369Sdduvall return (DDI_SUCCESS); 24611369Sdduvall 24621369Sdduvall attach_fail: 24631408Srandyf #ifdef BGE_IPMI_ASF 24641408Srandyf bge_unattach(bgep, ASF_MODE_NONE); 24651408Srandyf #else 24661369Sdduvall bge_unattach(bgep); 24671408Srandyf #endif 24681369Sdduvall return (DDI_FAILURE); 24691369Sdduvall } 24701369Sdduvall 24711369Sdduvall /* 24721369Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown 24731369Sdduvall */ 24741369Sdduvall static int 24751369Sdduvall bge_suspend(bge_t *bgep) 24761369Sdduvall { 24771369Sdduvall /* 24781369Sdduvall * Stop processing and idle (powerdown) the PHY ... 24791369Sdduvall */ 24801369Sdduvall mutex_enter(bgep->genlock); 24811408Srandyf #ifdef BGE_IPMI_ASF 24821408Srandyf /* 24831408Srandyf * Power management hasn't been supported in BGE now. If you 24841408Srandyf * want to implement it, please add the ASF/IPMI related 24851408Srandyf * code here. 24861408Srandyf */ 24871408Srandyf #endif 24881369Sdduvall bge_stop(bgep); 2489*1865Sdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) { 2490*1865Sdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle); 2491*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 2492*1865Sdilpreet mutex_exit(bgep->genlock); 2493*1865Sdilpreet return (DDI_FAILURE); 2494*1865Sdilpreet } 2495*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) { 2496*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); 2497*1865Sdilpreet mutex_exit(bgep->genlock); 2498*1865Sdilpreet return (DDI_FAILURE); 2499*1865Sdilpreet } 25001369Sdduvall mutex_exit(bgep->genlock); 25011369Sdduvall 25021369Sdduvall return (DDI_SUCCESS); 25031369Sdduvall } 25041369Sdduvall 25051369Sdduvall /* 25061369Sdduvall * detach(9E) -- Detach a device from the system 25071369Sdduvall */ 25081369Sdduvall static int 25091369Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 25101369Sdduvall { 25111369Sdduvall bge_t *bgep; 25121408Srandyf #ifdef BGE_IPMI_ASF 25131408Srandyf uint_t asf_mode; 25141408Srandyf asf_mode = ASF_MODE_NONE; 25151408Srandyf #endif 25161369Sdduvall 25171369Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd)); 25181369Sdduvall 25191369Sdduvall bgep = ddi_get_driver_private(devinfo); 25201369Sdduvall 25211369Sdduvall switch (cmd) { 25221369Sdduvall default: 25231369Sdduvall return (DDI_FAILURE); 25241369Sdduvall 25251369Sdduvall case DDI_SUSPEND: 25261369Sdduvall return (bge_suspend(bgep)); 25271369Sdduvall 25281369Sdduvall case DDI_DETACH: 25291369Sdduvall break; 25301369Sdduvall } 25311369Sdduvall 25321408Srandyf #ifdef BGE_IPMI_ASF 25331408Srandyf mutex_enter(bgep->genlock); 25341408Srandyf if (bgep->asf_enabled && (bgep->asf_status == ASF_STAT_RUN)) { 25351408Srandyf 25361408Srandyf bge_asf_update_status(bgep); 25371408Srandyf bge_asf_stop_timer(bgep); 25381408Srandyf bgep->asf_status = ASF_STAT_STOP; 25391408Srandyf 25401408Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET); 25411408Srandyf 25421408Srandyf if (bgep->asf_pseudostop) { 25431408Srandyf bgep->link_up_msg = bgep->link_down_msg = " (stopped)"; 25441408Srandyf bge_chip_stop(bgep, B_FALSE); 25451408Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED; 25461408Srandyf bgep->asf_pseudostop = B_FALSE; 25471408Srandyf } 25481408Srandyf 25491408Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN; 2550*1865Sdilpreet 2551*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) 2552*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 2553*1865Sdilpreet DDI_SERVICE_UNAFFECTED); 2554*1865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 2555*1865Sdilpreet ddi_fm_service_impact(bgep->devinfo, 2556*1865Sdilpreet DDI_SERVICE_UNAFFECTED); 25571408Srandyf } 25581408Srandyf mutex_exit(bgep->genlock); 25591408Srandyf #endif 25601408Srandyf 25611369Sdduvall /* 25621369Sdduvall * Unregister from the GLD subsystem. This can fail, in 25631369Sdduvall * particular if there are DLPI style-2 streams still open - 25641369Sdduvall * in which case we just return failure without shutting 25651369Sdduvall * down chip operations. 25661369Sdduvall */ 25671369Sdduvall if (mac_unregister(bgep->macp) != 0) 25681369Sdduvall return (DDI_FAILURE); 25691369Sdduvall 25701369Sdduvall /* 25711369Sdduvall * All activity stopped, so we can clean up & exit 25721369Sdduvall */ 25731408Srandyf #ifdef BGE_IPMI_ASF 25741408Srandyf bge_unattach(bgep, asf_mode); 25751408Srandyf #else 25761369Sdduvall bge_unattach(bgep); 25771408Srandyf #endif 25781369Sdduvall return (DDI_SUCCESS); 25791369Sdduvall } 25801369Sdduvall 25811369Sdduvall 25821369Sdduvall /* 25831369Sdduvall * ========== Module Loading Data & Entry Points ========== 25841369Sdduvall */ 25851369Sdduvall 25861369Sdduvall #undef BGE_DBG 25871369Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */ 25881369Sdduvall 25891369Sdduvall DDI_DEFINE_STREAM_OPS(bge_dev_ops, nulldev, nulldev, bge_attach, bge_detach, 25901369Sdduvall nodev, NULL, D_MP, NULL); 25911369Sdduvall 25921369Sdduvall static struct modldrv bge_modldrv = { 25931369Sdduvall &mod_driverops, /* Type of module. This one is a driver */ 25941369Sdduvall bge_ident, /* short description */ 25951369Sdduvall &bge_dev_ops /* driver specific ops */ 25961369Sdduvall }; 25971369Sdduvall 25981369Sdduvall static struct modlinkage modlinkage = { 25991369Sdduvall MODREV_1, (void *)&bge_modldrv, NULL 26001369Sdduvall }; 26011369Sdduvall 26021369Sdduvall 26031369Sdduvall int 26041369Sdduvall _info(struct modinfo *modinfop) 26051369Sdduvall { 26061369Sdduvall return (mod_info(&modlinkage, modinfop)); 26071369Sdduvall } 26081369Sdduvall 26091369Sdduvall int 26101369Sdduvall _init(void) 26111369Sdduvall { 26121369Sdduvall int status; 26131369Sdduvall 26141369Sdduvall mac_init_ops(&bge_dev_ops, "bge"); 26151369Sdduvall status = mod_install(&modlinkage); 26161369Sdduvall if (status == DDI_SUCCESS) 26171369Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL); 26181369Sdduvall else 26191369Sdduvall mac_fini_ops(&bge_dev_ops); 26201369Sdduvall return (status); 26211369Sdduvall } 26221369Sdduvall 26231369Sdduvall int 26241369Sdduvall _fini(void) 26251369Sdduvall { 26261369Sdduvall int status; 26271369Sdduvall 26281369Sdduvall status = mod_remove(&modlinkage); 26291369Sdduvall if (status == DDI_SUCCESS) { 26301369Sdduvall mac_fini_ops(&bge_dev_ops); 26311369Sdduvall mutex_destroy(bge_log_mutex); 26321369Sdduvall } 26331369Sdduvall return (status); 26341369Sdduvall } 26351369Sdduvall 26361369Sdduvall 26371369Sdduvall /* 26381369Sdduvall * bge_add_intrs: 26391369Sdduvall * 26401369Sdduvall * Register FIXED or MSI interrupts. 26411369Sdduvall */ 26421369Sdduvall static int 26431369Sdduvall bge_add_intrs(bge_t *bgep, int intr_type) 26441369Sdduvall { 26451369Sdduvall dev_info_t *dip = bgep->devinfo; 26461369Sdduvall int avail, actual, intr_size, count = 0; 26471369Sdduvall int i, flag, ret; 26481369Sdduvall 26491369Sdduvall bge_log(bgep, "bge_add_intrs: interrupt type 0x%x\n", intr_type); 26501369Sdduvall 26511369Sdduvall /* Get number of interrupts */ 26521369Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count); 26531369Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) { 26541369Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, " 26551369Sdduvall "count: %d", ret, count); 26561369Sdduvall 26571369Sdduvall return (DDI_FAILURE); 26581369Sdduvall } 26591369Sdduvall 26601369Sdduvall /* Get number of available interrupts */ 26611369Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail); 26621369Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) { 26631369Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, " 26641369Sdduvall "ret: %d, avail: %d\n", ret, avail); 26651369Sdduvall 26661369Sdduvall return (DDI_FAILURE); 26671369Sdduvall } 26681369Sdduvall 26691369Sdduvall if (avail < count) { 26701369Sdduvall bge_log(bgep, "nitrs() returned %d, navail returned %d\n", 26711369Sdduvall count, avail); 26721369Sdduvall } 26731369Sdduvall 26741369Sdduvall /* 26751369Sdduvall * BGE hardware generates only single MSI even though it claims 26761369Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1. 26771369Sdduvall */ 26781369Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) { 26791369Sdduvall count = 1; 26801369Sdduvall flag = DDI_INTR_ALLOC_STRICT; 26811369Sdduvall } else { 26821369Sdduvall flag = DDI_INTR_ALLOC_NORMAL; 26831369Sdduvall } 26841369Sdduvall 26851369Sdduvall /* Allocate an array of interrupt handles */ 26861369Sdduvall intr_size = count * sizeof (ddi_intr_handle_t); 26871369Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP); 26881369Sdduvall 26891369Sdduvall /* Call ddi_intr_alloc() */ 26901369Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0, 26911369Sdduvall count, &actual, flag); 26921369Sdduvall 26931369Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) { 26941369Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret); 26951369Sdduvall 26961369Sdduvall kmem_free(bgep->htable, intr_size); 26971369Sdduvall return (DDI_FAILURE); 26981369Sdduvall } 26991369Sdduvall 27001369Sdduvall if (actual < count) { 27011369Sdduvall bge_log(bgep, "Requested: %d, Received: %d\n", count, actual); 27021369Sdduvall } 27031369Sdduvall 27041369Sdduvall bgep->intr_cnt = actual; 27051369Sdduvall 27061369Sdduvall /* 27071369Sdduvall * Get priority for first msi, assume remaining are all the same 27081369Sdduvall */ 27091369Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) != 27101369Sdduvall DDI_SUCCESS) { 27111369Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret); 27121369Sdduvall 27131369Sdduvall /* Free already allocated intr */ 27141369Sdduvall for (i = 0; i < actual; i++) { 27151369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 27161369Sdduvall } 27171369Sdduvall 27181369Sdduvall kmem_free(bgep->htable, intr_size); 27191369Sdduvall return (DDI_FAILURE); 27201369Sdduvall } 27211369Sdduvall 27221369Sdduvall /* Call ddi_intr_add_handler() */ 27231369Sdduvall for (i = 0; i < actual; i++) { 27241369Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr, 27251369Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 27261369Sdduvall bge_error(bgep, "ddi_intr_add_handler() " 27271369Sdduvall "failed %d\n", ret); 27281369Sdduvall 27291369Sdduvall /* Free already allocated intr */ 27301369Sdduvall for (i = 0; i < actual; i++) { 27311369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 27321369Sdduvall } 27331369Sdduvall 27341369Sdduvall kmem_free(bgep->htable, intr_size); 27351369Sdduvall return (DDI_FAILURE); 27361369Sdduvall } 27371369Sdduvall } 27381369Sdduvall 27391369Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap)) 27401369Sdduvall != DDI_SUCCESS) { 27411369Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret); 27421369Sdduvall 27431369Sdduvall for (i = 0; i < actual; i++) { 27441369Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]); 27451369Sdduvall (void) ddi_intr_free(bgep->htable[i]); 27461369Sdduvall } 27471369Sdduvall 27481369Sdduvall kmem_free(bgep->htable, intr_size); 27491369Sdduvall return (DDI_FAILURE); 27501369Sdduvall } 27511369Sdduvall 27521369Sdduvall return (DDI_SUCCESS); 27531369Sdduvall } 27541369Sdduvall 27551369Sdduvall /* 27561369Sdduvall * bge_rem_intrs: 27571369Sdduvall * 27581369Sdduvall * Unregister FIXED or MSI interrupts 27591369Sdduvall */ 27601369Sdduvall static void 27611369Sdduvall bge_rem_intrs(bge_t *bgep) 27621369Sdduvall { 27631369Sdduvall int i; 27641369Sdduvall 27651369Sdduvall bge_log(bgep, "bge_rem_intrs\n"); 27661369Sdduvall 2767*1865Sdilpreet /* Call ddi_intr_remove_handler() */ 2768*1865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 2769*1865Sdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]); 2770*1865Sdilpreet (void) ddi_intr_free(bgep->htable[i]); 2771*1865Sdilpreet } 2772*1865Sdilpreet 2773*1865Sdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t)); 2774*1865Sdilpreet } 2775*1865Sdilpreet 2776*1865Sdilpreet 2777*1865Sdilpreet void 2778*1865Sdilpreet bge_intr_enable(bge_t *bgep) 2779*1865Sdilpreet { 2780*1865Sdilpreet int i; 2781*1865Sdilpreet 2782*1865Sdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 2783*1865Sdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */ 2784*1865Sdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt); 2785*1865Sdilpreet } else { 2786*1865Sdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */ 2787*1865Sdilpreet for (i = 0; i < bgep->intr_cnt; i++) { 2788*1865Sdilpreet (void) ddi_intr_enable(bgep->htable[i]); 2789*1865Sdilpreet } 2790*1865Sdilpreet } 2791*1865Sdilpreet } 2792*1865Sdilpreet 2793*1865Sdilpreet 2794*1865Sdilpreet void 2795*1865Sdilpreet bge_intr_disable(bge_t *bgep) 2796*1865Sdilpreet { 2797*1865Sdilpreet int i; 2798*1865Sdilpreet 27991369Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) { 28001369Sdduvall /* Call ddi_intr_block_disable() */ 28011369Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt); 28021369Sdduvall } else { 28031369Sdduvall for (i = 0; i < bgep->intr_cnt; i++) { 28041369Sdduvall (void) ddi_intr_disable(bgep->htable[i]); 28051369Sdduvall } 28061369Sdduvall } 28071369Sdduvall } 2808