19865SSaurabh.Mishra@Sun.COM /* 29865SSaurabh.Mishra@Sun.COM * CDDL HEADER START 39865SSaurabh.Mishra@Sun.COM * 49865SSaurabh.Mishra@Sun.COM * The contents of this file are subject to the terms of the 59865SSaurabh.Mishra@Sun.COM * Common Development and Distribution License (the "License"). 69865SSaurabh.Mishra@Sun.COM * You may not use this file except in compliance with the License. 79865SSaurabh.Mishra@Sun.COM * 89865SSaurabh.Mishra@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99865SSaurabh.Mishra@Sun.COM * or http://www.opensolaris.org/os/licensing. 109865SSaurabh.Mishra@Sun.COM * See the License for the specific language governing permissions 119865SSaurabh.Mishra@Sun.COM * and limitations under the License. 129865SSaurabh.Mishra@Sun.COM * 139865SSaurabh.Mishra@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149865SSaurabh.Mishra@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159865SSaurabh.Mishra@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169865SSaurabh.Mishra@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179865SSaurabh.Mishra@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189865SSaurabh.Mishra@Sun.COM * 199865SSaurabh.Mishra@Sun.COM * CDDL HEADER END 209865SSaurabh.Mishra@Sun.COM */ 219865SSaurabh.Mishra@Sun.COM 229865SSaurabh.Mishra@Sun.COM /* 23*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 249865SSaurabh.Mishra@Sun.COM * Use is subject to license terms. 259865SSaurabh.Mishra@Sun.COM */ 269865SSaurabh.Mishra@Sun.COM #include <sys/stream.h> 279865SSaurabh.Mishra@Sun.COM #include <sys/strsun.h> 289865SSaurabh.Mishra@Sun.COM #include <sys/stat.h> 299865SSaurabh.Mishra@Sun.COM #include <sys/pci.h> 309865SSaurabh.Mishra@Sun.COM #include <sys/modctl.h> 319865SSaurabh.Mishra@Sun.COM #include <sys/kstat.h> 329865SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h> 339865SSaurabh.Mishra@Sun.COM #include <sys/devops.h> 349865SSaurabh.Mishra@Sun.COM #include <sys/debug.h> 359865SSaurabh.Mishra@Sun.COM #include <sys/conf.h> 369865SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h> 379865SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h> 389865SSaurabh.Mishra@Sun.COM #include <sys/ddi.h> 399865SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h> 409865SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h> 419865SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h> 429865SSaurabh.Mishra@Sun.COM #include <sys/cyclic.h> 439865SSaurabh.Mishra@Sun.COM #include <sys/note.h> 449865SSaurabh.Mishra@Sun.COM #include <sys/crc32.h> 459865SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h> 469865SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h> 479865SSaurabh.Mishra@Sun.COM #include <sys/vlan.h> 489865SSaurabh.Mishra@Sun.COM #include <sys/errno.h> 499865SSaurabh.Mishra@Sun.COM #include <sys/sdt.h> 509865SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h> 519865SSaurabh.Mishra@Sun.COM 529865SSaurabh.Mishra@Sun.COM #include "bfe.h" 539865SSaurabh.Mishra@Sun.COM #include "bfe_hw.h" 549865SSaurabh.Mishra@Sun.COM 559865SSaurabh.Mishra@Sun.COM 569865SSaurabh.Mishra@Sun.COM /* 579865SSaurabh.Mishra@Sun.COM * Broadcom BCM4401 chipsets use two rings : 589865SSaurabh.Mishra@Sun.COM * 599865SSaurabh.Mishra@Sun.COM * - One TX : For sending packets down the wire. 609865SSaurabh.Mishra@Sun.COM * - One RX : For receving packets. 619865SSaurabh.Mishra@Sun.COM * 629865SSaurabh.Mishra@Sun.COM * Each ring can have any number of descriptors (configured during attach). 639865SSaurabh.Mishra@Sun.COM * As of now we configure only 128 descriptor per ring (TX/RX). Each descriptor 649865SSaurabh.Mishra@Sun.COM * has address (desc_addr) and control (desc_ctl) which holds a DMA buffer for 659865SSaurabh.Mishra@Sun.COM * the packet and control information (like start/end of frame or end of table). 669865SSaurabh.Mishra@Sun.COM * The descriptor table is allocated first and then a DMA buffer (for a packet) 679865SSaurabh.Mishra@Sun.COM * is allocated and linked to each descriptor. 689865SSaurabh.Mishra@Sun.COM * 699865SSaurabh.Mishra@Sun.COM * Each descriptor entry is bfe_desc_t structure in bfe. During TX/RX 709865SSaurabh.Mishra@Sun.COM * interrupt, the stat register will point to current descriptor being 719865SSaurabh.Mishra@Sun.COM * processed. 729865SSaurabh.Mishra@Sun.COM * 739865SSaurabh.Mishra@Sun.COM * Here's an example of TX and RX ring : 749865SSaurabh.Mishra@Sun.COM * 759865SSaurabh.Mishra@Sun.COM * TX: 769865SSaurabh.Mishra@Sun.COM * 779865SSaurabh.Mishra@Sun.COM * Base of the descriptor table is programmed using BFE_DMATX_CTRL control 789865SSaurabh.Mishra@Sun.COM * register. Each 'addr' points to DMA buffer (or packet data buffer) to 799865SSaurabh.Mishra@Sun.COM * be transmitted and 'ctl' has the length of the packet (usually MTU). 809865SSaurabh.Mishra@Sun.COM * 819865SSaurabh.Mishra@Sun.COM * ----------------------| 829865SSaurabh.Mishra@Sun.COM * | addr |Descriptor 0 | 839865SSaurabh.Mishra@Sun.COM * | ctl | | 849865SSaurabh.Mishra@Sun.COM * ----------------------| 859865SSaurabh.Mishra@Sun.COM * | addr |Descriptor 1 | SOF (start of the frame) 869865SSaurabh.Mishra@Sun.COM * | ctl | | 879865SSaurabh.Mishra@Sun.COM * ----------------------| 889865SSaurabh.Mishra@Sun.COM * | ... |Descriptor... | EOF (end of the frame) 899865SSaurabh.Mishra@Sun.COM * | ... | | 909865SSaurabh.Mishra@Sun.COM * ----------------------| 919865SSaurabh.Mishra@Sun.COM * | addr |Descritor 127 | 929865SSaurabh.Mishra@Sun.COM * | ctl | EOT | EOT (End of Table) 939865SSaurabh.Mishra@Sun.COM * ----------------------| 949865SSaurabh.Mishra@Sun.COM * 959865SSaurabh.Mishra@Sun.COM * 'r_curr_desc' : pointer to current descriptor which can be used to transmit 969865SSaurabh.Mishra@Sun.COM * a packet. 979865SSaurabh.Mishra@Sun.COM * 'r_avail_desc' : decremented whenever a packet is being sent. 989865SSaurabh.Mishra@Sun.COM * 'r_cons_desc' : incremented whenever a packet is sent down the wire and 999865SSaurabh.Mishra@Sun.COM * notified by an interrupt to bfe driver. 1009865SSaurabh.Mishra@Sun.COM * 1019865SSaurabh.Mishra@Sun.COM * RX: 1029865SSaurabh.Mishra@Sun.COM * 1039865SSaurabh.Mishra@Sun.COM * Base of the descriptor table is programmed using BFE_DMARX_CTRL control 1049865SSaurabh.Mishra@Sun.COM * register. Each 'addr' points to DMA buffer (or packet data buffer). 'ctl' 1059865SSaurabh.Mishra@Sun.COM * contains the size of the DMA buffer and all the DMA buffers are 1069865SSaurabh.Mishra@Sun.COM * pre-allocated during attach and hence the maxmium size of the packet is 1079865SSaurabh.Mishra@Sun.COM * also known (r_buf_len from the bfe_rint_t structure). During RX interrupt 1089865SSaurabh.Mishra@Sun.COM * the packet length is embedded in bfe_header_t which is added by the 1099865SSaurabh.Mishra@Sun.COM * chip in the beginning of the packet. 1109865SSaurabh.Mishra@Sun.COM * 1119865SSaurabh.Mishra@Sun.COM * ----------------------| 1129865SSaurabh.Mishra@Sun.COM * | addr |Descriptor 0 | 1139865SSaurabh.Mishra@Sun.COM * | ctl | | 1149865SSaurabh.Mishra@Sun.COM * ----------------------| 1159865SSaurabh.Mishra@Sun.COM * | addr |Descriptor 1 | 1169865SSaurabh.Mishra@Sun.COM * | ctl | | 1179865SSaurabh.Mishra@Sun.COM * ----------------------| 1189865SSaurabh.Mishra@Sun.COM * | ... |Descriptor... | 1199865SSaurabh.Mishra@Sun.COM * | ... | | 1209865SSaurabh.Mishra@Sun.COM * ----------------------| 1219865SSaurabh.Mishra@Sun.COM * | addr |Descriptor 127| 1229865SSaurabh.Mishra@Sun.COM * | ctl | EOT | EOT (End of Table) 1239865SSaurabh.Mishra@Sun.COM * ----------------------| 1249865SSaurabh.Mishra@Sun.COM * 1259865SSaurabh.Mishra@Sun.COM * 'r_curr_desc' : pointer to current descriptor while receving a packet. 1269865SSaurabh.Mishra@Sun.COM * 1279865SSaurabh.Mishra@Sun.COM */ 1289865SSaurabh.Mishra@Sun.COM 1299865SSaurabh.Mishra@Sun.COM #define MODULE_NAME "bfe" 1309865SSaurabh.Mishra@Sun.COM 1319865SSaurabh.Mishra@Sun.COM /* 1329865SSaurabh.Mishra@Sun.COM * Used for checking PHY (link state, speed) 1339865SSaurabh.Mishra@Sun.COM */ 1349865SSaurabh.Mishra@Sun.COM #define BFE_TIMEOUT_INTERVAL (1000 * 1000 * 1000) 1359865SSaurabh.Mishra@Sun.COM 1369865SSaurabh.Mishra@Sun.COM 1379865SSaurabh.Mishra@Sun.COM /* 1389865SSaurabh.Mishra@Sun.COM * Chip restart action and reason for restart 1399865SSaurabh.Mishra@Sun.COM */ 1409865SSaurabh.Mishra@Sun.COM #define BFE_ACTION_RESTART 0x1 /* For restarting the chip */ 1419865SSaurabh.Mishra@Sun.COM #define BFE_ACTION_RESTART_SETPROP 0x2 /* restart due to setprop */ 1429865SSaurabh.Mishra@Sun.COM #define BFE_ACTION_RESTART_FAULT 0x4 /* restart due to fault */ 1439865SSaurabh.Mishra@Sun.COM #define BFE_ACTION_RESTART_PKT 0x8 /* restart due to pkt timeout */ 1449865SSaurabh.Mishra@Sun.COM 1459865SSaurabh.Mishra@Sun.COM static char bfe_ident[] = "bfe driver for Broadcom BCM4401 chipsets"; 1469865SSaurabh.Mishra@Sun.COM 1479865SSaurabh.Mishra@Sun.COM /* 1489865SSaurabh.Mishra@Sun.COM * Function Prototypes for bfe driver. 1499865SSaurabh.Mishra@Sun.COM */ 1509865SSaurabh.Mishra@Sun.COM static int bfe_check_link(bfe_t *); 1519865SSaurabh.Mishra@Sun.COM static void bfe_report_link(bfe_t *); 1529865SSaurabh.Mishra@Sun.COM static void bfe_chip_halt(bfe_t *); 1539865SSaurabh.Mishra@Sun.COM static void bfe_chip_reset(bfe_t *); 1549865SSaurabh.Mishra@Sun.COM static void bfe_tx_desc_init(bfe_ring_t *); 1559865SSaurabh.Mishra@Sun.COM static void bfe_rx_desc_init(bfe_ring_t *); 1569865SSaurabh.Mishra@Sun.COM static void bfe_set_rx_mode(bfe_t *); 1579865SSaurabh.Mishra@Sun.COM static void bfe_enable_chip_intrs(bfe_t *); 1589865SSaurabh.Mishra@Sun.COM static void bfe_chip_restart(bfe_t *); 1599865SSaurabh.Mishra@Sun.COM static void bfe_init_vars(bfe_t *); 1609865SSaurabh.Mishra@Sun.COM static void bfe_clear_stats(bfe_t *); 1619865SSaurabh.Mishra@Sun.COM static void bfe_gather_stats(bfe_t *); 1629865SSaurabh.Mishra@Sun.COM static void bfe_error(dev_info_t *, char *, ...); 1639865SSaurabh.Mishra@Sun.COM static int bfe_mac_getprop(void *, const char *, mac_prop_id_t, uint_t, 164*11878SVenu.Iyer@Sun.COM void *); 1659865SSaurabh.Mishra@Sun.COM static int bfe_mac_setprop(void *, const char *, mac_prop_id_t, uint_t, 1669865SSaurabh.Mishra@Sun.COM const void *); 1679865SSaurabh.Mishra@Sun.COM static int bfe_tx_reclaim(bfe_ring_t *); 1689865SSaurabh.Mishra@Sun.COM int bfe_mac_set_ether_addr(void *, const uint8_t *); 1699865SSaurabh.Mishra@Sun.COM 1709865SSaurabh.Mishra@Sun.COM 1719865SSaurabh.Mishra@Sun.COM /* 1729865SSaurabh.Mishra@Sun.COM * Macros for ddi_dma_sync(). 1739865SSaurabh.Mishra@Sun.COM */ 1749865SSaurabh.Mishra@Sun.COM #define SYNC_DESC(r, s, l, d) \ 1759865SSaurabh.Mishra@Sun.COM (void) ddi_dma_sync(r->r_desc_dma_handle, \ 1769865SSaurabh.Mishra@Sun.COM (off_t)(s * sizeof (bfe_desc_t)), \ 1779865SSaurabh.Mishra@Sun.COM (size_t)(l * sizeof (bfe_desc_t)), \ 1789865SSaurabh.Mishra@Sun.COM d) 1799865SSaurabh.Mishra@Sun.COM 1809865SSaurabh.Mishra@Sun.COM #define SYNC_BUF(r, s, b, l, d) \ 1819865SSaurabh.Mishra@Sun.COM (void) ddi_dma_sync(r->r_buf_dma[s].handle, \ 1829865SSaurabh.Mishra@Sun.COM (off_t)(b), (size_t)(l), d) 1839865SSaurabh.Mishra@Sun.COM 1849865SSaurabh.Mishra@Sun.COM /* 1859865SSaurabh.Mishra@Sun.COM * Supported Broadcom BCM4401 Cards. 1869865SSaurabh.Mishra@Sun.COM */ 1879865SSaurabh.Mishra@Sun.COM static bfe_cards_t bfe_cards[] = { 1889865SSaurabh.Mishra@Sun.COM { 0x14e4, 0x170c, "BCM4401 100Base-TX"}, 1899865SSaurabh.Mishra@Sun.COM }; 1909865SSaurabh.Mishra@Sun.COM 1919865SSaurabh.Mishra@Sun.COM 1929865SSaurabh.Mishra@Sun.COM /* 1939865SSaurabh.Mishra@Sun.COM * DMA attributes for device registers, packet data (buffer) and 1949865SSaurabh.Mishra@Sun.COM * descriptor table. 1959865SSaurabh.Mishra@Sun.COM */ 1969865SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr bfe_dev_attr = { 1979865SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0, 1989865SSaurabh.Mishra@Sun.COM DDI_STRUCTURE_LE_ACC, 1999865SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC 2009865SSaurabh.Mishra@Sun.COM }; 2019865SSaurabh.Mishra@Sun.COM 2029865SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr bfe_buf_attr = { 2039865SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0, 2049865SSaurabh.Mishra@Sun.COM DDI_NEVERSWAP_ACC, /* native endianness */ 2059865SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC 2069865SSaurabh.Mishra@Sun.COM }; 2079865SSaurabh.Mishra@Sun.COM 2089865SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t bfe_dma_attr_buf = { 2099865SSaurabh.Mishra@Sun.COM DMA_ATTR_V0, /* dma_attr_version */ 2109865SSaurabh.Mishra@Sun.COM 0, /* dma_attr_addr_lo */ 2119865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_addr_hi */ 2129865SSaurabh.Mishra@Sun.COM 0x1fff, /* dma_attr_count_max */ 2139865SSaurabh.Mishra@Sun.COM 8, /* dma_attr_align */ 2149865SSaurabh.Mishra@Sun.COM 0, /* dma_attr_burstsizes */ 2159865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_minxfer */ 2169865SSaurabh.Mishra@Sun.COM 0x1fff, /* dma_attr_maxxfer */ 2179865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_seg */ 2189865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_sgllen */ 2199865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_granular */ 2209865SSaurabh.Mishra@Sun.COM 0 /* dma_attr_flags */ 2219865SSaurabh.Mishra@Sun.COM }; 2229865SSaurabh.Mishra@Sun.COM 2239865SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t bfe_dma_attr_desc = { 2249865SSaurabh.Mishra@Sun.COM DMA_ATTR_V0, /* dma_attr_version */ 2259865SSaurabh.Mishra@Sun.COM 0, /* dma_attr_addr_lo */ 2269865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_addr_hi */ 2279865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_count_max */ 2289865SSaurabh.Mishra@Sun.COM BFE_DESC_ALIGN, /* dma_attr_align */ 2299865SSaurabh.Mishra@Sun.COM 0, /* dma_attr_burstsizes */ 2309865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_minxfer */ 2319865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_maxxfer */ 2329865SSaurabh.Mishra@Sun.COM BFE_PCI_DMA - 1, /* dma_attr_seg */ 2339865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_sgllen */ 2349865SSaurabh.Mishra@Sun.COM 1, /* dma_attr_granular */ 2359865SSaurabh.Mishra@Sun.COM 0 /* dma_attr_flags */ 2369865SSaurabh.Mishra@Sun.COM }; 2379865SSaurabh.Mishra@Sun.COM 2389865SSaurabh.Mishra@Sun.COM /* 2399865SSaurabh.Mishra@Sun.COM * Ethernet broadcast addresses. 2409865SSaurabh.Mishra@Sun.COM */ 2419865SSaurabh.Mishra@Sun.COM static uchar_t bfe_broadcast[ETHERADDRL] = { 2429865SSaurabh.Mishra@Sun.COM 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2439865SSaurabh.Mishra@Sun.COM }; 2449865SSaurabh.Mishra@Sun.COM 2459865SSaurabh.Mishra@Sun.COM #define ASSERT_ALL_LOCKS(bfe) { \ 2469865SSaurabh.Mishra@Sun.COM ASSERT(mutex_owned(&bfe->bfe_tx_ring.r_lock)); \ 2479865SSaurabh.Mishra@Sun.COM ASSERT(rw_write_held(&bfe->bfe_rwlock)); \ 2489865SSaurabh.Mishra@Sun.COM } 2499865SSaurabh.Mishra@Sun.COM 2509865SSaurabh.Mishra@Sun.COM /* 2519865SSaurabh.Mishra@Sun.COM * Debugging and error reproting code. 2529865SSaurabh.Mishra@Sun.COM */ 2539865SSaurabh.Mishra@Sun.COM static void 2549865SSaurabh.Mishra@Sun.COM bfe_error(dev_info_t *dip, char *fmt, ...) 2559865SSaurabh.Mishra@Sun.COM { 2569865SSaurabh.Mishra@Sun.COM va_list ap; 2579865SSaurabh.Mishra@Sun.COM char buf[256]; 2589865SSaurabh.Mishra@Sun.COM 2599865SSaurabh.Mishra@Sun.COM va_start(ap, fmt); 2609865SSaurabh.Mishra@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap); 2619865SSaurabh.Mishra@Sun.COM va_end(ap); 2629865SSaurabh.Mishra@Sun.COM 2639865SSaurabh.Mishra@Sun.COM if (dip) { 2649865SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "%s%d: %s", 2659865SSaurabh.Mishra@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), buf); 2669865SSaurabh.Mishra@Sun.COM } else { 2679865SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "bfe: %s", buf); 2689865SSaurabh.Mishra@Sun.COM } 2699865SSaurabh.Mishra@Sun.COM } 2709865SSaurabh.Mishra@Sun.COM 2719865SSaurabh.Mishra@Sun.COM /* 2729865SSaurabh.Mishra@Sun.COM * Grabs all necessary locks to block any other operation on the chip. 2739865SSaurabh.Mishra@Sun.COM */ 2749865SSaurabh.Mishra@Sun.COM static void 2759865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe_t *bfe) 2769865SSaurabh.Mishra@Sun.COM { 2779865SSaurabh.Mishra@Sun.COM bfe_ring_t *tx = &bfe->bfe_tx_ring; 2789865SSaurabh.Mishra@Sun.COM 2799865SSaurabh.Mishra@Sun.COM /* 2809865SSaurabh.Mishra@Sun.COM * Grab all the locks. 2819865SSaurabh.Mishra@Sun.COM * - bfe_rwlock : locks down whole chip including RX. 2829865SSaurabh.Mishra@Sun.COM * - tx's r_lock : locks down only TX side. 2839865SSaurabh.Mishra@Sun.COM */ 2849865SSaurabh.Mishra@Sun.COM rw_enter(&bfe->bfe_rwlock, RW_WRITER); 2859865SSaurabh.Mishra@Sun.COM mutex_enter(&tx->r_lock); 2869865SSaurabh.Mishra@Sun.COM 2879865SSaurabh.Mishra@Sun.COM /* 2889865SSaurabh.Mishra@Sun.COM * Note that we don't use RX's r_lock. 2899865SSaurabh.Mishra@Sun.COM */ 2909865SSaurabh.Mishra@Sun.COM } 2919865SSaurabh.Mishra@Sun.COM 2929865SSaurabh.Mishra@Sun.COM /* 2939865SSaurabh.Mishra@Sun.COM * Release lock on chip/drver. 2949865SSaurabh.Mishra@Sun.COM */ 2959865SSaurabh.Mishra@Sun.COM static void 2969865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe_t *bfe) 2979865SSaurabh.Mishra@Sun.COM { 2989865SSaurabh.Mishra@Sun.COM bfe_ring_t *tx = &bfe->bfe_tx_ring; 2999865SSaurabh.Mishra@Sun.COM 3009865SSaurabh.Mishra@Sun.COM /* 3019865SSaurabh.Mishra@Sun.COM * Release all the locks in the order in which they were grabbed. 3029865SSaurabh.Mishra@Sun.COM */ 3039865SSaurabh.Mishra@Sun.COM mutex_exit(&tx->r_lock); 3049865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 3059865SSaurabh.Mishra@Sun.COM } 3069865SSaurabh.Mishra@Sun.COM 3079865SSaurabh.Mishra@Sun.COM 3089865SSaurabh.Mishra@Sun.COM /* 3099865SSaurabh.Mishra@Sun.COM * It's used to make sure that the write to device register was successful. 3109865SSaurabh.Mishra@Sun.COM */ 3119865SSaurabh.Mishra@Sun.COM static int 3129865SSaurabh.Mishra@Sun.COM bfe_wait_bit(bfe_t *bfe, uint32_t reg, uint32_t bit, 3139865SSaurabh.Mishra@Sun.COM ulong_t t, const int clear) 3149865SSaurabh.Mishra@Sun.COM { 3159865SSaurabh.Mishra@Sun.COM ulong_t i; 3169865SSaurabh.Mishra@Sun.COM uint32_t v; 3179865SSaurabh.Mishra@Sun.COM 3189865SSaurabh.Mishra@Sun.COM for (i = 0; i < t; i++) { 3199865SSaurabh.Mishra@Sun.COM v = INL(bfe, reg); 3209865SSaurabh.Mishra@Sun.COM 3219865SSaurabh.Mishra@Sun.COM if (clear && !(v & bit)) 3229865SSaurabh.Mishra@Sun.COM break; 3239865SSaurabh.Mishra@Sun.COM 3249865SSaurabh.Mishra@Sun.COM if (!clear && (v & bit)) 3259865SSaurabh.Mishra@Sun.COM break; 3269865SSaurabh.Mishra@Sun.COM 3279865SSaurabh.Mishra@Sun.COM drv_usecwait(10); 3289865SSaurabh.Mishra@Sun.COM } 3299865SSaurabh.Mishra@Sun.COM 3309865SSaurabh.Mishra@Sun.COM /* if device still didn't see the value */ 3319865SSaurabh.Mishra@Sun.COM if (i == t) 3329865SSaurabh.Mishra@Sun.COM return (-1); 3339865SSaurabh.Mishra@Sun.COM 3349865SSaurabh.Mishra@Sun.COM return (0); 3359865SSaurabh.Mishra@Sun.COM } 3369865SSaurabh.Mishra@Sun.COM 3379865SSaurabh.Mishra@Sun.COM /* 3389865SSaurabh.Mishra@Sun.COM * PHY functions (read, write, stop, reset and startup) 3399865SSaurabh.Mishra@Sun.COM */ 3409865SSaurabh.Mishra@Sun.COM static int 3419865SSaurabh.Mishra@Sun.COM bfe_read_phy(bfe_t *bfe, uint32_t reg) 3429865SSaurabh.Mishra@Sun.COM { 3439865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 3449865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 3459865SSaurabh.Mishra@Sun.COM (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | 3469865SSaurabh.Mishra@Sun.COM (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) | 3479865SSaurabh.Mishra@Sun.COM (reg << BFE_MDIO_RA_SHIFT) | 3489865SSaurabh.Mishra@Sun.COM (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); 3499865SSaurabh.Mishra@Sun.COM 3509865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0); 3519865SSaurabh.Mishra@Sun.COM 3529865SSaurabh.Mishra@Sun.COM return ((INL(bfe, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA)); 3539865SSaurabh.Mishra@Sun.COM } 3549865SSaurabh.Mishra@Sun.COM 3559865SSaurabh.Mishra@Sun.COM static void 3569865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe_t *bfe, uint32_t reg, uint32_t val) 3579865SSaurabh.Mishra@Sun.COM { 3589865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 3599865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 3609865SSaurabh.Mishra@Sun.COM (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | 3619865SSaurabh.Mishra@Sun.COM (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) | 3629865SSaurabh.Mishra@Sun.COM (reg << BFE_MDIO_RA_SHIFT) | 3639865SSaurabh.Mishra@Sun.COM (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | 3649865SSaurabh.Mishra@Sun.COM (val & BFE_MDIO_DATA_DATA))); 3659865SSaurabh.Mishra@Sun.COM 3669865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0); 3679865SSaurabh.Mishra@Sun.COM } 3689865SSaurabh.Mishra@Sun.COM 3699865SSaurabh.Mishra@Sun.COM /* 3709865SSaurabh.Mishra@Sun.COM * It resets the PHY layer. 3719865SSaurabh.Mishra@Sun.COM */ 3729865SSaurabh.Mishra@Sun.COM static int 3739865SSaurabh.Mishra@Sun.COM bfe_reset_phy(bfe_t *bfe) 3749865SSaurabh.Mishra@Sun.COM { 3759865SSaurabh.Mishra@Sun.COM uint32_t i; 3769865SSaurabh.Mishra@Sun.COM 3779865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_RESET); 3789865SSaurabh.Mishra@Sun.COM drv_usecwait(100); 3799865SSaurabh.Mishra@Sun.COM for (i = 0; i < 10; i++) { 3809865SSaurabh.Mishra@Sun.COM if (bfe_read_phy(bfe, MII_CONTROL) & 3819865SSaurabh.Mishra@Sun.COM MII_CONTROL_RESET) { 3829865SSaurabh.Mishra@Sun.COM drv_usecwait(500); 3839865SSaurabh.Mishra@Sun.COM continue; 3849865SSaurabh.Mishra@Sun.COM } 3859865SSaurabh.Mishra@Sun.COM 3869865SSaurabh.Mishra@Sun.COM break; 3879865SSaurabh.Mishra@Sun.COM } 3889865SSaurabh.Mishra@Sun.COM 3899865SSaurabh.Mishra@Sun.COM if (i == 10) { 3909865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "Timeout waiting for PHY to reset"); 3919865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_state = BFE_PHY_RESET_TIMEOUT; 3929865SSaurabh.Mishra@Sun.COM return (BFE_FAILURE); 3939865SSaurabh.Mishra@Sun.COM } 3949865SSaurabh.Mishra@Sun.COM 3959865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_state = BFE_PHY_RESET_DONE; 3969865SSaurabh.Mishra@Sun.COM 3979865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 3989865SSaurabh.Mishra@Sun.COM } 3999865SSaurabh.Mishra@Sun.COM 4009865SSaurabh.Mishra@Sun.COM /* 4019865SSaurabh.Mishra@Sun.COM * Make sure timer function is out of our way and especially during 4029865SSaurabh.Mishra@Sun.COM * detach. 4039865SSaurabh.Mishra@Sun.COM */ 4049865SSaurabh.Mishra@Sun.COM static void 4059865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe_t *bfe) 4069865SSaurabh.Mishra@Sun.COM { 4079865SSaurabh.Mishra@Sun.COM if (bfe->bfe_periodic_id) { 4089865SSaurabh.Mishra@Sun.COM ddi_periodic_delete(bfe->bfe_periodic_id); 4099865SSaurabh.Mishra@Sun.COM bfe->bfe_periodic_id = NULL; 4109865SSaurabh.Mishra@Sun.COM } 4119865SSaurabh.Mishra@Sun.COM } 4129865SSaurabh.Mishra@Sun.COM 4139865SSaurabh.Mishra@Sun.COM /* 4149865SSaurabh.Mishra@Sun.COM * Stops the PHY 4159865SSaurabh.Mishra@Sun.COM */ 4169865SSaurabh.Mishra@Sun.COM static void 4179865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe_t *bfe) 4189865SSaurabh.Mishra@Sun.COM { 4199865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_PWRDN | 4209865SSaurabh.Mishra@Sun.COM MII_CONTROL_ISOLATE); 4219865SSaurabh.Mishra@Sun.COM 4229865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.link = LINK_STATE_UNKNOWN; 4239865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 0; 4249865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN; 4259865SSaurabh.Mishra@Sun.COM 4269865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_state = BFE_PHY_STOPPED; 4279865SSaurabh.Mishra@Sun.COM 4289865SSaurabh.Mishra@Sun.COM /* 4299865SSaurabh.Mishra@Sun.COM * Report the link status to MAC layer. 4309865SSaurabh.Mishra@Sun.COM */ 4319865SSaurabh.Mishra@Sun.COM if (bfe->bfe_machdl != NULL) 4329865SSaurabh.Mishra@Sun.COM (void) bfe_report_link(bfe); 4339865SSaurabh.Mishra@Sun.COM } 4349865SSaurabh.Mishra@Sun.COM 4359865SSaurabh.Mishra@Sun.COM static int 4369865SSaurabh.Mishra@Sun.COM bfe_probe_phy(bfe_t *bfe) 4379865SSaurabh.Mishra@Sun.COM { 4389865SSaurabh.Mishra@Sun.COM int phy; 4399865SSaurabh.Mishra@Sun.COM uint32_t status; 4409865SSaurabh.Mishra@Sun.COM 4419865SSaurabh.Mishra@Sun.COM if (bfe->bfe_phy_addr) { 4429865SSaurabh.Mishra@Sun.COM status = bfe_read_phy(bfe, MII_STATUS); 4439865SSaurabh.Mishra@Sun.COM if (status != 0xffff && status != 0) { 4449865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_CONTROL, 0); 4459865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 4469865SSaurabh.Mishra@Sun.COM } 4479865SSaurabh.Mishra@Sun.COM } 4489865SSaurabh.Mishra@Sun.COM 4499865SSaurabh.Mishra@Sun.COM for (phy = 0; phy < 32; phy++) { 4509865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_addr = phy; 4519865SSaurabh.Mishra@Sun.COM status = bfe_read_phy(bfe, MII_STATUS); 4529865SSaurabh.Mishra@Sun.COM if (status != 0xffff && status != 0) { 4539865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_CONTROL, 0); 4549865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 4559865SSaurabh.Mishra@Sun.COM } 4569865SSaurabh.Mishra@Sun.COM } 4579865SSaurabh.Mishra@Sun.COM 4589865SSaurabh.Mishra@Sun.COM return (BFE_FAILURE); 4599865SSaurabh.Mishra@Sun.COM } 4609865SSaurabh.Mishra@Sun.COM 4619865SSaurabh.Mishra@Sun.COM /* 4629865SSaurabh.Mishra@Sun.COM * This timeout function fires at BFE_TIMEOUT_INTERVAL to check the link 4639865SSaurabh.Mishra@Sun.COM * status. 4649865SSaurabh.Mishra@Sun.COM */ 4659865SSaurabh.Mishra@Sun.COM static void 4669865SSaurabh.Mishra@Sun.COM bfe_timeout(void *arg) 4679865SSaurabh.Mishra@Sun.COM { 4689865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 46910591SSaurabh.Mishra@Sun.COM int resched = 0; 4709865SSaurabh.Mishra@Sun.COM 4719865SSaurabh.Mishra@Sun.COM /* 4729865SSaurabh.Mishra@Sun.COM * We don't grab any lock because bfe can't go away. 4739865SSaurabh.Mishra@Sun.COM * untimeout() will wait for this timeout instance to complete. 4749865SSaurabh.Mishra@Sun.COM */ 4759865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_action & BFE_ACTION_RESTART) { 4769865SSaurabh.Mishra@Sun.COM /* 4779865SSaurabh.Mishra@Sun.COM * Restart the chip. 4789865SSaurabh.Mishra@Sun.COM */ 4799865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 4809865SSaurabh.Mishra@Sun.COM bfe_chip_restart(bfe); 4819865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action &= ~BFE_ACTION_RESTART; 4829865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_FAULT; 4839865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_PKT; 4849865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 4859865SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 4869865SSaurabh.Mishra@Sun.COM /* Restart will register a new timeout */ 4879865SSaurabh.Mishra@Sun.COM return; 4889865SSaurabh.Mishra@Sun.COM } 4899865SSaurabh.Mishra@Sun.COM 4909865SSaurabh.Mishra@Sun.COM rw_enter(&bfe->bfe_rwlock, RW_READER); 4919865SSaurabh.Mishra@Sun.COM 4929865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) { 4939865SSaurabh.Mishra@Sun.COM hrtime_t hr; 4949865SSaurabh.Mishra@Sun.COM 4959865SSaurabh.Mishra@Sun.COM hr = gethrtime(); 4969865SSaurabh.Mishra@Sun.COM if (bfe->bfe_tx_stall_time != 0 && 4979865SSaurabh.Mishra@Sun.COM hr > bfe->bfe_tx_stall_time) { 4989865SSaurabh.Mishra@Sun.COM DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit, 4999865SSaurabh.Mishra@Sun.COM char *, "pkt timeout"); 5009865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= 5019865SSaurabh.Mishra@Sun.COM (BFE_ACTION_RESTART | BFE_ACTION_RESTART_PKT); 5029865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_stall_time = 0; 5039865SSaurabh.Mishra@Sun.COM } 5049865SSaurabh.Mishra@Sun.COM } 5059865SSaurabh.Mishra@Sun.COM 5069865SSaurabh.Mishra@Sun.COM if (bfe->bfe_phy_state == BFE_PHY_STARTED) { 5079865SSaurabh.Mishra@Sun.COM /* 5089865SSaurabh.Mishra@Sun.COM * Report the link status to MAC layer if link status changed. 5099865SSaurabh.Mishra@Sun.COM */ 5109865SSaurabh.Mishra@Sun.COM if (bfe_check_link(bfe)) { 5119865SSaurabh.Mishra@Sun.COM bfe_report_link(bfe); 5129865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip.link == LINK_STATE_UP) { 5139865SSaurabh.Mishra@Sun.COM uint32_t val, flow; 5149865SSaurabh.Mishra@Sun.COM 5159865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_TX_CTRL); 5169865SSaurabh.Mishra@Sun.COM val &= ~BFE_TX_DUPLEX; 5179865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip.duplex == LINK_DUPLEX_FULL) { 5189865SSaurabh.Mishra@Sun.COM val |= BFE_TX_DUPLEX; 5199865SSaurabh.Mishra@Sun.COM flow = INL(bfe, BFE_RXCONF); 5209865SSaurabh.Mishra@Sun.COM flow &= ~BFE_RXCONF_FLOW; 5219865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RXCONF, flow); 5229865SSaurabh.Mishra@Sun.COM 5239865SSaurabh.Mishra@Sun.COM flow = INL(bfe, BFE_MAC_FLOW); 5249865SSaurabh.Mishra@Sun.COM flow &= ~(BFE_FLOW_RX_HIWAT); 5259865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_MAC_FLOW, flow); 5269865SSaurabh.Mishra@Sun.COM } 5279865SSaurabh.Mishra@Sun.COM 52810591SSaurabh.Mishra@Sun.COM resched = 1; 52910591SSaurabh.Mishra@Sun.COM 5309865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_TX_CTRL, val); 5319865SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(link__up, 5329865SSaurabh.Mishra@Sun.COM int, bfe->bfe_unit); 5339865SSaurabh.Mishra@Sun.COM } 5349865SSaurabh.Mishra@Sun.COM } 5359865SSaurabh.Mishra@Sun.COM } 5369865SSaurabh.Mishra@Sun.COM 5379865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 53810591SSaurabh.Mishra@Sun.COM 53910591SSaurabh.Mishra@Sun.COM if (resched) 54010591SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 5419865SSaurabh.Mishra@Sun.COM } 5429865SSaurabh.Mishra@Sun.COM 5439865SSaurabh.Mishra@Sun.COM /* 5449865SSaurabh.Mishra@Sun.COM * Starts PHY layer. 5459865SSaurabh.Mishra@Sun.COM */ 5469865SSaurabh.Mishra@Sun.COM static int 5479865SSaurabh.Mishra@Sun.COM bfe_startup_phy(bfe_t *bfe) 5489865SSaurabh.Mishra@Sun.COM { 5499865SSaurabh.Mishra@Sun.COM uint16_t bmsr, bmcr, anar; 5509865SSaurabh.Mishra@Sun.COM int prog, s; 5519865SSaurabh.Mishra@Sun.COM int phyid1, phyid2; 5529865SSaurabh.Mishra@Sun.COM 5539865SSaurabh.Mishra@Sun.COM if (bfe_probe_phy(bfe) == BFE_FAILURE) { 5549865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_state = BFE_PHY_NOTFOUND; 5559865SSaurabh.Mishra@Sun.COM return (BFE_FAILURE); 5569865SSaurabh.Mishra@Sun.COM } 5579865SSaurabh.Mishra@Sun.COM 5589865SSaurabh.Mishra@Sun.COM (void) bfe_reset_phy(bfe); 5599865SSaurabh.Mishra@Sun.COM 5609865SSaurabh.Mishra@Sun.COM phyid1 = bfe_read_phy(bfe, MII_PHYIDH); 5619865SSaurabh.Mishra@Sun.COM phyid2 = bfe_read_phy(bfe, MII_PHYIDL); 5629865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_id = (phyid1 << 16) | phyid2; 5639865SSaurabh.Mishra@Sun.COM 5649865SSaurabh.Mishra@Sun.COM bmsr = bfe_read_phy(bfe, MII_STATUS); 5659865SSaurabh.Mishra@Sun.COM anar = bfe_read_phy(bfe, MII_AN_ADVERT); 5669865SSaurabh.Mishra@Sun.COM 5679865SSaurabh.Mishra@Sun.COM again: 5689865SSaurabh.Mishra@Sun.COM anar &= ~(MII_ABILITY_100BASE_T4 | 5699865SSaurabh.Mishra@Sun.COM MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX | 5709865SSaurabh.Mishra@Sun.COM MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T); 5719865SSaurabh.Mishra@Sun.COM 5729865SSaurabh.Mishra@Sun.COM /* 5739865SSaurabh.Mishra@Sun.COM * Supported hardware modes are in bmsr. 5749865SSaurabh.Mishra@Sun.COM */ 5759865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.bmsr = bmsr; 5769865SSaurabh.Mishra@Sun.COM 5779865SSaurabh.Mishra@Sun.COM /* 5789865SSaurabh.Mishra@Sun.COM * Assume no capabilities are supported in the hardware. 5799865SSaurabh.Mishra@Sun.COM */ 5809865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_aneg = bfe->bfe_cap_100T4 = 5819865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_100fdx = bfe->bfe_cap_100hdx = 5829865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_10fdx = bfe->bfe_cap_10hdx = 0; 5839865SSaurabh.Mishra@Sun.COM 5849865SSaurabh.Mishra@Sun.COM /* 5859865SSaurabh.Mishra@Sun.COM * Assume property is set. 5869865SSaurabh.Mishra@Sun.COM */ 5879865SSaurabh.Mishra@Sun.COM s = 1; 5889865SSaurabh.Mishra@Sun.COM if (!(bfe->bfe_chip_action & BFE_ACTION_RESTART_SETPROP)) { 5899865SSaurabh.Mishra@Sun.COM /* 5909865SSaurabh.Mishra@Sun.COM * Property is not set which means bfe_mac_setprop() 5919865SSaurabh.Mishra@Sun.COM * is not called on us. 5929865SSaurabh.Mishra@Sun.COM */ 5939865SSaurabh.Mishra@Sun.COM s = 0; 5949865SSaurabh.Mishra@Sun.COM } 5959865SSaurabh.Mishra@Sun.COM 5969865SSaurabh.Mishra@Sun.COM bmcr = prog = 0; 5979865SSaurabh.Mishra@Sun.COM 5989865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_100_BASEX_FD) { 5999865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_100fdx = 1; 6009865SSaurabh.Mishra@Sun.COM if (s == 0) { 6019865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_TX_FD; 6029865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_100fdx = 1; 6039865SSaurabh.Mishra@Sun.COM prog++; 6049865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_adv_100fdx) { 6059865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_TX_FD; 6069865SSaurabh.Mishra@Sun.COM prog++; 6079865SSaurabh.Mishra@Sun.COM } 6089865SSaurabh.Mishra@Sun.COM } 6099865SSaurabh.Mishra@Sun.COM 6109865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_100_BASE_T4) { 6119865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_100T4 = 1; 6129865SSaurabh.Mishra@Sun.COM if (s == 0) { 6139865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_T4; 6149865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_100T4 = 1; 6159865SSaurabh.Mishra@Sun.COM prog++; 6169865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_adv_100T4) { 6179865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_T4; 6189865SSaurabh.Mishra@Sun.COM prog++; 6199865SSaurabh.Mishra@Sun.COM } 6209865SSaurabh.Mishra@Sun.COM } 6219865SSaurabh.Mishra@Sun.COM 6229865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_100_BASEX) { 6239865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_100hdx = 1; 6249865SSaurabh.Mishra@Sun.COM if (s == 0) { 6259865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_TX; 6269865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_100hdx = 1; 6279865SSaurabh.Mishra@Sun.COM prog++; 6289865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_adv_100hdx) { 6299865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_100BASE_TX; 6309865SSaurabh.Mishra@Sun.COM prog++; 6319865SSaurabh.Mishra@Sun.COM } 6329865SSaurabh.Mishra@Sun.COM } 6339865SSaurabh.Mishra@Sun.COM 6349865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_10_FD) { 6359865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_10fdx = 1; 6369865SSaurabh.Mishra@Sun.COM if (s == 0) { 6379865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_10BASE_T_FD; 6389865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_10fdx = 1; 6399865SSaurabh.Mishra@Sun.COM prog++; 6409865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_adv_10fdx) { 6419865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_10BASE_T_FD; 6429865SSaurabh.Mishra@Sun.COM prog++; 6439865SSaurabh.Mishra@Sun.COM } 6449865SSaurabh.Mishra@Sun.COM } 6459865SSaurabh.Mishra@Sun.COM 6469865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_10) { 6479865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_10hdx = 1; 6489865SSaurabh.Mishra@Sun.COM if (s == 0) { 6499865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_10BASE_T; 6509865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_10hdx = 1; 6519865SSaurabh.Mishra@Sun.COM prog++; 6529865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_adv_10hdx) { 6539865SSaurabh.Mishra@Sun.COM anar |= MII_ABILITY_10BASE_T; 6549865SSaurabh.Mishra@Sun.COM prog++; 6559865SSaurabh.Mishra@Sun.COM } 6569865SSaurabh.Mishra@Sun.COM } 6579865SSaurabh.Mishra@Sun.COM 6589865SSaurabh.Mishra@Sun.COM if (bmsr & MII_STATUS_CANAUTONEG) { 6599865SSaurabh.Mishra@Sun.COM bfe->bfe_cap_aneg = 1; 6609865SSaurabh.Mishra@Sun.COM if (s == 0) { 6619865SSaurabh.Mishra@Sun.COM bfe->bfe_adv_aneg = 1; 6629865SSaurabh.Mishra@Sun.COM } 6639865SSaurabh.Mishra@Sun.COM } 6649865SSaurabh.Mishra@Sun.COM 6659865SSaurabh.Mishra@Sun.COM if (prog == 0) { 6669865SSaurabh.Mishra@Sun.COM if (s == 0) { 6679865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, 6689865SSaurabh.Mishra@Sun.COM "No valid link mode selected. Powering down PHY"); 6699865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 6709865SSaurabh.Mishra@Sun.COM bfe_report_link(bfe); 6719865SSaurabh.Mishra@Sun.COM return (BFE_FAILURE); 6729865SSaurabh.Mishra@Sun.COM } 6739865SSaurabh.Mishra@Sun.COM 6749865SSaurabh.Mishra@Sun.COM /* 6759865SSaurabh.Mishra@Sun.COM * If property is set then user would have goofed up. So we 6769865SSaurabh.Mishra@Sun.COM * go back to default properties. 6779865SSaurabh.Mishra@Sun.COM */ 6789865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_SETPROP; 6799865SSaurabh.Mishra@Sun.COM goto again; 6809865SSaurabh.Mishra@Sun.COM } 6819865SSaurabh.Mishra@Sun.COM 6829865SSaurabh.Mishra@Sun.COM if (bfe->bfe_adv_aneg && (bmsr & MII_STATUS_CANAUTONEG)) { 6839865SSaurabh.Mishra@Sun.COM bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN); 6849865SSaurabh.Mishra@Sun.COM } else { 6859865SSaurabh.Mishra@Sun.COM if (bfe->bfe_adv_100fdx) 6869865SSaurabh.Mishra@Sun.COM bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 6879865SSaurabh.Mishra@Sun.COM else if (bfe->bfe_adv_100hdx) 6889865SSaurabh.Mishra@Sun.COM bmcr = MII_CONTROL_100MB; 6899865SSaurabh.Mishra@Sun.COM else if (bfe->bfe_adv_10fdx) 6909865SSaurabh.Mishra@Sun.COM bmcr = MII_CONTROL_FDUPLEX; 6919865SSaurabh.Mishra@Sun.COM else 6929865SSaurabh.Mishra@Sun.COM bmcr = 0; /* 10HDX */ 6939865SSaurabh.Mishra@Sun.COM } 6949865SSaurabh.Mishra@Sun.COM 6959865SSaurabh.Mishra@Sun.COM if (prog) 6969865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_AN_ADVERT, anar); 6979865SSaurabh.Mishra@Sun.COM 6989865SSaurabh.Mishra@Sun.COM if (bmcr) 6999865SSaurabh.Mishra@Sun.COM bfe_write_phy(bfe, MII_CONTROL, bmcr); 7009865SSaurabh.Mishra@Sun.COM 7019865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_anar = anar; 7029865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_bmcr = bmcr; 7039865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_state = BFE_PHY_STARTED; 7049865SSaurabh.Mishra@Sun.COM 7059865SSaurabh.Mishra@Sun.COM if (bfe->bfe_periodic_id == NULL) { 7069865SSaurabh.Mishra@Sun.COM bfe->bfe_periodic_id = ddi_periodic_add(bfe_timeout, 7079865SSaurabh.Mishra@Sun.COM (void *)bfe, BFE_TIMEOUT_INTERVAL, DDI_IPL_0); 7089865SSaurabh.Mishra@Sun.COM 7099865SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(first__timeout, int, bfe->bfe_unit); 7109865SSaurabh.Mishra@Sun.COM } 7119865SSaurabh.Mishra@Sun.COM 7129865SSaurabh.Mishra@Sun.COM DTRACE_PROBE4(phy_started, int, bfe->bfe_unit, 7139865SSaurabh.Mishra@Sun.COM int, bmsr, int, bmcr, int, anar); 7149865SSaurabh.Mishra@Sun.COM 7159865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 7169865SSaurabh.Mishra@Sun.COM } 7179865SSaurabh.Mishra@Sun.COM 7189865SSaurabh.Mishra@Sun.COM /* 7199865SSaurabh.Mishra@Sun.COM * Reports link status back to MAC Layer. 7209865SSaurabh.Mishra@Sun.COM */ 7219865SSaurabh.Mishra@Sun.COM static void 7229865SSaurabh.Mishra@Sun.COM bfe_report_link(bfe_t *bfe) 7239865SSaurabh.Mishra@Sun.COM { 7249865SSaurabh.Mishra@Sun.COM mac_link_update(bfe->bfe_machdl, bfe->bfe_chip.link); 7259865SSaurabh.Mishra@Sun.COM } 7269865SSaurabh.Mishra@Sun.COM 7279865SSaurabh.Mishra@Sun.COM /* 7289865SSaurabh.Mishra@Sun.COM * Reads PHY/MII registers and get the link status for us. 7299865SSaurabh.Mishra@Sun.COM */ 7309865SSaurabh.Mishra@Sun.COM static int 7319865SSaurabh.Mishra@Sun.COM bfe_check_link(bfe_t *bfe) 7329865SSaurabh.Mishra@Sun.COM { 7339865SSaurabh.Mishra@Sun.COM uint16_t bmsr, bmcr, anar, anlpar; 7349865SSaurabh.Mishra@Sun.COM int speed, duplex, link; 7359865SSaurabh.Mishra@Sun.COM 7369865SSaurabh.Mishra@Sun.COM speed = bfe->bfe_chip.speed; 7379865SSaurabh.Mishra@Sun.COM duplex = bfe->bfe_chip.duplex; 7389865SSaurabh.Mishra@Sun.COM link = bfe->bfe_chip.link; 7399865SSaurabh.Mishra@Sun.COM 7409865SSaurabh.Mishra@Sun.COM bmsr = bfe_read_phy(bfe, MII_STATUS); 7419865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_bmsr = bmsr; 7429865SSaurabh.Mishra@Sun.COM 7439865SSaurabh.Mishra@Sun.COM bmcr = bfe_read_phy(bfe, MII_CONTROL); 7449865SSaurabh.Mishra@Sun.COM 7459865SSaurabh.Mishra@Sun.COM anar = bfe_read_phy(bfe, MII_AN_ADVERT); 7469865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_anar = anar; 7479865SSaurabh.Mishra@Sun.COM 7489865SSaurabh.Mishra@Sun.COM anlpar = bfe_read_phy(bfe, MII_AN_LPABLE); 7499865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_anlpar = anlpar; 7509865SSaurabh.Mishra@Sun.COM 7519865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_exp = bfe_read_phy(bfe, MII_AN_EXPANSION); 7529865SSaurabh.Mishra@Sun.COM 7539865SSaurabh.Mishra@Sun.COM /* 7549865SSaurabh.Mishra@Sun.COM * If exp register is not present in PHY. 7559865SSaurabh.Mishra@Sun.COM */ 7569865SSaurabh.Mishra@Sun.COM if (bfe->bfe_mii_exp == 0xffff) { 7579865SSaurabh.Mishra@Sun.COM bfe->bfe_mii_exp = 0; 7589865SSaurabh.Mishra@Sun.COM } 7599865SSaurabh.Mishra@Sun.COM 7609865SSaurabh.Mishra@Sun.COM if ((bmsr & MII_STATUS_LINKUP) == 0) { 7619865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.link = LINK_STATE_DOWN; 7629865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 0; 7639865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN; 7649865SSaurabh.Mishra@Sun.COM goto done; 7659865SSaurabh.Mishra@Sun.COM } 7669865SSaurabh.Mishra@Sun.COM 7679865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.link = LINK_STATE_UP; 7689865SSaurabh.Mishra@Sun.COM 7699865SSaurabh.Mishra@Sun.COM if (!(bmcr & MII_CONTROL_ANE)) { 7709865SSaurabh.Mishra@Sun.COM /* Forced mode */ 7719865SSaurabh.Mishra@Sun.COM if (bmcr & MII_CONTROL_100MB) 7729865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 100000000; 7739865SSaurabh.Mishra@Sun.COM else 7749865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 10000000; 7759865SSaurabh.Mishra@Sun.COM 7769865SSaurabh.Mishra@Sun.COM if (bmcr & MII_CONTROL_FDUPLEX) 7779865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_FULL; 7789865SSaurabh.Mishra@Sun.COM else 7799865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_HALF; 7809865SSaurabh.Mishra@Sun.COM 7819865SSaurabh.Mishra@Sun.COM } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) || 7829865SSaurabh.Mishra@Sun.COM (!(bmsr & MII_STATUS_ANDONE))) { 7839865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 0; 7849865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN; 7859865SSaurabh.Mishra@Sun.COM } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) { 7869865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 100000000; 7879865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_FULL; 7889865SSaurabh.Mishra@Sun.COM } else if (anar & anlpar & MII_ABILITY_100BASE_T4) { 7899865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 100000000; 7909865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_HALF; 7919865SSaurabh.Mishra@Sun.COM } else if (anar & anlpar & MII_ABILITY_100BASE_TX) { 7929865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 100000000; 7939865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_HALF; 7949865SSaurabh.Mishra@Sun.COM } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) { 7959865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 10000000; 7969865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_FULL; 7979865SSaurabh.Mishra@Sun.COM } else if (anar & anlpar & MII_ABILITY_10BASE_T) { 7989865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 10000000; 7999865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_HALF; 8009865SSaurabh.Mishra@Sun.COM } else { 8019865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 0; 8029865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN; 8039865SSaurabh.Mishra@Sun.COM } 8049865SSaurabh.Mishra@Sun.COM 8059865SSaurabh.Mishra@Sun.COM done: 8069865SSaurabh.Mishra@Sun.COM /* 8079865SSaurabh.Mishra@Sun.COM * If speed or link status or duplex mode changed then report to 8089865SSaurabh.Mishra@Sun.COM * MAC layer which is done by the caller. 8099865SSaurabh.Mishra@Sun.COM */ 8109865SSaurabh.Mishra@Sun.COM if (speed != bfe->bfe_chip.speed || 8119865SSaurabh.Mishra@Sun.COM duplex != bfe->bfe_chip.duplex || 8129865SSaurabh.Mishra@Sun.COM link != bfe->bfe_chip.link) { 8139865SSaurabh.Mishra@Sun.COM return (1); 8149865SSaurabh.Mishra@Sun.COM } 8159865SSaurabh.Mishra@Sun.COM 8169865SSaurabh.Mishra@Sun.COM return (0); 8179865SSaurabh.Mishra@Sun.COM } 8189865SSaurabh.Mishra@Sun.COM 8199865SSaurabh.Mishra@Sun.COM static void 8209865SSaurabh.Mishra@Sun.COM bfe_cam_write(bfe_t *bfe, uchar_t *d, int index) 8219865SSaurabh.Mishra@Sun.COM { 8229865SSaurabh.Mishra@Sun.COM uint32_t v; 8239865SSaurabh.Mishra@Sun.COM 8249865SSaurabh.Mishra@Sun.COM v = ((uint32_t)d[2] << 24); 8259865SSaurabh.Mishra@Sun.COM v |= ((uint32_t)d[3] << 16); 8269865SSaurabh.Mishra@Sun.COM v |= ((uint32_t)d[4] << 8); 8279865SSaurabh.Mishra@Sun.COM v |= (uint32_t)d[5]; 8289865SSaurabh.Mishra@Sun.COM 8299865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_CAM_DATA_LO, v); 8309865SSaurabh.Mishra@Sun.COM v = (BFE_CAM_HI_VALID | 8319865SSaurabh.Mishra@Sun.COM (((uint32_t)d[0]) << 8) | 8329865SSaurabh.Mishra@Sun.COM (((uint32_t)d[1]))); 8339865SSaurabh.Mishra@Sun.COM 8349865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_CAM_DATA_HI, v); 8359865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_CAM_CTRL, (BFE_CAM_WRITE | 8369865SSaurabh.Mishra@Sun.COM ((uint32_t)index << BFE_CAM_INDEX_SHIFT))); 8379865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_CAM_CTRL, BFE_CAM_BUSY, 10, 1); 8389865SSaurabh.Mishra@Sun.COM } 8399865SSaurabh.Mishra@Sun.COM 8409865SSaurabh.Mishra@Sun.COM /* 8419865SSaurabh.Mishra@Sun.COM * Chip related functions (halt, reset, start). 8429865SSaurabh.Mishra@Sun.COM */ 8439865SSaurabh.Mishra@Sun.COM static void 8449865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe_t *bfe) 8459865SSaurabh.Mishra@Sun.COM { 8469865SSaurabh.Mishra@Sun.COM /* 8479865SSaurabh.Mishra@Sun.COM * Disables interrupts. 8489865SSaurabh.Mishra@Sun.COM */ 8499865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_INTR_MASK, 0); 8509865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_INTR_MASK); 8519865SSaurabh.Mishra@Sun.COM 8529865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE); 8539865SSaurabh.Mishra@Sun.COM 8549865SSaurabh.Mishra@Sun.COM /* 8559865SSaurabh.Mishra@Sun.COM * Wait until TX and RX finish their job. 8569865SSaurabh.Mishra@Sun.COM */ 8579865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE, 20, 1); 8589865SSaurabh.Mishra@Sun.COM 8599865SSaurabh.Mishra@Sun.COM /* 8609865SSaurabh.Mishra@Sun.COM * Disables DMA engine. 8619865SSaurabh.Mishra@Sun.COM */ 8629865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMARX_CTRL, 0); 8639865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMATX_CTRL, 0); 8649865SSaurabh.Mishra@Sun.COM 8659865SSaurabh.Mishra@Sun.COM drv_usecwait(10); 8669865SSaurabh.Mishra@Sun.COM 8679865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_HALT; 8689865SSaurabh.Mishra@Sun.COM } 8699865SSaurabh.Mishra@Sun.COM 8709865SSaurabh.Mishra@Sun.COM static void 8719865SSaurabh.Mishra@Sun.COM bfe_chip_restart(bfe_t *bfe) 8729865SSaurabh.Mishra@Sun.COM { 8739865SSaurabh.Mishra@Sun.COM DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit, 8749865SSaurabh.Mishra@Sun.COM int, bfe->bfe_chip_action); 8759865SSaurabh.Mishra@Sun.COM 8769865SSaurabh.Mishra@Sun.COM /* 8779865SSaurabh.Mishra@Sun.COM * Halt chip and PHY. 8789865SSaurabh.Mishra@Sun.COM */ 8799865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 8809865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 8819865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_STOPPED; 8829865SSaurabh.Mishra@Sun.COM 8839865SSaurabh.Mishra@Sun.COM /* 8849865SSaurabh.Mishra@Sun.COM * Init variables. 8859865SSaurabh.Mishra@Sun.COM */ 8869865SSaurabh.Mishra@Sun.COM bfe_init_vars(bfe); 8879865SSaurabh.Mishra@Sun.COM 8889865SSaurabh.Mishra@Sun.COM /* 8899865SSaurabh.Mishra@Sun.COM * Reset chip and start PHY. 8909865SSaurabh.Mishra@Sun.COM */ 8919865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe); 8929865SSaurabh.Mishra@Sun.COM 8939865SSaurabh.Mishra@Sun.COM /* 8949865SSaurabh.Mishra@Sun.COM * DMA descriptor rings. 8959865SSaurabh.Mishra@Sun.COM */ 8969865SSaurabh.Mishra@Sun.COM bfe_tx_desc_init(&bfe->bfe_tx_ring); 8979865SSaurabh.Mishra@Sun.COM bfe_rx_desc_init(&bfe->bfe_rx_ring); 8989865SSaurabh.Mishra@Sun.COM 8999865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_ACTIVE; 9009865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe); 9019865SSaurabh.Mishra@Sun.COM bfe_enable_chip_intrs(bfe); 9029865SSaurabh.Mishra@Sun.COM } 9039865SSaurabh.Mishra@Sun.COM 9049865SSaurabh.Mishra@Sun.COM /* 9059865SSaurabh.Mishra@Sun.COM * Disables core by stopping the clock. 9069865SSaurabh.Mishra@Sun.COM */ 9079865SSaurabh.Mishra@Sun.COM static void 9089865SSaurabh.Mishra@Sun.COM bfe_core_disable(bfe_t *bfe) 9099865SSaurabh.Mishra@Sun.COM { 9109865SSaurabh.Mishra@Sun.COM if ((INL(bfe, BFE_SBTMSLOW) & BFE_RESET)) 9119865SSaurabh.Mishra@Sun.COM return; 9129865SSaurabh.Mishra@Sun.COM 9139865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); 9149865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_SBTMSLOW, BFE_REJECT, 100, 0); 9159865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_SBTMSHIGH, BFE_BUSY, 100, 1); 9169865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | BFE_RESET)); 9179865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_SBTMSLOW); 9189865SSaurabh.Mishra@Sun.COM drv_usecwait(10); 9199865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); 9209865SSaurabh.Mishra@Sun.COM drv_usecwait(10); 9219865SSaurabh.Mishra@Sun.COM } 9229865SSaurabh.Mishra@Sun.COM 9239865SSaurabh.Mishra@Sun.COM /* 9249865SSaurabh.Mishra@Sun.COM * Resets core. 9259865SSaurabh.Mishra@Sun.COM */ 9269865SSaurabh.Mishra@Sun.COM static void 9279865SSaurabh.Mishra@Sun.COM bfe_core_reset(bfe_t *bfe) 9289865SSaurabh.Mishra@Sun.COM { 9299865SSaurabh.Mishra@Sun.COM uint32_t val; 9309865SSaurabh.Mishra@Sun.COM 9319865SSaurabh.Mishra@Sun.COM /* 9329865SSaurabh.Mishra@Sun.COM * First disable the core. 9339865SSaurabh.Mishra@Sun.COM */ 9349865SSaurabh.Mishra@Sun.COM bfe_core_disable(bfe); 9359865SSaurabh.Mishra@Sun.COM 9369865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); 9379865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_SBTMSLOW); 9389865SSaurabh.Mishra@Sun.COM drv_usecwait(1); 9399865SSaurabh.Mishra@Sun.COM 9409865SSaurabh.Mishra@Sun.COM if (INL(bfe, BFE_SBTMSHIGH) & BFE_SERR) 9419865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSHIGH, 0); 9429865SSaurabh.Mishra@Sun.COM 9439865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_SBIMSTATE); 9449865SSaurabh.Mishra@Sun.COM if (val & (BFE_IBE | BFE_TO)) 9459865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); 9469865SSaurabh.Mishra@Sun.COM 9479865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); 9489865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_SBTMSLOW); 9499865SSaurabh.Mishra@Sun.COM drv_usecwait(1); 9509865SSaurabh.Mishra@Sun.COM 9519865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBTMSLOW, BFE_CLOCK); 9529865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_SBTMSLOW); 9539865SSaurabh.Mishra@Sun.COM drv_usecwait(1); 9549865SSaurabh.Mishra@Sun.COM } 9559865SSaurabh.Mishra@Sun.COM 9569865SSaurabh.Mishra@Sun.COM static void 9579865SSaurabh.Mishra@Sun.COM bfe_setup_config(bfe_t *bfe, uint32_t cores) 9589865SSaurabh.Mishra@Sun.COM { 9599865SSaurabh.Mishra@Sun.COM uint32_t bar_orig, val; 9609865SSaurabh.Mishra@Sun.COM 9619865SSaurabh.Mishra@Sun.COM /* 9629865SSaurabh.Mishra@Sun.COM * Change bar0 window to map sbtopci registers. 9639865SSaurabh.Mishra@Sun.COM */ 9649865SSaurabh.Mishra@Sun.COM bar_orig = pci_config_get32(bfe->bfe_conf_handle, BFE_BAR0_WIN); 9659865SSaurabh.Mishra@Sun.COM pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, BFE_REG_PCI); 9669865SSaurabh.Mishra@Sun.COM 9679865SSaurabh.Mishra@Sun.COM /* Just read it and don't do anything */ 9689865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_SBIDHIGH) & BFE_IDH_CORE; 9699865SSaurabh.Mishra@Sun.COM 9709865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_SBINTVEC); 9719865SSaurabh.Mishra@Sun.COM val |= cores; 9729865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SBINTVEC, val); 9739865SSaurabh.Mishra@Sun.COM 9749865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_SSB_PCI_TRANS_2); 9759865SSaurabh.Mishra@Sun.COM val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; 9769865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_SSB_PCI_TRANS_2, val); 9779865SSaurabh.Mishra@Sun.COM 9789865SSaurabh.Mishra@Sun.COM /* 9799865SSaurabh.Mishra@Sun.COM * Restore bar0 window mapping. 9809865SSaurabh.Mishra@Sun.COM */ 9819865SSaurabh.Mishra@Sun.COM pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, bar_orig); 9829865SSaurabh.Mishra@Sun.COM } 9839865SSaurabh.Mishra@Sun.COM 9849865SSaurabh.Mishra@Sun.COM /* 9859865SSaurabh.Mishra@Sun.COM * Resets chip and starts PHY. 9869865SSaurabh.Mishra@Sun.COM */ 9879865SSaurabh.Mishra@Sun.COM static void 9889865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe_t *bfe) 9899865SSaurabh.Mishra@Sun.COM { 9909865SSaurabh.Mishra@Sun.COM uint32_t val; 9919865SSaurabh.Mishra@Sun.COM 9929865SSaurabh.Mishra@Sun.COM /* Set the interrupt vector for the enet core */ 9939865SSaurabh.Mishra@Sun.COM bfe_setup_config(bfe, BFE_INTVEC_ENET0); 9949865SSaurabh.Mishra@Sun.COM 9959865SSaurabh.Mishra@Sun.COM /* check if core is up */ 9969865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_SBTMSLOW) & 9979865SSaurabh.Mishra@Sun.COM (BFE_RESET | BFE_REJECT | BFE_CLOCK); 9989865SSaurabh.Mishra@Sun.COM 9999865SSaurabh.Mishra@Sun.COM if (val == BFE_CLOCK) { 10009865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RCV_LAZY, 0); 10019865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE); 10029865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_ENET_CTRL, 10039865SSaurabh.Mishra@Sun.COM BFE_ENET_DISABLE, 10, 1); 10049865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMATX_CTRL, 0); 10059865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_DMARX_STAT); 10069865SSaurabh.Mishra@Sun.COM drv_usecwait(20000); /* 20 milli seconds */ 10079865SSaurabh.Mishra@Sun.COM if (INL(bfe, BFE_DMARX_STAT) & BFE_STAT_EMASK) { 10089865SSaurabh.Mishra@Sun.COM (void) bfe_wait_bit(bfe, BFE_DMARX_STAT, BFE_STAT_SIDLE, 10099865SSaurabh.Mishra@Sun.COM 10, 0); 10109865SSaurabh.Mishra@Sun.COM } 10119865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMARX_CTRL, 0); 10129865SSaurabh.Mishra@Sun.COM } 10139865SSaurabh.Mishra@Sun.COM 10149865SSaurabh.Mishra@Sun.COM bfe_core_reset(bfe); 10159865SSaurabh.Mishra@Sun.COM bfe_clear_stats(bfe); 10169865SSaurabh.Mishra@Sun.COM 10179865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_MDIO_CTRL, 0x8d); 10189865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_DEVCTRL); 10199865SSaurabh.Mishra@Sun.COM if (!(val & BFE_IPP)) 10209865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_EPSEL); 10219865SSaurabh.Mishra@Sun.COM else if (INL(bfe, BFE_DEVCTRL & BFE_EPR)) { 10229865SSaurabh.Mishra@Sun.COM OUTL_AND(bfe, BFE_DEVCTRL, ~BFE_EPR); 10239865SSaurabh.Mishra@Sun.COM drv_usecwait(20000); /* 20 milli seconds */ 10249865SSaurabh.Mishra@Sun.COM } 10259865SSaurabh.Mishra@Sun.COM 10269865SSaurabh.Mishra@Sun.COM OUTL_OR(bfe, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); 10279865SSaurabh.Mishra@Sun.COM 10289865SSaurabh.Mishra@Sun.COM OUTL_AND(bfe, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN); 10299865SSaurabh.Mishra@Sun.COM 10309865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 10319865SSaurabh.Mishra@Sun.COM BFE_LAZY_FC_MASK)); 10329865SSaurabh.Mishra@Sun.COM 10339865SSaurabh.Mishra@Sun.COM OUTL_OR(bfe, BFE_RCV_LAZY, 0); 10349865SSaurabh.Mishra@Sun.COM 10359865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RXMAXLEN, bfe->bfe_rx_ring.r_buf_len); 10369865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_TXMAXLEN, bfe->bfe_tx_ring.r_buf_len); 10379865SSaurabh.Mishra@Sun.COM 10389865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_TX_WMARK, 56); 10399865SSaurabh.Mishra@Sun.COM 10409865SSaurabh.Mishra@Sun.COM /* Program DMA channels */ 10419865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); 10429865SSaurabh.Mishra@Sun.COM 10439865SSaurabh.Mishra@Sun.COM /* 10449865SSaurabh.Mishra@Sun.COM * DMA addresses need to be added to BFE_PCI_DMA 10459865SSaurabh.Mishra@Sun.COM */ 10469865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMATX_ADDR, 10479865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA); 10489865SSaurabh.Mishra@Sun.COM 10499865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) 10509865SSaurabh.Mishra@Sun.COM | BFE_RX_CTRL_ENABLE); 10519865SSaurabh.Mishra@Sun.COM 10529865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMARX_ADDR, 10539865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA); 10549865SSaurabh.Mishra@Sun.COM 10559865SSaurabh.Mishra@Sun.COM (void) bfe_startup_phy(bfe); 10569865SSaurabh.Mishra@Sun.COM 10579865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_INITIALIZED; 10589865SSaurabh.Mishra@Sun.COM } 10599865SSaurabh.Mishra@Sun.COM 10609865SSaurabh.Mishra@Sun.COM /* 10619865SSaurabh.Mishra@Sun.COM * It enables interrupts. Should be the last step while starting chip. 10629865SSaurabh.Mishra@Sun.COM */ 10639865SSaurabh.Mishra@Sun.COM static void 10649865SSaurabh.Mishra@Sun.COM bfe_enable_chip_intrs(bfe_t *bfe) 10659865SSaurabh.Mishra@Sun.COM { 10669865SSaurabh.Mishra@Sun.COM /* Enable the chip and core */ 10679865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_ENABLE); 10689865SSaurabh.Mishra@Sun.COM 10699865SSaurabh.Mishra@Sun.COM /* Enable interrupts */ 10709865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_INTR_MASK, BFE_IMASK_DEF); 10719865SSaurabh.Mishra@Sun.COM } 10729865SSaurabh.Mishra@Sun.COM 10739865SSaurabh.Mishra@Sun.COM /* 10749865SSaurabh.Mishra@Sun.COM * Common code to take care of setting RX side mode (filter). 10759865SSaurabh.Mishra@Sun.COM */ 10769865SSaurabh.Mishra@Sun.COM static void 10779865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe_t *bfe) 10789865SSaurabh.Mishra@Sun.COM { 10799865SSaurabh.Mishra@Sun.COM uint32_t val; 10809865SSaurabh.Mishra@Sun.COM int i; 10819865SSaurabh.Mishra@Sun.COM ether_addr_t mac[ETHERADDRL] = {0, 0, 0, 0, 0, 0}; 10829865SSaurabh.Mishra@Sun.COM 10839865SSaurabh.Mishra@Sun.COM /* 10849865SSaurabh.Mishra@Sun.COM * We don't touch RX filter if we were asked to suspend. It's fine 10859865SSaurabh.Mishra@Sun.COM * if chip is not active (no interface is plumbed on us). 10869865SSaurabh.Mishra@Sun.COM */ 10879865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED) 10889865SSaurabh.Mishra@Sun.COM return; 10899865SSaurabh.Mishra@Sun.COM 10909865SSaurabh.Mishra@Sun.COM val = INL(bfe, BFE_RXCONF); 10919865SSaurabh.Mishra@Sun.COM 10929865SSaurabh.Mishra@Sun.COM val &= ~BFE_RXCONF_PROMISC; 10939865SSaurabh.Mishra@Sun.COM val &= ~BFE_RXCONF_DBCAST; 10949865SSaurabh.Mishra@Sun.COM 10959865SSaurabh.Mishra@Sun.COM if ((bfe->bfe_chip_mode & BFE_RX_MODE_ENABLE) == 0) { 10969865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_CAM_CTRL, 0); 10979865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_CAM_CTRL); 10989865SSaurabh.Mishra@Sun.COM } else if (bfe->bfe_chip_mode & BFE_RX_MODE_PROMISC) { 10999865SSaurabh.Mishra@Sun.COM val |= BFE_RXCONF_PROMISC; 11009865SSaurabh.Mishra@Sun.COM val &= ~BFE_RXCONF_DBCAST; 11019865SSaurabh.Mishra@Sun.COM } else { 11029865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) { 11039865SSaurabh.Mishra@Sun.COM /* Flush everything */ 11049865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RXCONF, val | 11059865SSaurabh.Mishra@Sun.COM BFE_RXCONF_PROMISC | BFE_RXCONF_ALLMULTI); 11069865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_RXCONF); 11079865SSaurabh.Mishra@Sun.COM } 11089865SSaurabh.Mishra@Sun.COM 11099865SSaurabh.Mishra@Sun.COM /* Disable CAM */ 11109865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_CAM_CTRL, 0); 11119865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_CAM_CTRL); 11129865SSaurabh.Mishra@Sun.COM 11139865SSaurabh.Mishra@Sun.COM /* 11149865SSaurabh.Mishra@Sun.COM * We receive all multicast packets. 11159865SSaurabh.Mishra@Sun.COM */ 11169865SSaurabh.Mishra@Sun.COM val |= BFE_RXCONF_ALLMULTI; 11179865SSaurabh.Mishra@Sun.COM 11189865SSaurabh.Mishra@Sun.COM for (i = 0; i < BFE_MAX_MULTICAST_TABLE - 1; i++) { 11199865SSaurabh.Mishra@Sun.COM bfe_cam_write(bfe, (uchar_t *)mac, i); 11209865SSaurabh.Mishra@Sun.COM } 11219865SSaurabh.Mishra@Sun.COM 11229865SSaurabh.Mishra@Sun.COM bfe_cam_write(bfe, bfe->bfe_ether_addr, i); 11239865SSaurabh.Mishra@Sun.COM 11249865SSaurabh.Mishra@Sun.COM /* Enable CAM */ 11259865SSaurabh.Mishra@Sun.COM OUTL_OR(bfe, BFE_CAM_CTRL, BFE_CAM_ENABLE); 11269865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_CAM_CTRL); 11279865SSaurabh.Mishra@Sun.COM } 11289865SSaurabh.Mishra@Sun.COM 11299865SSaurabh.Mishra@Sun.COM DTRACE_PROBE2(rx__mode__filter, int, bfe->bfe_unit, 11309865SSaurabh.Mishra@Sun.COM int, val); 11319865SSaurabh.Mishra@Sun.COM 11329865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_RXCONF, val); 11339865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_RXCONF); 11349865SSaurabh.Mishra@Sun.COM } 11359865SSaurabh.Mishra@Sun.COM 11369865SSaurabh.Mishra@Sun.COM /* 11379865SSaurabh.Mishra@Sun.COM * Reset various variable values to initial state. 11389865SSaurabh.Mishra@Sun.COM */ 11399865SSaurabh.Mishra@Sun.COM static void 11409865SSaurabh.Mishra@Sun.COM bfe_init_vars(bfe_t *bfe) 11419865SSaurabh.Mishra@Sun.COM { 11429865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_mode = BFE_RX_MODE_ENABLE; 11439865SSaurabh.Mishra@Sun.COM 11449865SSaurabh.Mishra@Sun.COM /* Initial assumption */ 11459865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.link = LINK_STATE_UNKNOWN; 11469865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.speed = 0; 11479865SSaurabh.Mishra@Sun.COM bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN; 11489865SSaurabh.Mishra@Sun.COM 11499865SSaurabh.Mishra@Sun.COM bfe->bfe_periodic_id = NULL; 11509865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_UNINITIALIZED; 11519865SSaurabh.Mishra@Sun.COM 11529865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_stall_time = 0; 11539865SSaurabh.Mishra@Sun.COM } 11549865SSaurabh.Mishra@Sun.COM 11559865SSaurabh.Mishra@Sun.COM /* 11569865SSaurabh.Mishra@Sun.COM * Initializes TX side descriptor entries (bfe_desc_t). Each descriptor entry 11579865SSaurabh.Mishra@Sun.COM * has control (desc_ctl) and address (desc_addr) member. 11589865SSaurabh.Mishra@Sun.COM */ 11599865SSaurabh.Mishra@Sun.COM static void 11609865SSaurabh.Mishra@Sun.COM bfe_tx_desc_init(bfe_ring_t *r) 11619865SSaurabh.Mishra@Sun.COM { 11629865SSaurabh.Mishra@Sun.COM int i; 11639865SSaurabh.Mishra@Sun.COM uint32_t v; 11649865SSaurabh.Mishra@Sun.COM 11659865SSaurabh.Mishra@Sun.COM for (i = 0; i < r->r_ndesc; i++) { 11669865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl), 11679865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[i].len & BFE_DESC_LEN)); 11689865SSaurabh.Mishra@Sun.COM 11699865SSaurabh.Mishra@Sun.COM /* 11709865SSaurabh.Mishra@Sun.COM * DMA addresses need to be added to BFE_PCI_DMA 11719865SSaurabh.Mishra@Sun.COM */ 11729865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr), 11739865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA)); 11749865SSaurabh.Mishra@Sun.COM } 11759865SSaurabh.Mishra@Sun.COM 11769865SSaurabh.Mishra@Sun.COM v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl)); 11779865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl), 11789865SSaurabh.Mishra@Sun.COM v | BFE_DESC_EOT); 11799865SSaurabh.Mishra@Sun.COM 11809865SSaurabh.Mishra@Sun.COM (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV); 11819865SSaurabh.Mishra@Sun.COM 11829865SSaurabh.Mishra@Sun.COM r->r_curr_desc = 0; 11839865SSaurabh.Mishra@Sun.COM r->r_avail_desc = TX_NUM_DESC; 11849865SSaurabh.Mishra@Sun.COM r->r_cons_desc = 0; 11859865SSaurabh.Mishra@Sun.COM } 11869865SSaurabh.Mishra@Sun.COM 11879865SSaurabh.Mishra@Sun.COM /* 11889865SSaurabh.Mishra@Sun.COM * Initializes RX side descriptor entries (bfe_desc_t). Each descriptor entry 11899865SSaurabh.Mishra@Sun.COM * has control (desc_ctl) and address (desc_addr) member. 11909865SSaurabh.Mishra@Sun.COM */ 11919865SSaurabh.Mishra@Sun.COM static void 11929865SSaurabh.Mishra@Sun.COM bfe_rx_desc_init(bfe_ring_t *r) 11939865SSaurabh.Mishra@Sun.COM { 11949865SSaurabh.Mishra@Sun.COM int i; 11959865SSaurabh.Mishra@Sun.COM uint32_t v; 11969865SSaurabh.Mishra@Sun.COM 11979865SSaurabh.Mishra@Sun.COM for (i = 0; i < r->r_ndesc; i++) { 11989865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl), 11999865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[i].len& BFE_DESC_LEN)); 12009865SSaurabh.Mishra@Sun.COM 12019865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr), 12029865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA)); 12039865SSaurabh.Mishra@Sun.COM 12049865SSaurabh.Mishra@Sun.COM /* Initialize rx header (len, flags) */ 12059865SSaurabh.Mishra@Sun.COM bzero(r->r_buf_dma[i].addr, sizeof (bfe_rx_header_t)); 12069865SSaurabh.Mishra@Sun.COM 12079865SSaurabh.Mishra@Sun.COM (void) SYNC_BUF(r, i, 0, sizeof (bfe_rx_header_t), 12089865SSaurabh.Mishra@Sun.COM DDI_DMA_SYNC_FORDEV); 12099865SSaurabh.Mishra@Sun.COM } 12109865SSaurabh.Mishra@Sun.COM 12119865SSaurabh.Mishra@Sun.COM v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl)); 12129865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl), 12139865SSaurabh.Mishra@Sun.COM v | BFE_DESC_EOT); 12149865SSaurabh.Mishra@Sun.COM 12159865SSaurabh.Mishra@Sun.COM (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV); 12169865SSaurabh.Mishra@Sun.COM 12179865SSaurabh.Mishra@Sun.COM /* TAIL of RX Descriptor */ 12189865SSaurabh.Mishra@Sun.COM OUTL(r->r_bfe, BFE_DMARX_PTR, ((i) * sizeof (bfe_desc_t))); 12199865SSaurabh.Mishra@Sun.COM 12209865SSaurabh.Mishra@Sun.COM r->r_curr_desc = 0; 12219865SSaurabh.Mishra@Sun.COM r->r_avail_desc = RX_NUM_DESC; 12229865SSaurabh.Mishra@Sun.COM } 12239865SSaurabh.Mishra@Sun.COM 12249865SSaurabh.Mishra@Sun.COM static int 12259865SSaurabh.Mishra@Sun.COM bfe_chip_start(bfe_t *bfe) 12269865SSaurabh.Mishra@Sun.COM { 122710591SSaurabh.Mishra@Sun.COM ASSERT_ALL_LOCKS(bfe); 12289865SSaurabh.Mishra@Sun.COM 12299865SSaurabh.Mishra@Sun.COM /* 12309865SSaurabh.Mishra@Sun.COM * Stop the chip first & then Reset the chip. At last enable interrupts. 12319865SSaurabh.Mishra@Sun.COM */ 12329865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 12339865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 12349865SSaurabh.Mishra@Sun.COM 12359865SSaurabh.Mishra@Sun.COM /* 12369865SSaurabh.Mishra@Sun.COM * Reset chip and start PHY. 12379865SSaurabh.Mishra@Sun.COM */ 12389865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe); 12399865SSaurabh.Mishra@Sun.COM 12409865SSaurabh.Mishra@Sun.COM /* 12419865SSaurabh.Mishra@Sun.COM * Initailize Descriptor Rings. 12429865SSaurabh.Mishra@Sun.COM */ 12439865SSaurabh.Mishra@Sun.COM bfe_tx_desc_init(&bfe->bfe_tx_ring); 12449865SSaurabh.Mishra@Sun.COM bfe_rx_desc_init(&bfe->bfe_rx_ring); 12459865SSaurabh.Mishra@Sun.COM 12469865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_ACTIVE; 12479865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_mode |= BFE_RX_MODE_ENABLE; 12489865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe); 12499865SSaurabh.Mishra@Sun.COM bfe_enable_chip_intrs(bfe); 12509865SSaurabh.Mishra@Sun.COM 12519865SSaurabh.Mishra@Sun.COM /* Check link, speed and duplex mode */ 12529865SSaurabh.Mishra@Sun.COM (void) bfe_check_link(bfe); 12539865SSaurabh.Mishra@Sun.COM 12549865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 12559865SSaurabh.Mishra@Sun.COM } 12569865SSaurabh.Mishra@Sun.COM 12579865SSaurabh.Mishra@Sun.COM 12589865SSaurabh.Mishra@Sun.COM /* 12599865SSaurabh.Mishra@Sun.COM * Clear chip statistics. 12609865SSaurabh.Mishra@Sun.COM */ 12619865SSaurabh.Mishra@Sun.COM static void 12629865SSaurabh.Mishra@Sun.COM bfe_clear_stats(bfe_t *bfe) 12639865SSaurabh.Mishra@Sun.COM { 12649865SSaurabh.Mishra@Sun.COM ulong_t r; 12659865SSaurabh.Mishra@Sun.COM 12669865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 12679865SSaurabh.Mishra@Sun.COM 12689865SSaurabh.Mishra@Sun.COM /* 12699865SSaurabh.Mishra@Sun.COM * Stat registers are cleared by reading. 12709865SSaurabh.Mishra@Sun.COM */ 12719865SSaurabh.Mishra@Sun.COM for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4) 12729865SSaurabh.Mishra@Sun.COM (void) INL(bfe, r); 12739865SSaurabh.Mishra@Sun.COM 12749865SSaurabh.Mishra@Sun.COM for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4) 12759865SSaurabh.Mishra@Sun.COM (void) INL(bfe, r); 12769865SSaurabh.Mishra@Sun.COM } 12779865SSaurabh.Mishra@Sun.COM 12789865SSaurabh.Mishra@Sun.COM /* 12799865SSaurabh.Mishra@Sun.COM * Collect chip statistics. 12809865SSaurabh.Mishra@Sun.COM */ 12819865SSaurabh.Mishra@Sun.COM static void 12829865SSaurabh.Mishra@Sun.COM bfe_gather_stats(bfe_t *bfe) 12839865SSaurabh.Mishra@Sun.COM { 12849865SSaurabh.Mishra@Sun.COM ulong_t r; 12859865SSaurabh.Mishra@Sun.COM uint32_t *v; 12869865SSaurabh.Mishra@Sun.COM uint32_t txerr = 0, rxerr = 0, coll = 0; 12879865SSaurabh.Mishra@Sun.COM 12889865SSaurabh.Mishra@Sun.COM v = &bfe->bfe_hw_stats.tx_good_octets; 12899865SSaurabh.Mishra@Sun.COM for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4) { 12909865SSaurabh.Mishra@Sun.COM *v += INL(bfe, r); 12919865SSaurabh.Mishra@Sun.COM v++; 12929865SSaurabh.Mishra@Sun.COM } 12939865SSaurabh.Mishra@Sun.COM 12949865SSaurabh.Mishra@Sun.COM v = &bfe->bfe_hw_stats.rx_good_octets; 12959865SSaurabh.Mishra@Sun.COM for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4) { 12969865SSaurabh.Mishra@Sun.COM *v += INL(bfe, r); 12979865SSaurabh.Mishra@Sun.COM v++; 12989865SSaurabh.Mishra@Sun.COM } 12999865SSaurabh.Mishra@Sun.COM 13009865SSaurabh.Mishra@Sun.COM /* 13019865SSaurabh.Mishra@Sun.COM * TX : 13029865SSaurabh.Mishra@Sun.COM * ------- 13039865SSaurabh.Mishra@Sun.COM * tx_good_octets, tx_good_pkts, tx_octets 13049865SSaurabh.Mishra@Sun.COM * tx_pkts, tx_broadcast_pkts, tx_multicast_pkts 13059865SSaurabh.Mishra@Sun.COM * tx_len_64, tx_len_65_to_127, tx_len_128_to_255 13069865SSaurabh.Mishra@Sun.COM * tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max 13079865SSaurabh.Mishra@Sun.COM * tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts 13089865SSaurabh.Mishra@Sun.COM * tx_underruns, tx_total_cols, tx_single_cols 13099865SSaurabh.Mishra@Sun.COM * tx_multiple_cols, tx_excessive_cols, tx_late_cols 13109865SSaurabh.Mishra@Sun.COM * tx_defered, tx_carrier_lost, tx_pause_pkts 13119865SSaurabh.Mishra@Sun.COM * 13129865SSaurabh.Mishra@Sun.COM * RX : 13139865SSaurabh.Mishra@Sun.COM * ------- 13149865SSaurabh.Mishra@Sun.COM * rx_good_octets, rx_good_pkts, rx_octets 13159865SSaurabh.Mishra@Sun.COM * rx_pkts, rx_broadcast_pkts, rx_multicast_pkts 13169865SSaurabh.Mishra@Sun.COM * rx_len_64, rx_len_65_to_127, rx_len_128_to_255 13179865SSaurabh.Mishra@Sun.COM * rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max 13189865SSaurabh.Mishra@Sun.COM * rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts 13199865SSaurabh.Mishra@Sun.COM * rx_missed_pkts, rx_crc_align_errs, rx_undersize 13209865SSaurabh.Mishra@Sun.COM * rx_crc_errs, rx_align_errs, rx_symbol_errs 13219865SSaurabh.Mishra@Sun.COM * rx_pause_pkts, rx_nonpause_pkts 13229865SSaurabh.Mishra@Sun.COM */ 13239865SSaurabh.Mishra@Sun.COM 13249865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_carrier_errors = 13259865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_carrier_lost; 13269865SSaurabh.Mishra@Sun.COM 13279865SSaurabh.Mishra@Sun.COM /* txerr += bfe->bfe_hw_stats.tx_carrier_lost; */ 13289865SSaurabh.Mishra@Sun.COM 13299865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_ex_collisions = 13309865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_excessive_cols; 13319865SSaurabh.Mishra@Sun.COM txerr += bfe->bfe_hw_stats.tx_excessive_cols; 13329865SSaurabh.Mishra@Sun.COM coll += bfe->bfe_hw_stats.tx_excessive_cols; 13339865SSaurabh.Mishra@Sun.COM 13349865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_fcs_errors = 13359865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.rx_crc_errs; 13369865SSaurabh.Mishra@Sun.COM rxerr += bfe->bfe_hw_stats.rx_crc_errs; 13379865SSaurabh.Mishra@Sun.COM 13389865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_first_collisions = 13399865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_single_cols; 13409865SSaurabh.Mishra@Sun.COM coll += bfe->bfe_hw_stats.tx_single_cols; 13419865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_multi_collisions = 13429865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_multiple_cols; 13439865SSaurabh.Mishra@Sun.COM coll += bfe->bfe_hw_stats.tx_multiple_cols; 13449865SSaurabh.Mishra@Sun.COM 13459865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_toolong_errors = 13469865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.rx_oversize_pkts; 13479865SSaurabh.Mishra@Sun.COM rxerr += bfe->bfe_hw_stats.rx_oversize_pkts; 13489865SSaurabh.Mishra@Sun.COM 13499865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_tooshort_errors = 13509865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.rx_undersize; 13519865SSaurabh.Mishra@Sun.COM rxerr += bfe->bfe_hw_stats.rx_undersize; 13529865SSaurabh.Mishra@Sun.COM 13539865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_tx_late_collisions += 13549865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_late_cols; 13559865SSaurabh.Mishra@Sun.COM 13569865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_defer_xmts += 13579865SSaurabh.Mishra@Sun.COM bfe->bfe_hw_stats.tx_defered; 13589865SSaurabh.Mishra@Sun.COM 13599865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_macrcv_errors += rxerr; 13609865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_macxmt_errors += txerr; 13619865SSaurabh.Mishra@Sun.COM 13629865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.collisions += coll; 13639865SSaurabh.Mishra@Sun.COM } 13649865SSaurabh.Mishra@Sun.COM 13659865SSaurabh.Mishra@Sun.COM /* 13669865SSaurabh.Mishra@Sun.COM * Gets the state for dladm command and all. 13679865SSaurabh.Mishra@Sun.COM */ 13689865SSaurabh.Mishra@Sun.COM int 13699865SSaurabh.Mishra@Sun.COM bfe_mac_getstat(void *arg, uint_t stat, uint64_t *val) 13709865SSaurabh.Mishra@Sun.COM { 13719865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 13729865SSaurabh.Mishra@Sun.COM uint64_t v; 13739865SSaurabh.Mishra@Sun.COM int err = 0; 13749865SSaurabh.Mishra@Sun.COM 13759865SSaurabh.Mishra@Sun.COM rw_enter(&bfe->bfe_rwlock, RW_READER); 13769865SSaurabh.Mishra@Sun.COM 13779865SSaurabh.Mishra@Sun.COM 13789865SSaurabh.Mishra@Sun.COM switch (stat) { 13799865SSaurabh.Mishra@Sun.COM default: 13809865SSaurabh.Mishra@Sun.COM err = ENOTSUP; 13819865SSaurabh.Mishra@Sun.COM break; 13829865SSaurabh.Mishra@Sun.COM 13839865SSaurabh.Mishra@Sun.COM case MAC_STAT_IFSPEED: 13849865SSaurabh.Mishra@Sun.COM /* 13859865SSaurabh.Mishra@Sun.COM * MAC layer will ask for IFSPEED first and hence we 13869865SSaurabh.Mishra@Sun.COM * collect it only once. 13879865SSaurabh.Mishra@Sun.COM */ 13889865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) { 13899865SSaurabh.Mishra@Sun.COM /* 13909865SSaurabh.Mishra@Sun.COM * Update stats from the hardware. 13919865SSaurabh.Mishra@Sun.COM */ 13929865SSaurabh.Mishra@Sun.COM bfe_gather_stats(bfe); 13939865SSaurabh.Mishra@Sun.COM } 13949865SSaurabh.Mishra@Sun.COM v = bfe->bfe_chip.speed; 13959865SSaurabh.Mishra@Sun.COM break; 13969865SSaurabh.Mishra@Sun.COM 13979865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_100T4: 13989865SSaurabh.Mishra@Sun.COM v = bfe->bfe_adv_100T4; 13999865SSaurabh.Mishra@Sun.COM break; 14009865SSaurabh.Mishra@Sun.COM 14019865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_100FDX: 14029865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX_FD) != 0; 14039865SSaurabh.Mishra@Sun.COM break; 14049865SSaurabh.Mishra@Sun.COM 14059865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_100HDX: 14069865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX) != 0; 14079865SSaurabh.Mishra@Sun.COM break; 14089865SSaurabh.Mishra@Sun.COM 14099865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_10FDX: 14109865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T_FD) != 0; 14119865SSaurabh.Mishra@Sun.COM break; 14129865SSaurabh.Mishra@Sun.COM 14139865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_10HDX: 14149865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T) != 0; 14159865SSaurabh.Mishra@Sun.COM break; 14169865SSaurabh.Mishra@Sun.COM 14179865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_ASMPAUSE: 14189865SSaurabh.Mishra@Sun.COM v = 0; 14199865SSaurabh.Mishra@Sun.COM break; 14209865SSaurabh.Mishra@Sun.COM 14219865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_AUTONEG: 14229865SSaurabh.Mishra@Sun.COM v = bfe->bfe_adv_aneg; 14239865SSaurabh.Mishra@Sun.COM break; 14249865SSaurabh.Mishra@Sun.COM 14259865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_CAP_PAUSE: 14269865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_ABILITY_PAUSE) != 0; 14279865SSaurabh.Mishra@Sun.COM break; 14289865SSaurabh.Mishra@Sun.COM 14299865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ADV_REMFAULT: 14309865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anar & MII_AN_ADVERT_REMFAULT) != 0; 14319865SSaurabh.Mishra@Sun.COM break; 14329865SSaurabh.Mishra@Sun.COM 14339865SSaurabh.Mishra@Sun.COM case ETHER_STAT_ALIGN_ERRORS: 14349865SSaurabh.Mishra@Sun.COM /* MIB */ 14359865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_align_errors; 14369865SSaurabh.Mishra@Sun.COM break; 14379865SSaurabh.Mishra@Sun.COM 14389865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_100T4: 14399865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASE_T4) != 0; 14409865SSaurabh.Mishra@Sun.COM break; 14419865SSaurabh.Mishra@Sun.COM 14429865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_100FDX: 14439865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX_FD) != 0; 14449865SSaurabh.Mishra@Sun.COM break; 14459865SSaurabh.Mishra@Sun.COM 14469865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_100HDX: 14479865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX) != 0; 14489865SSaurabh.Mishra@Sun.COM break; 14499865SSaurabh.Mishra@Sun.COM 14509865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_10FDX: 14519865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_10_FD) != 0; 14529865SSaurabh.Mishra@Sun.COM break; 14539865SSaurabh.Mishra@Sun.COM 14549865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_10HDX: 14559865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_10) != 0; 14569865SSaurabh.Mishra@Sun.COM break; 14579865SSaurabh.Mishra@Sun.COM 14589865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_ASMPAUSE: 14599865SSaurabh.Mishra@Sun.COM v = 0; 14609865SSaurabh.Mishra@Sun.COM break; 14619865SSaurabh.Mishra@Sun.COM 14629865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_AUTONEG: 14639865SSaurabh.Mishra@Sun.COM v = ((bfe->bfe_mii_bmsr & MII_STATUS_CANAUTONEG) != 0); 14649865SSaurabh.Mishra@Sun.COM break; 14659865SSaurabh.Mishra@Sun.COM 14669865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_PAUSE: 14679865SSaurabh.Mishra@Sun.COM v = 1; 14689865SSaurabh.Mishra@Sun.COM break; 14699865SSaurabh.Mishra@Sun.COM 14709865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CAP_REMFAULT: 14719865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmsr & MII_STATUS_REMFAULT) != 0; 14729865SSaurabh.Mishra@Sun.COM break; 14739865SSaurabh.Mishra@Sun.COM 14749865SSaurabh.Mishra@Sun.COM case ETHER_STAT_CARRIER_ERRORS: 14759865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_carrier_errors; 14769865SSaurabh.Mishra@Sun.COM break; 14779865SSaurabh.Mishra@Sun.COM 14789865SSaurabh.Mishra@Sun.COM case ETHER_STAT_JABBER_ERRORS: 14799865SSaurabh.Mishra@Sun.COM err = ENOTSUP; 14809865SSaurabh.Mishra@Sun.COM break; 14819865SSaurabh.Mishra@Sun.COM 14829865SSaurabh.Mishra@Sun.COM case ETHER_STAT_DEFER_XMTS: 14839865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_defer_xmts; 14849865SSaurabh.Mishra@Sun.COM break; 14859865SSaurabh.Mishra@Sun.COM 14869865SSaurabh.Mishra@Sun.COM case ETHER_STAT_EX_COLLISIONS: 14879865SSaurabh.Mishra@Sun.COM /* MIB */ 14889865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_ex_collisions; 14899865SSaurabh.Mishra@Sun.COM break; 14909865SSaurabh.Mishra@Sun.COM 14919865SSaurabh.Mishra@Sun.COM case ETHER_STAT_FCS_ERRORS: 14929865SSaurabh.Mishra@Sun.COM /* MIB */ 14939865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_fcs_errors; 14949865SSaurabh.Mishra@Sun.COM break; 14959865SSaurabh.Mishra@Sun.COM 14969865SSaurabh.Mishra@Sun.COM case ETHER_STAT_FIRST_COLLISIONS: 14979865SSaurabh.Mishra@Sun.COM /* MIB */ 14989865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_first_collisions; 14999865SSaurabh.Mishra@Sun.COM break; 15009865SSaurabh.Mishra@Sun.COM 15019865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LINK_ASMPAUSE: 15029865SSaurabh.Mishra@Sun.COM v = 0; 15039865SSaurabh.Mishra@Sun.COM break; 15049865SSaurabh.Mishra@Sun.COM 15059865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LINK_AUTONEG: 15069865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_bmcr & MII_CONTROL_ANE) != 0 && 15079865SSaurabh.Mishra@Sun.COM (bfe->bfe_mii_bmsr & MII_STATUS_ANDONE) != 0; 15089865SSaurabh.Mishra@Sun.COM break; 15099865SSaurabh.Mishra@Sun.COM 15109865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LINK_DUPLEX: 15119865SSaurabh.Mishra@Sun.COM v = bfe->bfe_chip.duplex; 15129865SSaurabh.Mishra@Sun.COM break; 15139865SSaurabh.Mishra@Sun.COM 15149865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_100T4: 15159865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_T4) != 0; 15169865SSaurabh.Mishra@Sun.COM break; 15179865SSaurabh.Mishra@Sun.COM 15189865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_100FDX: 15199865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX_FD) != 0; 15209865SSaurabh.Mishra@Sun.COM break; 15219865SSaurabh.Mishra@Sun.COM 15229865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_100HDX: 15239865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX) != 0; 15249865SSaurabh.Mishra@Sun.COM break; 15259865SSaurabh.Mishra@Sun.COM 15269865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_10FDX: 15279865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T_FD) != 0; 15289865SSaurabh.Mishra@Sun.COM break; 15299865SSaurabh.Mishra@Sun.COM 15309865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_10HDX: 15319865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T) != 0; 15329865SSaurabh.Mishra@Sun.COM break; 15339865SSaurabh.Mishra@Sun.COM 15349865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_ASMPAUSE: 15359865SSaurabh.Mishra@Sun.COM v = 0; 15369865SSaurabh.Mishra@Sun.COM break; 15379865SSaurabh.Mishra@Sun.COM 15389865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_AUTONEG: 15399865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_exp & MII_AN_EXP_LPCANAN) != 0; 15409865SSaurabh.Mishra@Sun.COM break; 15419865SSaurabh.Mishra@Sun.COM 15429865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_CAP_PAUSE: 15439865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_ABILITY_PAUSE) != 0; 15449865SSaurabh.Mishra@Sun.COM break; 15459865SSaurabh.Mishra@Sun.COM 15469865SSaurabh.Mishra@Sun.COM case ETHER_STAT_LP_REMFAULT: 15479865SSaurabh.Mishra@Sun.COM v = (bfe->bfe_mii_anlpar & MII_STATUS_REMFAULT) != 0; 15489865SSaurabh.Mishra@Sun.COM break; 15499865SSaurabh.Mishra@Sun.COM 15509865SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACRCV_ERRORS: 15519865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_macrcv_errors; 15529865SSaurabh.Mishra@Sun.COM break; 15539865SSaurabh.Mishra@Sun.COM 15549865SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACXMT_ERRORS: 15559865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_macxmt_errors; 15569865SSaurabh.Mishra@Sun.COM break; 15579865SSaurabh.Mishra@Sun.COM 15589865SSaurabh.Mishra@Sun.COM case ETHER_STAT_MULTI_COLLISIONS: 15599865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_multi_collisions; 15609865SSaurabh.Mishra@Sun.COM break; 15619865SSaurabh.Mishra@Sun.COM 15629865SSaurabh.Mishra@Sun.COM case ETHER_STAT_SQE_ERRORS: 15639865SSaurabh.Mishra@Sun.COM err = ENOTSUP; 15649865SSaurabh.Mishra@Sun.COM break; 15659865SSaurabh.Mishra@Sun.COM 15669865SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOLONG_ERRORS: 15679865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_toolong_errors; 15689865SSaurabh.Mishra@Sun.COM break; 15699865SSaurabh.Mishra@Sun.COM 15709865SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS: 15719865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_tooshort_errors; 15729865SSaurabh.Mishra@Sun.COM break; 15739865SSaurabh.Mishra@Sun.COM 15749865SSaurabh.Mishra@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS: 15759865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_tx_late_collisions; 15769865SSaurabh.Mishra@Sun.COM break; 15779865SSaurabh.Mishra@Sun.COM 15789865SSaurabh.Mishra@Sun.COM case ETHER_STAT_XCVR_ADDR: 15799865SSaurabh.Mishra@Sun.COM v = bfe->bfe_phy_addr; 15809865SSaurabh.Mishra@Sun.COM break; 15819865SSaurabh.Mishra@Sun.COM 15829865SSaurabh.Mishra@Sun.COM case ETHER_STAT_XCVR_ID: 15839865SSaurabh.Mishra@Sun.COM v = bfe->bfe_phy_id; 15849865SSaurabh.Mishra@Sun.COM break; 15859865SSaurabh.Mishra@Sun.COM 15869865SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTRCV: 15879865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.brdcstrcv; 15889865SSaurabh.Mishra@Sun.COM break; 15899865SSaurabh.Mishra@Sun.COM 15909865SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTXMT: 15919865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.brdcstxmt; 15929865SSaurabh.Mishra@Sun.COM break; 15939865SSaurabh.Mishra@Sun.COM 15949865SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIXMT: 15959865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.multixmt; 15969865SSaurabh.Mishra@Sun.COM break; 15979865SSaurabh.Mishra@Sun.COM 15989865SSaurabh.Mishra@Sun.COM case MAC_STAT_COLLISIONS: 15999865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.collisions; 16009865SSaurabh.Mishra@Sun.COM break; 16019865SSaurabh.Mishra@Sun.COM 16029865SSaurabh.Mishra@Sun.COM case MAC_STAT_IERRORS: 16039865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ierrors; 16049865SSaurabh.Mishra@Sun.COM break; 16059865SSaurabh.Mishra@Sun.COM 16069865SSaurabh.Mishra@Sun.COM case MAC_STAT_IPACKETS: 16079865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ipackets; 16089865SSaurabh.Mishra@Sun.COM break; 16099865SSaurabh.Mishra@Sun.COM 16109865SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIRCV: 16119865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.multircv; 16129865SSaurabh.Mishra@Sun.COM break; 16139865SSaurabh.Mishra@Sun.COM 16149865SSaurabh.Mishra@Sun.COM case MAC_STAT_NORCVBUF: 16159865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.norcvbuf; 16169865SSaurabh.Mishra@Sun.COM break; 16179865SSaurabh.Mishra@Sun.COM 16189865SSaurabh.Mishra@Sun.COM case MAC_STAT_NOXMTBUF: 16199865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.noxmtbuf; 16209865SSaurabh.Mishra@Sun.COM break; 16219865SSaurabh.Mishra@Sun.COM 16229865SSaurabh.Mishra@Sun.COM case MAC_STAT_OBYTES: 16239865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.obytes; 16249865SSaurabh.Mishra@Sun.COM break; 16259865SSaurabh.Mishra@Sun.COM 16269865SSaurabh.Mishra@Sun.COM case MAC_STAT_OERRORS: 16279865SSaurabh.Mishra@Sun.COM /* MIB */ 16289865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.ether_stat_macxmt_errors; 16299865SSaurabh.Mishra@Sun.COM break; 16309865SSaurabh.Mishra@Sun.COM 16319865SSaurabh.Mishra@Sun.COM case MAC_STAT_OPACKETS: 16329865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.opackets; 16339865SSaurabh.Mishra@Sun.COM break; 16349865SSaurabh.Mishra@Sun.COM 16359865SSaurabh.Mishra@Sun.COM case MAC_STAT_RBYTES: 16369865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.rbytes; 16379865SSaurabh.Mishra@Sun.COM break; 16389865SSaurabh.Mishra@Sun.COM 16399865SSaurabh.Mishra@Sun.COM case MAC_STAT_UNDERFLOWS: 16409865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.underflows; 16419865SSaurabh.Mishra@Sun.COM break; 16429865SSaurabh.Mishra@Sun.COM 16439865SSaurabh.Mishra@Sun.COM case MAC_STAT_OVERFLOWS: 16449865SSaurabh.Mishra@Sun.COM v = bfe->bfe_stats.overflows; 16459865SSaurabh.Mishra@Sun.COM break; 16469865SSaurabh.Mishra@Sun.COM } 16479865SSaurabh.Mishra@Sun.COM 16489865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 16499865SSaurabh.Mishra@Sun.COM 16509865SSaurabh.Mishra@Sun.COM *val = v; 16519865SSaurabh.Mishra@Sun.COM return (err); 16529865SSaurabh.Mishra@Sun.COM } 16539865SSaurabh.Mishra@Sun.COM 16549865SSaurabh.Mishra@Sun.COM int 1655*11878SVenu.Iyer@Sun.COM bfe_mac_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 1656*11878SVenu.Iyer@Sun.COM void *val) 16579865SSaurabh.Mishra@Sun.COM { 16589865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 16599865SSaurabh.Mishra@Sun.COM int err = 0; 1660*11878SVenu.Iyer@Sun.COM 16619865SSaurabh.Mishra@Sun.COM switch (num) { 16629865SSaurabh.Mishra@Sun.COM case MAC_PROP_DUPLEX: 1663*11878SVenu.Iyer@Sun.COM ASSERT(sz >= sizeof (link_duplex_t)); 1664*11878SVenu.Iyer@Sun.COM bcopy(&bfe->bfe_chip.duplex, val, sizeof (link_duplex_t)); 16659865SSaurabh.Mishra@Sun.COM break; 16669865SSaurabh.Mishra@Sun.COM 16679865SSaurabh.Mishra@Sun.COM case MAC_PROP_SPEED: 1668*11878SVenu.Iyer@Sun.COM ASSERT(sz >= sizeof (uint64_t)); 1669*11878SVenu.Iyer@Sun.COM bcopy(&bfe->bfe_chip.speed, val, sizeof (uint64_t)); 16709865SSaurabh.Mishra@Sun.COM break; 16719865SSaurabh.Mishra@Sun.COM 16729865SSaurabh.Mishra@Sun.COM case MAC_PROP_AUTONEG: 1673*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_aneg; 16749865SSaurabh.Mishra@Sun.COM break; 16759865SSaurabh.Mishra@Sun.COM 16769865SSaurabh.Mishra@Sun.COM case MAC_PROP_ADV_100FDX_CAP: 1677*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100fdx; 16789865SSaurabh.Mishra@Sun.COM break; 1679*11878SVenu.Iyer@Sun.COM 16809865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100FDX_CAP: 1681*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100fdx; 16829865SSaurabh.Mishra@Sun.COM break; 16839865SSaurabh.Mishra@Sun.COM 16849865SSaurabh.Mishra@Sun.COM case MAC_PROP_ADV_100HDX_CAP: 1685*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100hdx; 16869865SSaurabh.Mishra@Sun.COM break; 1687*11878SVenu.Iyer@Sun.COM 16889865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100HDX_CAP: 1689*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100hdx; 16909865SSaurabh.Mishra@Sun.COM break; 16919865SSaurabh.Mishra@Sun.COM 16929865SSaurabh.Mishra@Sun.COM case MAC_PROP_ADV_10FDX_CAP: 1693*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_10fdx; 16949865SSaurabh.Mishra@Sun.COM break; 1695*11878SVenu.Iyer@Sun.COM 16969865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_10FDX_CAP: 1697*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_10fdx; 16989865SSaurabh.Mishra@Sun.COM break; 16999865SSaurabh.Mishra@Sun.COM 17009865SSaurabh.Mishra@Sun.COM case MAC_PROP_ADV_10HDX_CAP: 1701*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_10hdx; 17029865SSaurabh.Mishra@Sun.COM break; 1703*11878SVenu.Iyer@Sun.COM 17049865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_10HDX_CAP: 1705*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_10hdx; 17069865SSaurabh.Mishra@Sun.COM break; 17079865SSaurabh.Mishra@Sun.COM 17089865SSaurabh.Mishra@Sun.COM case MAC_PROP_ADV_100T4_CAP: 1709*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100T4; 17109865SSaurabh.Mishra@Sun.COM break; 1711*11878SVenu.Iyer@Sun.COM 17129865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100T4_CAP: 1713*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = bfe->bfe_adv_100T4; 17149865SSaurabh.Mishra@Sun.COM break; 17159865SSaurabh.Mishra@Sun.COM 17169865SSaurabh.Mishra@Sun.COM default: 17179865SSaurabh.Mishra@Sun.COM err = ENOTSUP; 17189865SSaurabh.Mishra@Sun.COM } 17199865SSaurabh.Mishra@Sun.COM 17209865SSaurabh.Mishra@Sun.COM return (err); 17219865SSaurabh.Mishra@Sun.COM } 17229865SSaurabh.Mishra@Sun.COM 1723*11878SVenu.Iyer@Sun.COM 1724*11878SVenu.Iyer@Sun.COM static void 1725*11878SVenu.Iyer@Sun.COM bfe_mac_propinfo(void *arg, const char *name, mac_prop_id_t num, 1726*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh) 1727*11878SVenu.Iyer@Sun.COM { 1728*11878SVenu.Iyer@Sun.COM bfe_t *bfe = (bfe_t *)arg; 1729*11878SVenu.Iyer@Sun.COM 1730*11878SVenu.Iyer@Sun.COM switch (num) { 1731*11878SVenu.Iyer@Sun.COM case MAC_PROP_DUPLEX: 1732*11878SVenu.Iyer@Sun.COM case MAC_PROP_SPEED: 1733*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100FDX_CAP: 1734*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100HDX_CAP: 1735*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10FDX_CAP: 1736*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10HDX_CAP: 1737*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100T4_CAP: 1738*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1739*11878SVenu.Iyer@Sun.COM break; 1740*11878SVenu.Iyer@Sun.COM 1741*11878SVenu.Iyer@Sun.COM case MAC_PROP_AUTONEG: 1742*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_aneg); 1743*11878SVenu.Iyer@Sun.COM break; 1744*11878SVenu.Iyer@Sun.COM 1745*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100FDX_CAP: 1746*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100fdx); 1747*11878SVenu.Iyer@Sun.COM break; 1748*11878SVenu.Iyer@Sun.COM 1749*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100HDX_CAP: 1750*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100hdx); 1751*11878SVenu.Iyer@Sun.COM break; 1752*11878SVenu.Iyer@Sun.COM 1753*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10FDX_CAP: 1754*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10fdx); 1755*11878SVenu.Iyer@Sun.COM break; 1756*11878SVenu.Iyer@Sun.COM 1757*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10HDX_CAP: 1758*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10hdx); 1759*11878SVenu.Iyer@Sun.COM break; 1760*11878SVenu.Iyer@Sun.COM 1761*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100T4_CAP: 1762*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100T4); 1763*11878SVenu.Iyer@Sun.COM break; 1764*11878SVenu.Iyer@Sun.COM } 1765*11878SVenu.Iyer@Sun.COM } 1766*11878SVenu.Iyer@Sun.COM 1767*11878SVenu.Iyer@Sun.COM 17689865SSaurabh.Mishra@Sun.COM /*ARGSUSED*/ 17699865SSaurabh.Mishra@Sun.COM int 17709865SSaurabh.Mishra@Sun.COM bfe_mac_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 17719865SSaurabh.Mishra@Sun.COM const void *val) 17729865SSaurabh.Mishra@Sun.COM { 17739865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 17749865SSaurabh.Mishra@Sun.COM uint8_t *advp; 17759865SSaurabh.Mishra@Sun.COM uint8_t *capp; 17769865SSaurabh.Mishra@Sun.COM int r = 0; 17779865SSaurabh.Mishra@Sun.COM 17789865SSaurabh.Mishra@Sun.COM switch (num) { 17799865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100FDX_CAP: 17809865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_100fdx; 17819865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_100fdx; 17829865SSaurabh.Mishra@Sun.COM break; 17839865SSaurabh.Mishra@Sun.COM 17849865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100HDX_CAP: 17859865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_100hdx; 17869865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_100hdx; 17879865SSaurabh.Mishra@Sun.COM break; 17889865SSaurabh.Mishra@Sun.COM 17899865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_10FDX_CAP: 17909865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_10fdx; 17919865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_10fdx; 17929865SSaurabh.Mishra@Sun.COM break; 17939865SSaurabh.Mishra@Sun.COM 17949865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_10HDX_CAP: 17959865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_10hdx; 17969865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_10hdx; 17979865SSaurabh.Mishra@Sun.COM break; 17989865SSaurabh.Mishra@Sun.COM 17999865SSaurabh.Mishra@Sun.COM case MAC_PROP_EN_100T4_CAP: 18009865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_100T4; 18019865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_100T4; 18029865SSaurabh.Mishra@Sun.COM break; 18039865SSaurabh.Mishra@Sun.COM 18049865SSaurabh.Mishra@Sun.COM case MAC_PROP_AUTONEG: 18059865SSaurabh.Mishra@Sun.COM advp = &bfe->bfe_adv_aneg; 18069865SSaurabh.Mishra@Sun.COM capp = &bfe->bfe_cap_aneg; 18079865SSaurabh.Mishra@Sun.COM break; 18089865SSaurabh.Mishra@Sun.COM 18099865SSaurabh.Mishra@Sun.COM default: 18109865SSaurabh.Mishra@Sun.COM return (ENOTSUP); 18119865SSaurabh.Mishra@Sun.COM } 18129865SSaurabh.Mishra@Sun.COM 18139865SSaurabh.Mishra@Sun.COM if (*capp == 0) 18149865SSaurabh.Mishra@Sun.COM return (ENOTSUP); 18159865SSaurabh.Mishra@Sun.COM 18169865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 18179865SSaurabh.Mishra@Sun.COM 18189865SSaurabh.Mishra@Sun.COM if (*advp != *(const uint8_t *)val) { 18199865SSaurabh.Mishra@Sun.COM *advp = *(const uint8_t *)val; 18209865SSaurabh.Mishra@Sun.COM 18219865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action = BFE_ACTION_RESTART_SETPROP; 18229865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) { 18239865SSaurabh.Mishra@Sun.COM /* 18249865SSaurabh.Mishra@Sun.COM * We need to stop the timer before grabbing locks 18259865SSaurabh.Mishra@Sun.COM * otherwise we can land-up in deadlock with untimeout. 18269865SSaurabh.Mishra@Sun.COM */ 18279865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe); 18289865SSaurabh.Mishra@Sun.COM 18299865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= BFE_ACTION_RESTART; 18309865SSaurabh.Mishra@Sun.COM 18319865SSaurabh.Mishra@Sun.COM bfe_chip_restart(bfe); 18329865SSaurabh.Mishra@Sun.COM 18339865SSaurabh.Mishra@Sun.COM /* 18349865SSaurabh.Mishra@Sun.COM * We leave SETPROP because properties can be 18359865SSaurabh.Mishra@Sun.COM * temporary. 18369865SSaurabh.Mishra@Sun.COM */ 18379865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action &= ~(BFE_ACTION_RESTART); 18389865SSaurabh.Mishra@Sun.COM r = 1; 18399865SSaurabh.Mishra@Sun.COM } 18409865SSaurabh.Mishra@Sun.COM } 18419865SSaurabh.Mishra@Sun.COM 18429865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 18439865SSaurabh.Mishra@Sun.COM 18449865SSaurabh.Mishra@Sun.COM /* kick-off a potential stopped downstream */ 18459865SSaurabh.Mishra@Sun.COM if (r) 18469865SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 18479865SSaurabh.Mishra@Sun.COM 18489865SSaurabh.Mishra@Sun.COM return (0); 18499865SSaurabh.Mishra@Sun.COM } 18509865SSaurabh.Mishra@Sun.COM 18519865SSaurabh.Mishra@Sun.COM 18529865SSaurabh.Mishra@Sun.COM int 18539865SSaurabh.Mishra@Sun.COM bfe_mac_set_ether_addr(void *arg, const uint8_t *ea) 18549865SSaurabh.Mishra@Sun.COM { 18559865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 18569865SSaurabh.Mishra@Sun.COM 18579865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 18589865SSaurabh.Mishra@Sun.COM bcopy(ea, bfe->bfe_ether_addr, ETHERADDRL); 18599865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe); 18609865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 18619865SSaurabh.Mishra@Sun.COM return (0); 18629865SSaurabh.Mishra@Sun.COM } 18639865SSaurabh.Mishra@Sun.COM 18649865SSaurabh.Mishra@Sun.COM int 18659865SSaurabh.Mishra@Sun.COM bfe_mac_start(void *arg) 18669865SSaurabh.Mishra@Sun.COM { 18679865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 18689865SSaurabh.Mishra@Sun.COM 186910591SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 187010591SSaurabh.Mishra@Sun.COM if (bfe_chip_start(bfe) == DDI_FAILURE) { 187110591SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 18729865SSaurabh.Mishra@Sun.COM return (EINVAL); 187310591SSaurabh.Mishra@Sun.COM } 187410591SSaurabh.Mishra@Sun.COM 187510591SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 187610591SSaurabh.Mishra@Sun.COM 187710591SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 18789865SSaurabh.Mishra@Sun.COM 18799865SSaurabh.Mishra@Sun.COM return (0); 18809865SSaurabh.Mishra@Sun.COM } 18819865SSaurabh.Mishra@Sun.COM 18829865SSaurabh.Mishra@Sun.COM void 18839865SSaurabh.Mishra@Sun.COM bfe_mac_stop(void *arg) 18849865SSaurabh.Mishra@Sun.COM { 18859865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 18869865SSaurabh.Mishra@Sun.COM 18879865SSaurabh.Mishra@Sun.COM /* 18889865SSaurabh.Mishra@Sun.COM * We need to stop the timer before grabbing locks otherwise 18899865SSaurabh.Mishra@Sun.COM * we can land-up in deadlock with untimeout. 18909865SSaurabh.Mishra@Sun.COM */ 18919865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe); 18929865SSaurabh.Mishra@Sun.COM 18939865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 18949865SSaurabh.Mishra@Sun.COM 18959865SSaurabh.Mishra@Sun.COM /* 18969865SSaurabh.Mishra@Sun.COM * First halt the chip by disabling interrupts. 18979865SSaurabh.Mishra@Sun.COM */ 18989865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 18999865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 19009865SSaurabh.Mishra@Sun.COM 19019865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_STOPPED; 19029865SSaurabh.Mishra@Sun.COM 19039865SSaurabh.Mishra@Sun.COM /* 19049865SSaurabh.Mishra@Sun.COM * This will leave the PHY running. 19059865SSaurabh.Mishra@Sun.COM */ 19069865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe); 19079865SSaurabh.Mishra@Sun.COM 19089865SSaurabh.Mishra@Sun.COM /* 19099865SSaurabh.Mishra@Sun.COM * Disable RX register. 19109865SSaurabh.Mishra@Sun.COM */ 19119865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_mode &= ~BFE_RX_MODE_ENABLE; 19129865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe); 19139865SSaurabh.Mishra@Sun.COM 19149865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 19159865SSaurabh.Mishra@Sun.COM } 19169865SSaurabh.Mishra@Sun.COM 19179865SSaurabh.Mishra@Sun.COM /* 19189865SSaurabh.Mishra@Sun.COM * Send a packet down the wire. 19199865SSaurabh.Mishra@Sun.COM */ 19209865SSaurabh.Mishra@Sun.COM static int 19219865SSaurabh.Mishra@Sun.COM bfe_send_a_packet(bfe_t *bfe, mblk_t *mp) 19229865SSaurabh.Mishra@Sun.COM { 19239865SSaurabh.Mishra@Sun.COM bfe_ring_t *r = &bfe->bfe_tx_ring; 19249865SSaurabh.Mishra@Sun.COM uint32_t cur = r->r_curr_desc; 19259865SSaurabh.Mishra@Sun.COM uint32_t next; 19269865SSaurabh.Mishra@Sun.COM size_t pktlen = msgsize(mp); 19279865SSaurabh.Mishra@Sun.COM uchar_t *buf; 19289865SSaurabh.Mishra@Sun.COM uint32_t v; 19299865SSaurabh.Mishra@Sun.COM 19309865SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&r->r_lock)); 19319865SSaurabh.Mishra@Sun.COM ASSERT(mp != NULL); 19329865SSaurabh.Mishra@Sun.COM 19339865SSaurabh.Mishra@Sun.COM if (pktlen > r->r_buf_len) { 19349865SSaurabh.Mishra@Sun.COM freemsg(mp); 19359865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 19369865SSaurabh.Mishra@Sun.COM } 19379865SSaurabh.Mishra@Sun.COM 19389865SSaurabh.Mishra@Sun.COM /* 19399865SSaurabh.Mishra@Sun.COM * There is a big reason why we don't check for '0'. It becomes easy 19409865SSaurabh.Mishra@Sun.COM * for us to not roll over the ring since we are based on producer (tx) 19419865SSaurabh.Mishra@Sun.COM * and consumer (reclaim by an interrupt) model. Especially when we 19429865SSaurabh.Mishra@Sun.COM * run out of TX descriptor, chip will send a single interrupt and 19439865SSaurabh.Mishra@Sun.COM * both producer and consumer counter will be same. So we keep a 19449865SSaurabh.Mishra@Sun.COM * difference of 1 always. 19459865SSaurabh.Mishra@Sun.COM */ 19469865SSaurabh.Mishra@Sun.COM if (r->r_avail_desc <= 1) { 19479865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.noxmtbuf++; 19489865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_resched = 1; 19499865SSaurabh.Mishra@Sun.COM return (BFE_FAILURE); 19509865SSaurabh.Mishra@Sun.COM } 19519865SSaurabh.Mishra@Sun.COM 19529865SSaurabh.Mishra@Sun.COM /* 19539865SSaurabh.Mishra@Sun.COM * Get the DMA buffer to hold packet. 19549865SSaurabh.Mishra@Sun.COM */ 19559865SSaurabh.Mishra@Sun.COM buf = (uchar_t *)r->r_buf_dma[cur].addr; 19569865SSaurabh.Mishra@Sun.COM 19579865SSaurabh.Mishra@Sun.COM mcopymsg(mp, buf); /* it also frees mp */ 19589865SSaurabh.Mishra@Sun.COM 19599865SSaurabh.Mishra@Sun.COM /* 19609865SSaurabh.Mishra@Sun.COM * Gather statistics. 19619865SSaurabh.Mishra@Sun.COM */ 19629865SSaurabh.Mishra@Sun.COM if (buf[0] & 0x1) { 19639865SSaurabh.Mishra@Sun.COM if (bcmp(buf, bfe_broadcast, ETHERADDRL) != 0) 19649865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.multixmt++; 19659865SSaurabh.Mishra@Sun.COM else 19669865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.brdcstxmt++; 19679865SSaurabh.Mishra@Sun.COM } 19689865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.opackets++; 19699865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.obytes += pktlen; 19709865SSaurabh.Mishra@Sun.COM 19719865SSaurabh.Mishra@Sun.COM 19729865SSaurabh.Mishra@Sun.COM /* 19739865SSaurabh.Mishra@Sun.COM * Program the DMA descriptor (start and end of frame are same). 19749865SSaurabh.Mishra@Sun.COM */ 19759865SSaurabh.Mishra@Sun.COM next = cur; 19769865SSaurabh.Mishra@Sun.COM v = (pktlen & BFE_DESC_LEN) | BFE_DESC_IOC | BFE_DESC_SOF | 19779865SSaurabh.Mishra@Sun.COM BFE_DESC_EOF; 19789865SSaurabh.Mishra@Sun.COM 19799865SSaurabh.Mishra@Sun.COM if (cur == (TX_NUM_DESC - 1)) 19809865SSaurabh.Mishra@Sun.COM v |= BFE_DESC_EOT; 19819865SSaurabh.Mishra@Sun.COM 19829865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_ctl), v); 19839865SSaurabh.Mishra@Sun.COM 19849865SSaurabh.Mishra@Sun.COM /* 19859865SSaurabh.Mishra@Sun.COM * DMA addresses need to be added to BFE_PCI_DMA 19869865SSaurabh.Mishra@Sun.COM */ 19879865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_addr), 19889865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[cur].cookie.dmac_laddress + BFE_PCI_DMA)); 19899865SSaurabh.Mishra@Sun.COM 19909865SSaurabh.Mishra@Sun.COM /* 19919865SSaurabh.Mishra@Sun.COM * Sync the packet data for the device. 19929865SSaurabh.Mishra@Sun.COM */ 19939865SSaurabh.Mishra@Sun.COM (void) SYNC_BUF(r, cur, 0, pktlen, DDI_DMA_SYNC_FORDEV); 19949865SSaurabh.Mishra@Sun.COM 19959865SSaurabh.Mishra@Sun.COM /* Move to next descriptor slot */ 19969865SSaurabh.Mishra@Sun.COM BFE_INC_SLOT(next, TX_NUM_DESC); 19979865SSaurabh.Mishra@Sun.COM 19989865SSaurabh.Mishra@Sun.COM (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV); 19999865SSaurabh.Mishra@Sun.COM 20009865SSaurabh.Mishra@Sun.COM r->r_curr_desc = next; 20019865SSaurabh.Mishra@Sun.COM 20029865SSaurabh.Mishra@Sun.COM /* 20039865SSaurabh.Mishra@Sun.COM * The order should be 1,2,3,... for BFE_DMATX_PTR if 0,1,2,3,... 20049865SSaurabh.Mishra@Sun.COM * descriptor slot are being programmed. 20059865SSaurabh.Mishra@Sun.COM */ 20069865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_DMATX_PTR, next * sizeof (bfe_desc_t)); 20079865SSaurabh.Mishra@Sun.COM FLUSH(bfe, BFE_DMATX_PTR); 20089865SSaurabh.Mishra@Sun.COM 20099865SSaurabh.Mishra@Sun.COM r->r_avail_desc--; 20109865SSaurabh.Mishra@Sun.COM 20119865SSaurabh.Mishra@Sun.COM /* 20129865SSaurabh.Mishra@Sun.COM * Let timeout know that it must reset the chip if a 20139865SSaurabh.Mishra@Sun.COM * packet is not sent down the wire for more than 5 seconds. 20149865SSaurabh.Mishra@Sun.COM */ 20159865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_stall_time = gethrtime() + (5 * 1000000000ULL); 20169865SSaurabh.Mishra@Sun.COM 20179865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 20189865SSaurabh.Mishra@Sun.COM } 20199865SSaurabh.Mishra@Sun.COM 20209865SSaurabh.Mishra@Sun.COM mblk_t * 20219865SSaurabh.Mishra@Sun.COM bfe_mac_transmit_packet(void *arg, mblk_t *mp) 20229865SSaurabh.Mishra@Sun.COM { 20239865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 20249865SSaurabh.Mishra@Sun.COM bfe_ring_t *r = &bfe->bfe_tx_ring; 20259865SSaurabh.Mishra@Sun.COM mblk_t *nmp; 20269865SSaurabh.Mishra@Sun.COM 20279865SSaurabh.Mishra@Sun.COM mutex_enter(&r->r_lock); 20289865SSaurabh.Mishra@Sun.COM 20299865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) { 203010591SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(tx__chip__not__active, int, bfe->bfe_unit); 20319865SSaurabh.Mishra@Sun.COM 20329865SSaurabh.Mishra@Sun.COM freemsgchain(mp); 20339865SSaurabh.Mishra@Sun.COM mutex_exit(&r->r_lock); 20349865SSaurabh.Mishra@Sun.COM return (NULL); 20359865SSaurabh.Mishra@Sun.COM } 20369865SSaurabh.Mishra@Sun.COM 20379865SSaurabh.Mishra@Sun.COM 20389865SSaurabh.Mishra@Sun.COM while (mp != NULL) { 20399865SSaurabh.Mishra@Sun.COM nmp = mp->b_next; 20409865SSaurabh.Mishra@Sun.COM mp->b_next = NULL; 20419865SSaurabh.Mishra@Sun.COM 20429865SSaurabh.Mishra@Sun.COM if (bfe_send_a_packet(bfe, mp) == BFE_FAILURE) { 20439865SSaurabh.Mishra@Sun.COM mp->b_next = nmp; 20449865SSaurabh.Mishra@Sun.COM break; 20459865SSaurabh.Mishra@Sun.COM } 20469865SSaurabh.Mishra@Sun.COM mp = nmp; 20479865SSaurabh.Mishra@Sun.COM } 20489865SSaurabh.Mishra@Sun.COM 20499865SSaurabh.Mishra@Sun.COM mutex_exit(&r->r_lock); 20509865SSaurabh.Mishra@Sun.COM 20519865SSaurabh.Mishra@Sun.COM return (mp); 20529865SSaurabh.Mishra@Sun.COM } 20539865SSaurabh.Mishra@Sun.COM 20549865SSaurabh.Mishra@Sun.COM int 20559865SSaurabh.Mishra@Sun.COM bfe_mac_set_promisc(void *arg, boolean_t promiscflag) 20569865SSaurabh.Mishra@Sun.COM { 20579865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (bfe_t *)arg; 20589865SSaurabh.Mishra@Sun.COM 20599865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 20609865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) { 20619865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 20629865SSaurabh.Mishra@Sun.COM return (EIO); 20639865SSaurabh.Mishra@Sun.COM } 20649865SSaurabh.Mishra@Sun.COM 20659865SSaurabh.Mishra@Sun.COM if (promiscflag) { 20669865SSaurabh.Mishra@Sun.COM /* Set Promiscous on */ 20679865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_mode |= BFE_RX_MODE_PROMISC; 20689865SSaurabh.Mishra@Sun.COM } else { 20699865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_mode &= ~BFE_RX_MODE_PROMISC; 20709865SSaurabh.Mishra@Sun.COM } 20719865SSaurabh.Mishra@Sun.COM 20729865SSaurabh.Mishra@Sun.COM bfe_set_rx_mode(bfe); 20739865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 20749865SSaurabh.Mishra@Sun.COM 20759865SSaurabh.Mishra@Sun.COM return (0); 20769865SSaurabh.Mishra@Sun.COM } 20779865SSaurabh.Mishra@Sun.COM 20789865SSaurabh.Mishra@Sun.COM int 20799865SSaurabh.Mishra@Sun.COM bfe_mac_set_multicast(void *arg, boolean_t add, const uint8_t *macaddr) 20809865SSaurabh.Mishra@Sun.COM { 20819865SSaurabh.Mishra@Sun.COM /* 20829865SSaurabh.Mishra@Sun.COM * It was too much of pain to implement multicast in CAM. Instead 20839865SSaurabh.Mishra@Sun.COM * we never disable multicast filter. 20849865SSaurabh.Mishra@Sun.COM */ 20859865SSaurabh.Mishra@Sun.COM return (0); 20869865SSaurabh.Mishra@Sun.COM } 20879865SSaurabh.Mishra@Sun.COM 20889865SSaurabh.Mishra@Sun.COM static mac_callbacks_t bfe_mac_callbacks = { 2089*11878SVenu.Iyer@Sun.COM MC_SETPROP | MC_GETPROP | MC_PROPINFO, 20909865SSaurabh.Mishra@Sun.COM bfe_mac_getstat, /* gets stats */ 20919865SSaurabh.Mishra@Sun.COM bfe_mac_start, /* starts mac */ 20929865SSaurabh.Mishra@Sun.COM bfe_mac_stop, /* stops mac */ 20939865SSaurabh.Mishra@Sun.COM bfe_mac_set_promisc, /* sets promisc mode for snoop */ 20949865SSaurabh.Mishra@Sun.COM bfe_mac_set_multicast, /* multicast implementation */ 20959865SSaurabh.Mishra@Sun.COM bfe_mac_set_ether_addr, /* sets ethernet address (unicast) */ 20969865SSaurabh.Mishra@Sun.COM bfe_mac_transmit_packet, /* transmits packet */ 2097*11878SVenu.Iyer@Sun.COM NULL, 20989865SSaurabh.Mishra@Sun.COM NULL, /* ioctl */ 20999865SSaurabh.Mishra@Sun.COM NULL, /* getcap */ 21009865SSaurabh.Mishra@Sun.COM NULL, /* open */ 21019865SSaurabh.Mishra@Sun.COM NULL, /* close */ 21029865SSaurabh.Mishra@Sun.COM bfe_mac_setprop, 21039865SSaurabh.Mishra@Sun.COM bfe_mac_getprop, 2104*11878SVenu.Iyer@Sun.COM bfe_mac_propinfo 21059865SSaurabh.Mishra@Sun.COM }; 21069865SSaurabh.Mishra@Sun.COM 21079865SSaurabh.Mishra@Sun.COM static void 21089865SSaurabh.Mishra@Sun.COM bfe_error_handler(bfe_t *bfe, int intr_mask) 21099865SSaurabh.Mishra@Sun.COM { 21109865SSaurabh.Mishra@Sun.COM uint32_t v; 21119865SSaurabh.Mishra@Sun.COM 21129865SSaurabh.Mishra@Sun.COM if (intr_mask & BFE_ISTAT_RFO) { 21139865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.overflows++; 211410591SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= 211510591SSaurabh.Mishra@Sun.COM (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT); 211610591SSaurabh.Mishra@Sun.COM goto action; 21179865SSaurabh.Mishra@Sun.COM } 21189865SSaurabh.Mishra@Sun.COM 21199865SSaurabh.Mishra@Sun.COM if (intr_mask & BFE_ISTAT_TFU) { 21209865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.underflows++; 21219865SSaurabh.Mishra@Sun.COM return; 21229865SSaurabh.Mishra@Sun.COM } 21239865SSaurabh.Mishra@Sun.COM 21249865SSaurabh.Mishra@Sun.COM /* Descriptor Protocol Error */ 21259865SSaurabh.Mishra@Sun.COM if (intr_mask & BFE_ISTAT_DPE) { 21269865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, 21279865SSaurabh.Mishra@Sun.COM "Descriptor Protocol Error. Halting Chip"); 21289865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= 21299865SSaurabh.Mishra@Sun.COM (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT); 21309865SSaurabh.Mishra@Sun.COM goto action; 21319865SSaurabh.Mishra@Sun.COM } 21329865SSaurabh.Mishra@Sun.COM 21339865SSaurabh.Mishra@Sun.COM /* Descriptor Error */ 21349865SSaurabh.Mishra@Sun.COM if (intr_mask & BFE_ISTAT_DSCE && halt == 0) { 21359865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "Descriptor Error. Restarting Chip"); 21369865SSaurabh.Mishra@Sun.COM goto action; 21379865SSaurabh.Mishra@Sun.COM } 21389865SSaurabh.Mishra@Sun.COM 21399865SSaurabh.Mishra@Sun.COM /* Receive Descr. Underflow */ 21409865SSaurabh.Mishra@Sun.COM if (intr_mask & BFE_ISTAT_RDU) { 21419865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, 21429865SSaurabh.Mishra@Sun.COM "Receive Descriptor Underflow. Restarting Chip"); 21439865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_macrcv_errors++; 21449865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= 21459865SSaurabh.Mishra@Sun.COM (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT); 21469865SSaurabh.Mishra@Sun.COM goto action; 21479865SSaurabh.Mishra@Sun.COM } 21489865SSaurabh.Mishra@Sun.COM 21499865SSaurabh.Mishra@Sun.COM v = INL(bfe, BFE_DMATX_STAT); 21509865SSaurabh.Mishra@Sun.COM 21519865SSaurabh.Mishra@Sun.COM /* Error while sending a packet */ 21529865SSaurabh.Mishra@Sun.COM if (v & BFE_STAT_EMASK) { 21539865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ether_stat_macxmt_errors++; 21549865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, 21559865SSaurabh.Mishra@Sun.COM "Error while sending a packet. Restarting Chip"); 21569865SSaurabh.Mishra@Sun.COM } 21579865SSaurabh.Mishra@Sun.COM 21589865SSaurabh.Mishra@Sun.COM /* Error while receiving a packet */ 21599865SSaurabh.Mishra@Sun.COM v = INL(bfe, BFE_DMARX_STAT); 21609865SSaurabh.Mishra@Sun.COM if (v & BFE_RX_FLAG_ERRORS) { 21619865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ierrors++; 21629865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, 21639865SSaurabh.Mishra@Sun.COM "Error while receiving a packet. Restarting Chip"); 21649865SSaurabh.Mishra@Sun.COM } 21659865SSaurabh.Mishra@Sun.COM 21669865SSaurabh.Mishra@Sun.COM 21679865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action |= 21689865SSaurabh.Mishra@Sun.COM (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT); 21699865SSaurabh.Mishra@Sun.COM 21709865SSaurabh.Mishra@Sun.COM action: 21719865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 21729865SSaurabh.Mishra@Sun.COM } 21739865SSaurabh.Mishra@Sun.COM 21749865SSaurabh.Mishra@Sun.COM /* 21759865SSaurabh.Mishra@Sun.COM * It will recycle a RX descriptor slot. 21769865SSaurabh.Mishra@Sun.COM */ 21779865SSaurabh.Mishra@Sun.COM static void 21789865SSaurabh.Mishra@Sun.COM bfe_rx_desc_buf_reinit(bfe_t *bfe, uint_t slot) 21799865SSaurabh.Mishra@Sun.COM { 21809865SSaurabh.Mishra@Sun.COM bfe_ring_t *r = &bfe->bfe_rx_ring; 21819865SSaurabh.Mishra@Sun.COM uint32_t v; 21829865SSaurabh.Mishra@Sun.COM 21839865SSaurabh.Mishra@Sun.COM slot %= RX_NUM_DESC; 21849865SSaurabh.Mishra@Sun.COM 21859865SSaurabh.Mishra@Sun.COM bzero(r->r_buf_dma[slot].addr, sizeof (bfe_rx_header_t)); 21869865SSaurabh.Mishra@Sun.COM 21879865SSaurabh.Mishra@Sun.COM (void) SYNC_BUF(r, slot, 0, BFE_RX_OFFSET, DDI_DMA_SYNC_FORDEV); 21889865SSaurabh.Mishra@Sun.COM 21899865SSaurabh.Mishra@Sun.COM v = r->r_buf_dma[slot].len & BFE_DESC_LEN; 21909865SSaurabh.Mishra@Sun.COM if (slot == (RX_NUM_DESC - 1)) 21919865SSaurabh.Mishra@Sun.COM v |= BFE_DESC_EOT; 21929865SSaurabh.Mishra@Sun.COM 21939865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_ctl), v); 21949865SSaurabh.Mishra@Sun.COM 21959865SSaurabh.Mishra@Sun.COM /* 21969865SSaurabh.Mishra@Sun.COM * DMA addresses need to be added to BFE_PCI_DMA 21979865SSaurabh.Mishra@Sun.COM */ 21989865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_addr), 21999865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[slot].cookie.dmac_laddress + BFE_PCI_DMA)); 22009865SSaurabh.Mishra@Sun.COM } 22019865SSaurabh.Mishra@Sun.COM 22029865SSaurabh.Mishra@Sun.COM /* 22039865SSaurabh.Mishra@Sun.COM * Gets called from interrupt context to handle RX interrupt. 22049865SSaurabh.Mishra@Sun.COM */ 22059865SSaurabh.Mishra@Sun.COM static mblk_t * 22069865SSaurabh.Mishra@Sun.COM bfe_receive(bfe_t *bfe, int intr_mask) 22079865SSaurabh.Mishra@Sun.COM { 22089865SSaurabh.Mishra@Sun.COM int rxstat, current; 22099865SSaurabh.Mishra@Sun.COM mblk_t *mp = NULL, *rx_head, *rx_tail; 22109865SSaurabh.Mishra@Sun.COM uchar_t *rx_header; 22119865SSaurabh.Mishra@Sun.COM uint16_t len; 22129865SSaurabh.Mishra@Sun.COM uchar_t *bp; 22139865SSaurabh.Mishra@Sun.COM bfe_ring_t *r = &bfe->bfe_rx_ring; 22149865SSaurabh.Mishra@Sun.COM int i; 22159865SSaurabh.Mishra@Sun.COM 22169865SSaurabh.Mishra@Sun.COM rxstat = INL(bfe, BFE_DMARX_STAT); 22179865SSaurabh.Mishra@Sun.COM current = (rxstat & BFE_STAT_CDMASK) / sizeof (bfe_desc_t); 22189865SSaurabh.Mishra@Sun.COM i = r->r_curr_desc; 22199865SSaurabh.Mishra@Sun.COM 22209865SSaurabh.Mishra@Sun.COM rx_head = rx_tail = NULL; 22219865SSaurabh.Mishra@Sun.COM 22229865SSaurabh.Mishra@Sun.COM DTRACE_PROBE3(receive, int, bfe->bfe_unit, 22239865SSaurabh.Mishra@Sun.COM int, r->r_curr_desc, 22249865SSaurabh.Mishra@Sun.COM int, current); 22259865SSaurabh.Mishra@Sun.COM 22269865SSaurabh.Mishra@Sun.COM for (i = r->r_curr_desc; i != current; 22279865SSaurabh.Mishra@Sun.COM BFE_INC_SLOT(i, RX_NUM_DESC)) { 22289865SSaurabh.Mishra@Sun.COM 22299865SSaurabh.Mishra@Sun.COM /* 22309865SSaurabh.Mishra@Sun.COM * Sync the buffer associated with the descriptor table entry. 22319865SSaurabh.Mishra@Sun.COM */ 22329865SSaurabh.Mishra@Sun.COM (void) SYNC_BUF(r, i, 0, r->r_buf_dma[i].len, 22339865SSaurabh.Mishra@Sun.COM DDI_DMA_SYNC_FORKERNEL); 22349865SSaurabh.Mishra@Sun.COM 22359865SSaurabh.Mishra@Sun.COM rx_header = (void *)r->r_buf_dma[i].addr; 22369865SSaurabh.Mishra@Sun.COM 22379865SSaurabh.Mishra@Sun.COM /* 22389865SSaurabh.Mishra@Sun.COM * We do this to make sure we are endian neutral. Chip is 22399865SSaurabh.Mishra@Sun.COM * big endian. 22409865SSaurabh.Mishra@Sun.COM * 22419865SSaurabh.Mishra@Sun.COM * The header looks like :- 22429865SSaurabh.Mishra@Sun.COM * 22439865SSaurabh.Mishra@Sun.COM * Offset 0 -> uint16_t len 22449865SSaurabh.Mishra@Sun.COM * Offset 2 -> uint16_t flags 22459865SSaurabh.Mishra@Sun.COM * Offset 4 -> uint16_t pad[12] 22469865SSaurabh.Mishra@Sun.COM */ 22479865SSaurabh.Mishra@Sun.COM len = (rx_header[1] << 8) | rx_header[0]; 22489865SSaurabh.Mishra@Sun.COM len -= 4; /* CRC bytes need to be removed */ 22499865SSaurabh.Mishra@Sun.COM 22509865SSaurabh.Mishra@Sun.COM /* 22519865SSaurabh.Mishra@Sun.COM * Don't receive this packet if pkt length is greater than 22529865SSaurabh.Mishra@Sun.COM * MTU + VLAN_TAGSZ. 22539865SSaurabh.Mishra@Sun.COM */ 22549865SSaurabh.Mishra@Sun.COM if (len > r->r_buf_len) { 22559865SSaurabh.Mishra@Sun.COM /* Recycle slot for later use */ 22569865SSaurabh.Mishra@Sun.COM bfe_rx_desc_buf_reinit(bfe, i); 22579865SSaurabh.Mishra@Sun.COM continue; 22589865SSaurabh.Mishra@Sun.COM } 22599865SSaurabh.Mishra@Sun.COM 22609865SSaurabh.Mishra@Sun.COM if ((mp = allocb(len + VLAN_TAGSZ, BPRI_MED)) != NULL) { 22619865SSaurabh.Mishra@Sun.COM mp->b_rptr += VLAN_TAGSZ; 22629865SSaurabh.Mishra@Sun.COM bp = mp->b_rptr; 22639865SSaurabh.Mishra@Sun.COM mp->b_wptr = bp + len; 22649865SSaurabh.Mishra@Sun.COM 22659865SSaurabh.Mishra@Sun.COM /* sizeof (bfe_rx_header_t) + 2 */ 22669865SSaurabh.Mishra@Sun.COM bcopy(r->r_buf_dma[i].addr + 22679865SSaurabh.Mishra@Sun.COM BFE_RX_OFFSET, bp, len); 22689865SSaurabh.Mishra@Sun.COM 22699865SSaurabh.Mishra@Sun.COM mp->b_next = NULL; 22709865SSaurabh.Mishra@Sun.COM if (rx_tail == NULL) 22719865SSaurabh.Mishra@Sun.COM rx_head = rx_tail = mp; 22729865SSaurabh.Mishra@Sun.COM else { 22739865SSaurabh.Mishra@Sun.COM rx_tail->b_next = mp; 22749865SSaurabh.Mishra@Sun.COM rx_tail = mp; 22759865SSaurabh.Mishra@Sun.COM } 22769865SSaurabh.Mishra@Sun.COM 22779865SSaurabh.Mishra@Sun.COM /* Number of packets received so far */ 22789865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.ipackets++; 22799865SSaurabh.Mishra@Sun.COM 22809865SSaurabh.Mishra@Sun.COM /* Total bytes of packets received so far */ 22819865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.rbytes += len; 22829865SSaurabh.Mishra@Sun.COM 22839865SSaurabh.Mishra@Sun.COM if (bcmp(mp->b_rptr, bfe_broadcast, ETHERADDRL) == 0) 22849865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.brdcstrcv++; 22859865SSaurabh.Mishra@Sun.COM else 22869865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.multircv++; 22879865SSaurabh.Mishra@Sun.COM } else { 22889865SSaurabh.Mishra@Sun.COM bfe->bfe_stats.norcvbuf++; 22899865SSaurabh.Mishra@Sun.COM /* Recycle the slot for later use */ 22909865SSaurabh.Mishra@Sun.COM bfe_rx_desc_buf_reinit(bfe, i); 22919865SSaurabh.Mishra@Sun.COM break; 22929865SSaurabh.Mishra@Sun.COM } 22939865SSaurabh.Mishra@Sun.COM 22949865SSaurabh.Mishra@Sun.COM /* 22959865SSaurabh.Mishra@Sun.COM * Reinitialize the current descriptor slot's buffer so that 22969865SSaurabh.Mishra@Sun.COM * it can be reused. 22979865SSaurabh.Mishra@Sun.COM */ 22989865SSaurabh.Mishra@Sun.COM bfe_rx_desc_buf_reinit(bfe, i); 22999865SSaurabh.Mishra@Sun.COM } 23009865SSaurabh.Mishra@Sun.COM 23019865SSaurabh.Mishra@Sun.COM r->r_curr_desc = i; 23029865SSaurabh.Mishra@Sun.COM 23039865SSaurabh.Mishra@Sun.COM (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV); 23049865SSaurabh.Mishra@Sun.COM 23059865SSaurabh.Mishra@Sun.COM return (rx_head); 23069865SSaurabh.Mishra@Sun.COM } 23079865SSaurabh.Mishra@Sun.COM 23089865SSaurabh.Mishra@Sun.COM static int 23099865SSaurabh.Mishra@Sun.COM bfe_tx_reclaim(bfe_ring_t *r) 23109865SSaurabh.Mishra@Sun.COM { 23119865SSaurabh.Mishra@Sun.COM uint32_t cur, start; 23129865SSaurabh.Mishra@Sun.COM uint32_t v; 23139865SSaurabh.Mishra@Sun.COM 23149865SSaurabh.Mishra@Sun.COM cur = INL(r->r_bfe, BFE_DMATX_STAT) & BFE_STAT_CDMASK; 23159865SSaurabh.Mishra@Sun.COM cur = cur / sizeof (bfe_desc_t); 23169865SSaurabh.Mishra@Sun.COM 23179865SSaurabh.Mishra@Sun.COM /* 23189865SSaurabh.Mishra@Sun.COM * Start with the last descriptor consumed by the chip. 23199865SSaurabh.Mishra@Sun.COM */ 23209865SSaurabh.Mishra@Sun.COM start = r->r_cons_desc; 23219865SSaurabh.Mishra@Sun.COM 23229865SSaurabh.Mishra@Sun.COM DTRACE_PROBE3(tx__reclaim, int, r->r_bfe->bfe_unit, 23239865SSaurabh.Mishra@Sun.COM int, start, 23249865SSaurabh.Mishra@Sun.COM int, cur); 23259865SSaurabh.Mishra@Sun.COM 23269865SSaurabh.Mishra@Sun.COM /* 23279865SSaurabh.Mishra@Sun.COM * There will be at least one descriptor to process. 23289865SSaurabh.Mishra@Sun.COM */ 23299865SSaurabh.Mishra@Sun.COM while (start != cur) { 23309865SSaurabh.Mishra@Sun.COM r->r_avail_desc++; 23319865SSaurabh.Mishra@Sun.COM v = r->r_buf_dma[start].len & BFE_DESC_LEN; 23329865SSaurabh.Mishra@Sun.COM if (start == (TX_NUM_DESC - 1)) 23339865SSaurabh.Mishra@Sun.COM v |= BFE_DESC_EOT; 23349865SSaurabh.Mishra@Sun.COM 23359865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_ctl), v); 23369865SSaurabh.Mishra@Sun.COM PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_addr), 23379865SSaurabh.Mishra@Sun.COM (r->r_buf_dma[start].cookie.dmac_laddress + BFE_PCI_DMA)); 23389865SSaurabh.Mishra@Sun.COM 23399865SSaurabh.Mishra@Sun.COM /* Move to next descriptor in TX ring */ 23409865SSaurabh.Mishra@Sun.COM BFE_INC_SLOT(start, TX_NUM_DESC); 23419865SSaurabh.Mishra@Sun.COM } 23429865SSaurabh.Mishra@Sun.COM 23439865SSaurabh.Mishra@Sun.COM (void) ddi_dma_sync(r->r_desc_dma_handle, 23449865SSaurabh.Mishra@Sun.COM 0, (r->r_ndesc * sizeof (bfe_desc_t)), 23459865SSaurabh.Mishra@Sun.COM DDI_DMA_SYNC_FORDEV); 23469865SSaurabh.Mishra@Sun.COM 23479865SSaurabh.Mishra@Sun.COM r->r_cons_desc = start; /* consumed pointer */ 23489865SSaurabh.Mishra@Sun.COM r->r_bfe->bfe_tx_stall_time = 0; 23499865SSaurabh.Mishra@Sun.COM 23509865SSaurabh.Mishra@Sun.COM return (cur); 23519865SSaurabh.Mishra@Sun.COM } 23529865SSaurabh.Mishra@Sun.COM 23539865SSaurabh.Mishra@Sun.COM static int 23549865SSaurabh.Mishra@Sun.COM bfe_tx_done(bfe_t *bfe, int intr_mask) 23559865SSaurabh.Mishra@Sun.COM { 23569865SSaurabh.Mishra@Sun.COM bfe_ring_t *r = &bfe->bfe_tx_ring; 23579865SSaurabh.Mishra@Sun.COM int resched = 0; 23589865SSaurabh.Mishra@Sun.COM 23599865SSaurabh.Mishra@Sun.COM mutex_enter(&r->r_lock); 23609865SSaurabh.Mishra@Sun.COM (void) bfe_tx_reclaim(r); 23619865SSaurabh.Mishra@Sun.COM 23629865SSaurabh.Mishra@Sun.COM if (bfe->bfe_tx_resched) { 23639865SSaurabh.Mishra@Sun.COM resched = 1; 23649865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_resched = 0; 23659865SSaurabh.Mishra@Sun.COM } 23669865SSaurabh.Mishra@Sun.COM mutex_exit(&r->r_lock); 23679865SSaurabh.Mishra@Sun.COM 23689865SSaurabh.Mishra@Sun.COM return (resched); 23699865SSaurabh.Mishra@Sun.COM } 23709865SSaurabh.Mishra@Sun.COM 23719865SSaurabh.Mishra@Sun.COM /* 23729865SSaurabh.Mishra@Sun.COM * ISR for interrupt handling 23739865SSaurabh.Mishra@Sun.COM */ 23749865SSaurabh.Mishra@Sun.COM static uint_t 23759865SSaurabh.Mishra@Sun.COM bfe_interrupt(caddr_t arg1, caddr_t arg2) 23769865SSaurabh.Mishra@Sun.COM { 23779865SSaurabh.Mishra@Sun.COM bfe_t *bfe = (void *)arg1; 23789865SSaurabh.Mishra@Sun.COM uint32_t intr_stat; 23799865SSaurabh.Mishra@Sun.COM mblk_t *rx_head = NULL; 23809865SSaurabh.Mishra@Sun.COM int resched = 0; 23819865SSaurabh.Mishra@Sun.COM 23829865SSaurabh.Mishra@Sun.COM /* 23839865SSaurabh.Mishra@Sun.COM * Grab the lock to avoid stopping the chip while this interrupt 23849865SSaurabh.Mishra@Sun.COM * is handled. 23859865SSaurabh.Mishra@Sun.COM */ 23869865SSaurabh.Mishra@Sun.COM rw_enter(&bfe->bfe_rwlock, RW_READER); 23879865SSaurabh.Mishra@Sun.COM 23889865SSaurabh.Mishra@Sun.COM /* 23899865SSaurabh.Mishra@Sun.COM * It's necessary to read intr stat again because masking interrupt 23909865SSaurabh.Mishra@Sun.COM * register does not really mask interrupts coming from the chip. 23919865SSaurabh.Mishra@Sun.COM */ 23929865SSaurabh.Mishra@Sun.COM intr_stat = INL(bfe, BFE_INTR_STAT); 23939865SSaurabh.Mishra@Sun.COM intr_stat &= BFE_IMASK_DEF; 23949865SSaurabh.Mishra@Sun.COM OUTL(bfe, BFE_INTR_STAT, intr_stat); 23959865SSaurabh.Mishra@Sun.COM (void) INL(bfe, BFE_INTR_STAT); 23969865SSaurabh.Mishra@Sun.COM 23979865SSaurabh.Mishra@Sun.COM if (intr_stat == 0) { 23989865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 23999865SSaurabh.Mishra@Sun.COM return (DDI_INTR_UNCLAIMED); 24009865SSaurabh.Mishra@Sun.COM } 24019865SSaurabh.Mishra@Sun.COM 240210591SSaurabh.Mishra@Sun.COM DTRACE_PROBE2(bfe__interrupt, int, bfe->bfe_unit, 240310591SSaurabh.Mishra@Sun.COM int, intr_stat); 240410591SSaurabh.Mishra@Sun.COM 24059865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) { 24069865SSaurabh.Mishra@Sun.COM /* 24079865SSaurabh.Mishra@Sun.COM * If chip is suspended then we just return. 24089865SSaurabh.Mishra@Sun.COM */ 24099865SSaurabh.Mishra@Sun.COM if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED) { 24109865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 24119865SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(interrupt__chip__is__suspend, int, 24129865SSaurabh.Mishra@Sun.COM bfe->bfe_unit); 24139865SSaurabh.Mishra@Sun.COM return (DDI_INTR_CLAIMED); 24149865SSaurabh.Mishra@Sun.COM } 24159865SSaurabh.Mishra@Sun.COM 24169865SSaurabh.Mishra@Sun.COM /* 24179865SSaurabh.Mishra@Sun.COM * Halt the chip again i.e basically disable interrupts. 24189865SSaurabh.Mishra@Sun.COM */ 24199865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 24209865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 24219865SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(interrupt__chip__not__active, int, 24229865SSaurabh.Mishra@Sun.COM bfe->bfe_unit); 24239865SSaurabh.Mishra@Sun.COM return (DDI_INTR_CLAIMED); 24249865SSaurabh.Mishra@Sun.COM } 24259865SSaurabh.Mishra@Sun.COM 24269865SSaurabh.Mishra@Sun.COM /* A packet was received */ 24279865SSaurabh.Mishra@Sun.COM if (intr_stat & BFE_ISTAT_RX) { 24289865SSaurabh.Mishra@Sun.COM rx_head = bfe_receive(bfe, intr_stat); 24299865SSaurabh.Mishra@Sun.COM } 24309865SSaurabh.Mishra@Sun.COM 24319865SSaurabh.Mishra@Sun.COM /* A packet was sent down the wire */ 24329865SSaurabh.Mishra@Sun.COM if (intr_stat & BFE_ISTAT_TX) { 24339865SSaurabh.Mishra@Sun.COM resched = bfe_tx_done(bfe, intr_stat); 24349865SSaurabh.Mishra@Sun.COM } 24359865SSaurabh.Mishra@Sun.COM 24369865SSaurabh.Mishra@Sun.COM /* There was an error */ 24379865SSaurabh.Mishra@Sun.COM if (intr_stat & BFE_ISTAT_ERRORS) { 24389865SSaurabh.Mishra@Sun.COM bfe_error_handler(bfe, intr_stat); 24399865SSaurabh.Mishra@Sun.COM } 24409865SSaurabh.Mishra@Sun.COM 24419865SSaurabh.Mishra@Sun.COM rw_exit(&bfe->bfe_rwlock); 24429865SSaurabh.Mishra@Sun.COM 24439865SSaurabh.Mishra@Sun.COM /* 24449865SSaurabh.Mishra@Sun.COM * Pass the list of packets received from chip to MAC layer. 24459865SSaurabh.Mishra@Sun.COM */ 24469865SSaurabh.Mishra@Sun.COM if (rx_head) { 24479865SSaurabh.Mishra@Sun.COM mac_rx(bfe->bfe_machdl, 0, rx_head); 24489865SSaurabh.Mishra@Sun.COM } 24499865SSaurabh.Mishra@Sun.COM 24509865SSaurabh.Mishra@Sun.COM /* 24519865SSaurabh.Mishra@Sun.COM * Let the MAC start sending pkts to a potential stopped stream. 24529865SSaurabh.Mishra@Sun.COM */ 24539865SSaurabh.Mishra@Sun.COM if (resched) 24549865SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 24559865SSaurabh.Mishra@Sun.COM 24569865SSaurabh.Mishra@Sun.COM return (DDI_INTR_CLAIMED); 24579865SSaurabh.Mishra@Sun.COM } 24589865SSaurabh.Mishra@Sun.COM 24599865SSaurabh.Mishra@Sun.COM /* 24609865SSaurabh.Mishra@Sun.COM * Removes registered interrupt handler. 24619865SSaurabh.Mishra@Sun.COM */ 24629865SSaurabh.Mishra@Sun.COM static void 24639865SSaurabh.Mishra@Sun.COM bfe_remove_intr(bfe_t *bfe) 24649865SSaurabh.Mishra@Sun.COM { 24659865SSaurabh.Mishra@Sun.COM (void) ddi_intr_remove_handler(bfe->bfe_intrhdl); 24669865SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(bfe->bfe_intrhdl); 24679865SSaurabh.Mishra@Sun.COM } 24689865SSaurabh.Mishra@Sun.COM 24699865SSaurabh.Mishra@Sun.COM /* 24709865SSaurabh.Mishra@Sun.COM * Add an interrupt for the driver. 24719865SSaurabh.Mishra@Sun.COM */ 24729865SSaurabh.Mishra@Sun.COM static int 24739865SSaurabh.Mishra@Sun.COM bfe_add_intr(bfe_t *bfe) 24749865SSaurabh.Mishra@Sun.COM { 24759865SSaurabh.Mishra@Sun.COM int nintrs = 1; 24769865SSaurabh.Mishra@Sun.COM int ret; 24779865SSaurabh.Mishra@Sun.COM 24789865SSaurabh.Mishra@Sun.COM ret = ddi_intr_alloc(bfe->bfe_dip, &bfe->bfe_intrhdl, 24799865SSaurabh.Mishra@Sun.COM DDI_INTR_TYPE_FIXED, /* type */ 24809865SSaurabh.Mishra@Sun.COM 0, /* inumber */ 24819865SSaurabh.Mishra@Sun.COM 1, /* count */ 24829865SSaurabh.Mishra@Sun.COM &nintrs, /* actual nintrs */ 24839865SSaurabh.Mishra@Sun.COM DDI_INTR_ALLOC_STRICT); 24849865SSaurabh.Mishra@Sun.COM 24859865SSaurabh.Mishra@Sun.COM if (ret != DDI_SUCCESS) { 24869865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "ddi_intr_alloc() failed" 24879865SSaurabh.Mishra@Sun.COM " : ret : %d", ret); 24889865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 24899865SSaurabh.Mishra@Sun.COM } 24909865SSaurabh.Mishra@Sun.COM 24919865SSaurabh.Mishra@Sun.COM ret = ddi_intr_add_handler(bfe->bfe_intrhdl, bfe_interrupt, bfe, NULL); 24929865SSaurabh.Mishra@Sun.COM if (ret != DDI_SUCCESS) { 24939865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "ddi_intr_add_handler() failed"); 24949865SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(bfe->bfe_intrhdl); 24959865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 24969865SSaurabh.Mishra@Sun.COM } 24979865SSaurabh.Mishra@Sun.COM 24989865SSaurabh.Mishra@Sun.COM ret = ddi_intr_get_pri(bfe->bfe_intrhdl, &bfe->bfe_intrpri); 24999865SSaurabh.Mishra@Sun.COM if (ret != DDI_SUCCESS) { 25009865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "ddi_intr_get_pri() failed"); 25019865SSaurabh.Mishra@Sun.COM bfe_remove_intr(bfe); 25029865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 25039865SSaurabh.Mishra@Sun.COM } 25049865SSaurabh.Mishra@Sun.COM 25059865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 25069865SSaurabh.Mishra@Sun.COM } 25079865SSaurabh.Mishra@Sun.COM 25089865SSaurabh.Mishra@Sun.COM 25099865SSaurabh.Mishra@Sun.COM /* 25109865SSaurabh.Mishra@Sun.COM * Identify chipset family. 25119865SSaurabh.Mishra@Sun.COM */ 25129865SSaurabh.Mishra@Sun.COM static int 25139865SSaurabh.Mishra@Sun.COM bfe_identify_hardware(bfe_t *bfe) 25149865SSaurabh.Mishra@Sun.COM { 25159865SSaurabh.Mishra@Sun.COM uint16_t vid, did; 25169865SSaurabh.Mishra@Sun.COM int i; 25179865SSaurabh.Mishra@Sun.COM 25189865SSaurabh.Mishra@Sun.COM vid = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_VENID); 25199865SSaurabh.Mishra@Sun.COM did = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_DEVID); 25209865SSaurabh.Mishra@Sun.COM 25219865SSaurabh.Mishra@Sun.COM for (i = 0; i < (sizeof (bfe_cards) / sizeof (bfe_cards_t)); i++) { 25229865SSaurabh.Mishra@Sun.COM if (bfe_cards[i].vendor_id == vid && 25239865SSaurabh.Mishra@Sun.COM bfe_cards[i].device_id == did) { 25249865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 25259865SSaurabh.Mishra@Sun.COM } 25269865SSaurabh.Mishra@Sun.COM } 25279865SSaurabh.Mishra@Sun.COM 25289865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "bfe driver is attaching to unknown pci%d,%d" 25299865SSaurabh.Mishra@Sun.COM " vendor/device-id card", vid, did); 25309865SSaurabh.Mishra@Sun.COM 25319865SSaurabh.Mishra@Sun.COM return (BFE_SUCCESS); 25329865SSaurabh.Mishra@Sun.COM } 25339865SSaurabh.Mishra@Sun.COM 25349865SSaurabh.Mishra@Sun.COM /* 25359865SSaurabh.Mishra@Sun.COM * Maps device registers. 25369865SSaurabh.Mishra@Sun.COM */ 25379865SSaurabh.Mishra@Sun.COM static int 25389865SSaurabh.Mishra@Sun.COM bfe_regs_map(bfe_t *bfe) 25399865SSaurabh.Mishra@Sun.COM { 25409865SSaurabh.Mishra@Sun.COM dev_info_t *dip = bfe->bfe_dip; 25419865SSaurabh.Mishra@Sun.COM int ret; 25429865SSaurabh.Mishra@Sun.COM 25439865SSaurabh.Mishra@Sun.COM ret = ddi_regs_map_setup(dip, 1, &bfe->bfe_mem_regset.addr, 0, 0, 25449865SSaurabh.Mishra@Sun.COM &bfe_dev_attr, &bfe->bfe_mem_regset.hdl); 25459865SSaurabh.Mishra@Sun.COM 25469865SSaurabh.Mishra@Sun.COM if (ret != DDI_SUCCESS) { 25479865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "ddi_regs_map_setup failed"); 25489865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 25499865SSaurabh.Mishra@Sun.COM } 25509865SSaurabh.Mishra@Sun.COM 25519865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 25529865SSaurabh.Mishra@Sun.COM } 25539865SSaurabh.Mishra@Sun.COM 25549865SSaurabh.Mishra@Sun.COM static void 25559865SSaurabh.Mishra@Sun.COM bfe_unmap_regs(bfe_t *bfe) 25569865SSaurabh.Mishra@Sun.COM { 25579865SSaurabh.Mishra@Sun.COM ddi_regs_map_free(&bfe->bfe_mem_regset.hdl); 25589865SSaurabh.Mishra@Sun.COM } 25599865SSaurabh.Mishra@Sun.COM 25609865SSaurabh.Mishra@Sun.COM static int 25619865SSaurabh.Mishra@Sun.COM bfe_get_chip_config(bfe_t *bfe) 25629865SSaurabh.Mishra@Sun.COM { 25639865SSaurabh.Mishra@Sun.COM uint32_t prom[BFE_EEPROM_SIZE]; 25649865SSaurabh.Mishra@Sun.COM int i; 25659865SSaurabh.Mishra@Sun.COM 25669865SSaurabh.Mishra@Sun.COM /* 25679865SSaurabh.Mishra@Sun.COM * Read EEPROM in prom[] 25689865SSaurabh.Mishra@Sun.COM */ 25699865SSaurabh.Mishra@Sun.COM for (i = 0; i < BFE_EEPROM_SIZE; i++) { 25709865SSaurabh.Mishra@Sun.COM prom[i] = INL(bfe, BFE_EEPROM_BASE + i * sizeof (uint32_t)); 25719865SSaurabh.Mishra@Sun.COM } 25729865SSaurabh.Mishra@Sun.COM 25739865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[0] = bfe->bfe_ether_addr[0] = 25749865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 79); 25759865SSaurabh.Mishra@Sun.COM 25769865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[1] = bfe->bfe_ether_addr[1] = 25779865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 78); 25789865SSaurabh.Mishra@Sun.COM 25799865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[2] = bfe->bfe_ether_addr[2] = 25809865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 81); 25819865SSaurabh.Mishra@Sun.COM 25829865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[3] = bfe->bfe_ether_addr[3] = 25839865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 80); 25849865SSaurabh.Mishra@Sun.COM 25859865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[4] = bfe->bfe_ether_addr[4] = 25869865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 83); 25879865SSaurabh.Mishra@Sun.COM 25889865SSaurabh.Mishra@Sun.COM bfe->bfe_dev_addr[5] = bfe->bfe_ether_addr[5] = 25899865SSaurabh.Mishra@Sun.COM INB(bfe, BFE_EEPROM_BASE + 82); 25909865SSaurabh.Mishra@Sun.COM 25919865SSaurabh.Mishra@Sun.COM bfe->bfe_phy_addr = -1; 25929865SSaurabh.Mishra@Sun.COM 25939865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 25949865SSaurabh.Mishra@Sun.COM } 25959865SSaurabh.Mishra@Sun.COM 25969865SSaurabh.Mishra@Sun.COM /* 25979865SSaurabh.Mishra@Sun.COM * Ring Management routines 25989865SSaurabh.Mishra@Sun.COM */ 25999865SSaurabh.Mishra@Sun.COM static int 26009865SSaurabh.Mishra@Sun.COM bfe_ring_buf_alloc(bfe_t *bfe, bfe_ring_t *r, int slot, int d) 26019865SSaurabh.Mishra@Sun.COM { 26029865SSaurabh.Mishra@Sun.COM int err; 26039865SSaurabh.Mishra@Sun.COM uint_t count = 0; 26049865SSaurabh.Mishra@Sun.COM 26059865SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(bfe->bfe_dip, 26069865SSaurabh.Mishra@Sun.COM &bfe_dma_attr_buf, DDI_DMA_SLEEP, NULL, 26079865SSaurabh.Mishra@Sun.COM &r->r_buf_dma[slot].handle); 26089865SSaurabh.Mishra@Sun.COM 26099865SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 26109865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :" 26119865SSaurabh.Mishra@Sun.COM " alloc_handle failed"); 26129865SSaurabh.Mishra@Sun.COM goto fail0; 26139865SSaurabh.Mishra@Sun.COM } 26149865SSaurabh.Mishra@Sun.COM 26159865SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(r->r_buf_dma[slot].handle, 26169865SSaurabh.Mishra@Sun.COM r->r_buf_len, &bfe_buf_attr, DDI_DMA_STREAMING, 26179865SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &r->r_buf_dma[slot].addr, 26189865SSaurabh.Mishra@Sun.COM &r->r_buf_dma[slot].len, 26199865SSaurabh.Mishra@Sun.COM &r->r_buf_dma[slot].acchdl); 26209865SSaurabh.Mishra@Sun.COM 26219865SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 26229865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :" 26239865SSaurabh.Mishra@Sun.COM " mem_alloc failed :%d", err); 26249865SSaurabh.Mishra@Sun.COM goto fail1; 26259865SSaurabh.Mishra@Sun.COM } 26269865SSaurabh.Mishra@Sun.COM 26279865SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(r->r_buf_dma[slot].handle, 26289865SSaurabh.Mishra@Sun.COM NULL, r->r_buf_dma[slot].addr, 26299865SSaurabh.Mishra@Sun.COM r->r_buf_dma[slot].len, 26309865SSaurabh.Mishra@Sun.COM (DDI_DMA_RDWR | DDI_DMA_STREAMING), 26319865SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, 26329865SSaurabh.Mishra@Sun.COM &r->r_buf_dma[slot].cookie, 26339865SSaurabh.Mishra@Sun.COM &count); 26349865SSaurabh.Mishra@Sun.COM 26359865SSaurabh.Mishra@Sun.COM if (err != DDI_DMA_MAPPED) { 26369865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :" 26379865SSaurabh.Mishra@Sun.COM " bind_handle failed"); 26389865SSaurabh.Mishra@Sun.COM goto fail2; 26399865SSaurabh.Mishra@Sun.COM } 26409865SSaurabh.Mishra@Sun.COM 26419865SSaurabh.Mishra@Sun.COM if (count > 1) { 26429865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :" 26439865SSaurabh.Mishra@Sun.COM " more than one DMA cookie"); 26449865SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle); 26459865SSaurabh.Mishra@Sun.COM goto fail2; 26469865SSaurabh.Mishra@Sun.COM } 26479865SSaurabh.Mishra@Sun.COM 26489865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 26499865SSaurabh.Mishra@Sun.COM fail2: 26509865SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl); 26519865SSaurabh.Mishra@Sun.COM fail1: 26529865SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&r->r_buf_dma[slot].handle); 26539865SSaurabh.Mishra@Sun.COM fail0: 26549865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 26559865SSaurabh.Mishra@Sun.COM } 26569865SSaurabh.Mishra@Sun.COM 26579865SSaurabh.Mishra@Sun.COM static void 26589865SSaurabh.Mishra@Sun.COM bfe_ring_buf_free(bfe_ring_t *r, int slot) 26599865SSaurabh.Mishra@Sun.COM { 26609865SSaurabh.Mishra@Sun.COM if (r->r_buf_dma == NULL) 26619865SSaurabh.Mishra@Sun.COM return; 26629865SSaurabh.Mishra@Sun.COM 26639865SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle); 26649865SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl); 26659865SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&r->r_buf_dma[slot].handle); 26669865SSaurabh.Mishra@Sun.COM } 26679865SSaurabh.Mishra@Sun.COM 26689865SSaurabh.Mishra@Sun.COM static void 26699865SSaurabh.Mishra@Sun.COM bfe_buffer_free(bfe_ring_t *r) 26709865SSaurabh.Mishra@Sun.COM { 26719865SSaurabh.Mishra@Sun.COM int i; 26729865SSaurabh.Mishra@Sun.COM 26739865SSaurabh.Mishra@Sun.COM for (i = 0; i < r->r_ndesc; i++) { 26749865SSaurabh.Mishra@Sun.COM bfe_ring_buf_free(r, i); 26759865SSaurabh.Mishra@Sun.COM } 26769865SSaurabh.Mishra@Sun.COM } 26779865SSaurabh.Mishra@Sun.COM 26789865SSaurabh.Mishra@Sun.COM static void 26799865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(bfe_ring_t *r) 26809865SSaurabh.Mishra@Sun.COM { 26819865SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(r->r_desc_dma_handle); 26829865SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&r->r_desc_acc_handle); 26839865SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&r->r_desc_dma_handle); 26849865SSaurabh.Mishra@Sun.COM kmem_free(r->r_buf_dma, r->r_ndesc * sizeof (bfe_dma_t)); 26859865SSaurabh.Mishra@Sun.COM 26869865SSaurabh.Mishra@Sun.COM r->r_buf_dma = NULL; 26879865SSaurabh.Mishra@Sun.COM r->r_desc = NULL; 26889865SSaurabh.Mishra@Sun.COM } 26899865SSaurabh.Mishra@Sun.COM 26909865SSaurabh.Mishra@Sun.COM 26919865SSaurabh.Mishra@Sun.COM static int 26929865SSaurabh.Mishra@Sun.COM bfe_ring_desc_alloc(bfe_t *bfe, bfe_ring_t *r, int d) 26939865SSaurabh.Mishra@Sun.COM { 26949865SSaurabh.Mishra@Sun.COM int err, i, fail = 0; 26959865SSaurabh.Mishra@Sun.COM caddr_t ring; 26969865SSaurabh.Mishra@Sun.COM size_t size_krnl = 0, size_dma = 0, ring_len = 0; 26979865SSaurabh.Mishra@Sun.COM ddi_dma_cookie_t cookie; 26989865SSaurabh.Mishra@Sun.COM uint_t count = 0; 26999865SSaurabh.Mishra@Sun.COM 27009865SSaurabh.Mishra@Sun.COM ASSERT(bfe != NULL); 27019865SSaurabh.Mishra@Sun.COM 27029865SSaurabh.Mishra@Sun.COM size_krnl = r->r_ndesc * sizeof (bfe_dma_t); 27039865SSaurabh.Mishra@Sun.COM size_dma = r->r_ndesc * sizeof (bfe_desc_t); 27049865SSaurabh.Mishra@Sun.COM r->r_buf_dma = kmem_zalloc(size_krnl, KM_SLEEP); 27059865SSaurabh.Mishra@Sun.COM 27069865SSaurabh.Mishra@Sun.COM 27079865SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(bfe->bfe_dip, &bfe_dma_attr_desc, 27089865SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &r->r_desc_dma_handle); 27099865SSaurabh.Mishra@Sun.COM 27109865SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 27119865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on" 27129865SSaurabh.Mishra@Sun.COM " ddi_dma_alloc_handle()"); 27139865SSaurabh.Mishra@Sun.COM kmem_free(r->r_buf_dma, size_krnl); 27149865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 27159865SSaurabh.Mishra@Sun.COM } 27169865SSaurabh.Mishra@Sun.COM 27179865SSaurabh.Mishra@Sun.COM 27189865SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(r->r_desc_dma_handle, 27199865SSaurabh.Mishra@Sun.COM size_dma, &bfe_buf_attr, 27209865SSaurabh.Mishra@Sun.COM DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 27219865SSaurabh.Mishra@Sun.COM &ring, &ring_len, &r->r_desc_acc_handle); 27229865SSaurabh.Mishra@Sun.COM 27239865SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 27249865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on" 27259865SSaurabh.Mishra@Sun.COM " ddi_dma_mem_alloc()"); 27269865SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&r->r_desc_dma_handle); 27279865SSaurabh.Mishra@Sun.COM kmem_free(r->r_buf_dma, size_krnl); 27289865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 27299865SSaurabh.Mishra@Sun.COM } 27309865SSaurabh.Mishra@Sun.COM 27319865SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(r->r_desc_dma_handle, 27329865SSaurabh.Mishra@Sun.COM NULL, ring, ring_len, 27339865SSaurabh.Mishra@Sun.COM DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 27349865SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, 27359865SSaurabh.Mishra@Sun.COM &cookie, &count); 27369865SSaurabh.Mishra@Sun.COM 27379865SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 27389865SSaurabh.Mishra@Sun.COM bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on" 27399865SSaurabh.Mishra@Sun.COM " ddi_dma_addr_bind_handle()"); 27409865SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&r->r_desc_acc_handle); 27419865SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&r->r_desc_dma_handle); 27429865SSaurabh.Mishra@Sun.COM kmem_free(r->r_buf_dma, size_krnl); 27439865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 27449865SSaurabh.Mishra@Sun.COM } 27459865SSaurabh.Mishra@Sun.COM 27469865SSaurabh.Mishra@Sun.COM /* 27479865SSaurabh.Mishra@Sun.COM * We don't want to have multiple cookies. Descriptor should be 27489865SSaurabh.Mishra@Sun.COM * aligned to PAGESIZE boundary. 27499865SSaurabh.Mishra@Sun.COM */ 27509865SSaurabh.Mishra@Sun.COM ASSERT(count == 1); 27519865SSaurabh.Mishra@Sun.COM 27529865SSaurabh.Mishra@Sun.COM /* The actual descriptor for the ring */ 27539865SSaurabh.Mishra@Sun.COM r->r_desc_len = ring_len; 27549865SSaurabh.Mishra@Sun.COM r->r_desc_cookie = cookie; 27559865SSaurabh.Mishra@Sun.COM 27569865SSaurabh.Mishra@Sun.COM r->r_desc = (void *)ring; 27579865SSaurabh.Mishra@Sun.COM 27589865SSaurabh.Mishra@Sun.COM bzero(r->r_desc, size_dma); 27599865SSaurabh.Mishra@Sun.COM bzero(r->r_desc, ring_len); 27609865SSaurabh.Mishra@Sun.COM 27619865SSaurabh.Mishra@Sun.COM /* For each descriptor, allocate a DMA buffer */ 27629865SSaurabh.Mishra@Sun.COM fail = 0; 27639865SSaurabh.Mishra@Sun.COM for (i = 0; i < r->r_ndesc; i++) { 27649865SSaurabh.Mishra@Sun.COM if (bfe_ring_buf_alloc(bfe, r, i, d) != DDI_SUCCESS) { 27659865SSaurabh.Mishra@Sun.COM i--; 27669865SSaurabh.Mishra@Sun.COM fail = 1; 27679865SSaurabh.Mishra@Sun.COM break; 27689865SSaurabh.Mishra@Sun.COM } 27699865SSaurabh.Mishra@Sun.COM } 27709865SSaurabh.Mishra@Sun.COM 27719865SSaurabh.Mishra@Sun.COM if (fail) { 27729865SSaurabh.Mishra@Sun.COM while (i-- >= 0) { 27739865SSaurabh.Mishra@Sun.COM bfe_ring_buf_free(r, i); 27749865SSaurabh.Mishra@Sun.COM } 27759865SSaurabh.Mishra@Sun.COM 27769865SSaurabh.Mishra@Sun.COM /* We don't need the descriptor anymore */ 27779865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(r); 27789865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 27799865SSaurabh.Mishra@Sun.COM } 27809865SSaurabh.Mishra@Sun.COM 27819865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 27829865SSaurabh.Mishra@Sun.COM } 27839865SSaurabh.Mishra@Sun.COM 27849865SSaurabh.Mishra@Sun.COM static int 27859865SSaurabh.Mishra@Sun.COM bfe_rings_alloc(bfe_t *bfe) 27869865SSaurabh.Mishra@Sun.COM { 27879865SSaurabh.Mishra@Sun.COM /* TX */ 27889865SSaurabh.Mishra@Sun.COM mutex_init(&bfe->bfe_tx_ring.r_lock, NULL, MUTEX_DRIVER, NULL); 27899865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_lockp = &bfe->bfe_tx_ring.r_lock; 27909865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) + 27919865SSaurabh.Mishra@Sun.COM VLAN_TAGSZ + ETHERFCSL; 27929865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_ndesc = TX_NUM_DESC; 27939865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_bfe = bfe; 27949865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_avail_desc = TX_NUM_DESC; 27959865SSaurabh.Mishra@Sun.COM 27969865SSaurabh.Mishra@Sun.COM /* RX */ 27979865SSaurabh.Mishra@Sun.COM mutex_init(&bfe->bfe_rx_ring.r_lock, NULL, MUTEX_DRIVER, NULL); 27989865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_lockp = &bfe->bfe_rx_ring.r_lock; 27999865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) + 28009865SSaurabh.Mishra@Sun.COM VLAN_TAGSZ + ETHERFCSL + RX_HEAD_ROOM; 28019865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_ndesc = RX_NUM_DESC; 28029865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_bfe = bfe; 28039865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_avail_desc = RX_NUM_DESC; 28049865SSaurabh.Mishra@Sun.COM 28059865SSaurabh.Mishra@Sun.COM /* Allocate TX Ring */ 28069865SSaurabh.Mishra@Sun.COM if (bfe_ring_desc_alloc(bfe, &bfe->bfe_tx_ring, 28079865SSaurabh.Mishra@Sun.COM DDI_DMA_WRITE) != DDI_SUCCESS) 28089865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 28099865SSaurabh.Mishra@Sun.COM 28109865SSaurabh.Mishra@Sun.COM /* Allocate RX Ring */ 28119865SSaurabh.Mishra@Sun.COM if (bfe_ring_desc_alloc(bfe, &bfe->bfe_rx_ring, 28129865SSaurabh.Mishra@Sun.COM DDI_DMA_READ) != DDI_SUCCESS) { 28139865SSaurabh.Mishra@Sun.COM cmn_err(CE_NOTE, "RX ring allocation failed"); 28149865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(&bfe->bfe_tx_ring); 28159865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 28169865SSaurabh.Mishra@Sun.COM } 28179865SSaurabh.Mishra@Sun.COM 28189865SSaurabh.Mishra@Sun.COM bfe->bfe_tx_ring.r_flags = BFE_RING_ALLOCATED; 28199865SSaurabh.Mishra@Sun.COM bfe->bfe_rx_ring.r_flags = BFE_RING_ALLOCATED; 28209865SSaurabh.Mishra@Sun.COM 28219865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 28229865SSaurabh.Mishra@Sun.COM } 28239865SSaurabh.Mishra@Sun.COM 28249865SSaurabh.Mishra@Sun.COM static int 28259865SSaurabh.Mishra@Sun.COM bfe_resume(dev_info_t *dip) 28269865SSaurabh.Mishra@Sun.COM { 28279865SSaurabh.Mishra@Sun.COM bfe_t *bfe; 28289865SSaurabh.Mishra@Sun.COM int err = DDI_SUCCESS; 28299865SSaurabh.Mishra@Sun.COM 28309865SSaurabh.Mishra@Sun.COM if ((bfe = ddi_get_driver_private(dip)) == NULL) { 28319865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Unexpected error (no driver private data)" 28329865SSaurabh.Mishra@Sun.COM " while resume"); 28339865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 28349865SSaurabh.Mishra@Sun.COM } 28359865SSaurabh.Mishra@Sun.COM 28369865SSaurabh.Mishra@Sun.COM /* 28379865SSaurabh.Mishra@Sun.COM * Grab all the locks first. 28389865SSaurabh.Mishra@Sun.COM */ 28399865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 28409865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_RESUME; 28419865SSaurabh.Mishra@Sun.COM 28429865SSaurabh.Mishra@Sun.COM bfe_init_vars(bfe); 28439865SSaurabh.Mishra@Sun.COM /* PHY will also start running */ 28449865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe); 28459865SSaurabh.Mishra@Sun.COM if (bfe_chip_start(bfe) == DDI_FAILURE) { 28469865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not resume chip"); 28479865SSaurabh.Mishra@Sun.COM err = DDI_FAILURE; 28489865SSaurabh.Mishra@Sun.COM } 284910591SSaurabh.Mishra@Sun.COM 28509865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 285110591SSaurabh.Mishra@Sun.COM 285210591SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) 285310591SSaurabh.Mishra@Sun.COM mac_tx_update(bfe->bfe_machdl); 285410591SSaurabh.Mishra@Sun.COM 28559865SSaurabh.Mishra@Sun.COM return (err); 28569865SSaurabh.Mishra@Sun.COM } 28579865SSaurabh.Mishra@Sun.COM 28589865SSaurabh.Mishra@Sun.COM static int 28599865SSaurabh.Mishra@Sun.COM bfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 28609865SSaurabh.Mishra@Sun.COM { 28619865SSaurabh.Mishra@Sun.COM int unit; 28629865SSaurabh.Mishra@Sun.COM bfe_t *bfe; 28639865SSaurabh.Mishra@Sun.COM mac_register_t *macreg; 28649865SSaurabh.Mishra@Sun.COM int ret; 28659865SSaurabh.Mishra@Sun.COM 28669865SSaurabh.Mishra@Sun.COM switch (cmd) { 28679865SSaurabh.Mishra@Sun.COM case DDI_RESUME: 28689865SSaurabh.Mishra@Sun.COM return (bfe_resume(dip)); 28699865SSaurabh.Mishra@Sun.COM 28709865SSaurabh.Mishra@Sun.COM case DDI_ATTACH: 28719865SSaurabh.Mishra@Sun.COM break; 28729865SSaurabh.Mishra@Sun.COM 28739865SSaurabh.Mishra@Sun.COM default: 28749865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 28759865SSaurabh.Mishra@Sun.COM } 28769865SSaurabh.Mishra@Sun.COM 28779865SSaurabh.Mishra@Sun.COM 28789865SSaurabh.Mishra@Sun.COM unit = ddi_get_instance(dip); 28799865SSaurabh.Mishra@Sun.COM 28809865SSaurabh.Mishra@Sun.COM bfe = kmem_zalloc(sizeof (bfe_t), KM_SLEEP); 28819865SSaurabh.Mishra@Sun.COM bfe->bfe_dip = dip; 28829865SSaurabh.Mishra@Sun.COM bfe->bfe_unit = unit; 28839865SSaurabh.Mishra@Sun.COM 28849865SSaurabh.Mishra@Sun.COM if (pci_config_setup(dip, &bfe->bfe_conf_handle) != DDI_SUCCESS) { 28859865SSaurabh.Mishra@Sun.COM bfe_error(dip, "pci_config_setup failed"); 28869865SSaurabh.Mishra@Sun.COM goto fail0; 28879865SSaurabh.Mishra@Sun.COM } 28889865SSaurabh.Mishra@Sun.COM 28899865SSaurabh.Mishra@Sun.COM /* 28909865SSaurabh.Mishra@Sun.COM * Enable IO space, Bus Master and Memory Space accessess. 28919865SSaurabh.Mishra@Sun.COM */ 28929865SSaurabh.Mishra@Sun.COM ret = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_COMM); 28939865SSaurabh.Mishra@Sun.COM pci_config_put16(bfe->bfe_conf_handle, PCI_CONF_COMM, 28949865SSaurabh.Mishra@Sun.COM PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | ret); 28959865SSaurabh.Mishra@Sun.COM 28969865SSaurabh.Mishra@Sun.COM ddi_set_driver_private(dip, bfe); 28979865SSaurabh.Mishra@Sun.COM 28989865SSaurabh.Mishra@Sun.COM /* Identify hardware */ 28999865SSaurabh.Mishra@Sun.COM if (bfe_identify_hardware(bfe) == BFE_FAILURE) { 29009865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not identify device"); 29019865SSaurabh.Mishra@Sun.COM goto fail1; 29029865SSaurabh.Mishra@Sun.COM } 29039865SSaurabh.Mishra@Sun.COM 29049865SSaurabh.Mishra@Sun.COM if (bfe_regs_map(bfe) != DDI_SUCCESS) { 29059865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not map device registers"); 29069865SSaurabh.Mishra@Sun.COM goto fail1; 29079865SSaurabh.Mishra@Sun.COM } 29089865SSaurabh.Mishra@Sun.COM 29099865SSaurabh.Mishra@Sun.COM (void) bfe_get_chip_config(bfe); 29109865SSaurabh.Mishra@Sun.COM 29119865SSaurabh.Mishra@Sun.COM /* 29129865SSaurabh.Mishra@Sun.COM * Register with MAC layer 29139865SSaurabh.Mishra@Sun.COM */ 29149865SSaurabh.Mishra@Sun.COM if ((macreg = mac_alloc(MAC_VERSION)) == NULL) { 29159865SSaurabh.Mishra@Sun.COM bfe_error(dip, "mac_alloc() failed"); 29169865SSaurabh.Mishra@Sun.COM goto fail2; 29179865SSaurabh.Mishra@Sun.COM } 29189865SSaurabh.Mishra@Sun.COM 29199865SSaurabh.Mishra@Sun.COM macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 29209865SSaurabh.Mishra@Sun.COM macreg->m_driver = bfe; 29219865SSaurabh.Mishra@Sun.COM macreg->m_dip = dip; 29229865SSaurabh.Mishra@Sun.COM macreg->m_instance = unit; 29239865SSaurabh.Mishra@Sun.COM macreg->m_src_addr = bfe->bfe_ether_addr; 29249865SSaurabh.Mishra@Sun.COM macreg->m_callbacks = &bfe_mac_callbacks; 29259865SSaurabh.Mishra@Sun.COM macreg->m_min_sdu = 0; 29269865SSaurabh.Mishra@Sun.COM macreg->m_max_sdu = ETHERMTU; 29279865SSaurabh.Mishra@Sun.COM macreg->m_margin = VLAN_TAGSZ; 29289865SSaurabh.Mishra@Sun.COM 29299865SSaurabh.Mishra@Sun.COM if ((ret = mac_register(macreg, &bfe->bfe_machdl)) != 0) { 29309865SSaurabh.Mishra@Sun.COM bfe_error(dip, "mac_register() failed with %d error", ret); 29319865SSaurabh.Mishra@Sun.COM mac_free(macreg); 29329865SSaurabh.Mishra@Sun.COM goto fail2; 29339865SSaurabh.Mishra@Sun.COM } 29349865SSaurabh.Mishra@Sun.COM 29359865SSaurabh.Mishra@Sun.COM mac_free(macreg); 29369865SSaurabh.Mishra@Sun.COM 29379865SSaurabh.Mishra@Sun.COM rw_init(&bfe->bfe_rwlock, NULL, RW_DRIVER, 29389865SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(bfe->bfe_intrpri)); 29399865SSaurabh.Mishra@Sun.COM 29409865SSaurabh.Mishra@Sun.COM if (bfe_add_intr(bfe) != DDI_SUCCESS) { 29419865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not add interrupt"); 29429865SSaurabh.Mishra@Sun.COM goto fail3; 29439865SSaurabh.Mishra@Sun.COM } 29449865SSaurabh.Mishra@Sun.COM 29459865SSaurabh.Mishra@Sun.COM if (bfe_rings_alloc(bfe) != DDI_SUCCESS) { 29469865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not allocate TX/RX Ring"); 29479865SSaurabh.Mishra@Sun.COM goto fail4; 29489865SSaurabh.Mishra@Sun.COM } 29499865SSaurabh.Mishra@Sun.COM 29509865SSaurabh.Mishra@Sun.COM /* Init and then reset the chip */ 29519865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_action = 0; 29529865SSaurabh.Mishra@Sun.COM bfe_init_vars(bfe); 29539865SSaurabh.Mishra@Sun.COM 29549865SSaurabh.Mishra@Sun.COM /* PHY will also start running */ 29559865SSaurabh.Mishra@Sun.COM bfe_chip_reset(bfe); 29569865SSaurabh.Mishra@Sun.COM 29579865SSaurabh.Mishra@Sun.COM /* 29589865SSaurabh.Mishra@Sun.COM * Even though we enable the interrupts here but chip's interrupt 29599865SSaurabh.Mishra@Sun.COM * is not enabled yet. It will be enabled once we plumb the interface. 29609865SSaurabh.Mishra@Sun.COM */ 29619865SSaurabh.Mishra@Sun.COM if (ddi_intr_enable(bfe->bfe_intrhdl) != DDI_SUCCESS) { 29629865SSaurabh.Mishra@Sun.COM bfe_error(dip, "Could not enable interrupt"); 29639865SSaurabh.Mishra@Sun.COM goto fail4; 29649865SSaurabh.Mishra@Sun.COM } 29659865SSaurabh.Mishra@Sun.COM 29669865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 29679865SSaurabh.Mishra@Sun.COM 29689865SSaurabh.Mishra@Sun.COM fail4: 29699865SSaurabh.Mishra@Sun.COM bfe_remove_intr(bfe); 29709865SSaurabh.Mishra@Sun.COM fail3: 297111387SSurya.Prakki@Sun.COM (void) mac_unregister(bfe->bfe_machdl); 29729865SSaurabh.Mishra@Sun.COM fail2: 29739865SSaurabh.Mishra@Sun.COM bfe_unmap_regs(bfe); 29749865SSaurabh.Mishra@Sun.COM fail1: 29759865SSaurabh.Mishra@Sun.COM pci_config_teardown(&bfe->bfe_conf_handle); 29769865SSaurabh.Mishra@Sun.COM fail0: 29779865SSaurabh.Mishra@Sun.COM kmem_free(bfe, sizeof (bfe_t)); 29789865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 29799865SSaurabh.Mishra@Sun.COM } 29809865SSaurabh.Mishra@Sun.COM 29819865SSaurabh.Mishra@Sun.COM static int 29829865SSaurabh.Mishra@Sun.COM bfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 29839865SSaurabh.Mishra@Sun.COM { 29849865SSaurabh.Mishra@Sun.COM bfe_t *bfe; 29859865SSaurabh.Mishra@Sun.COM 29869865SSaurabh.Mishra@Sun.COM bfe = ddi_get_driver_private(devinfo); 29879865SSaurabh.Mishra@Sun.COM 29889865SSaurabh.Mishra@Sun.COM switch (cmd) { 29899865SSaurabh.Mishra@Sun.COM case DDI_DETACH: 29909865SSaurabh.Mishra@Sun.COM /* 29919865SSaurabh.Mishra@Sun.COM * We need to stop the timer before grabbing locks otherwise 29929865SSaurabh.Mishra@Sun.COM * we can land-up in deadlock with untimeout. 29939865SSaurabh.Mishra@Sun.COM */ 29949865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe); 29959865SSaurabh.Mishra@Sun.COM 29969865SSaurabh.Mishra@Sun.COM /* 29979865SSaurabh.Mishra@Sun.COM * First unregister with MAC layer before stopping DMA 29989865SSaurabh.Mishra@Sun.COM * engine. 29999865SSaurabh.Mishra@Sun.COM */ 30009865SSaurabh.Mishra@Sun.COM if (mac_unregister(bfe->bfe_machdl) != DDI_SUCCESS) 30019865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 30029865SSaurabh.Mishra@Sun.COM 30039865SSaurabh.Mishra@Sun.COM bfe->bfe_machdl = NULL; 30049865SSaurabh.Mishra@Sun.COM 30059865SSaurabh.Mishra@Sun.COM /* 30069865SSaurabh.Mishra@Sun.COM * Quiesce the chip first. 30079865SSaurabh.Mishra@Sun.COM */ 30089865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 30099865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 30109865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 30119865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 30129865SSaurabh.Mishra@Sun.COM 30139865SSaurabh.Mishra@Sun.COM (void) ddi_intr_disable(bfe->bfe_intrhdl); 30149865SSaurabh.Mishra@Sun.COM 30159865SSaurabh.Mishra@Sun.COM /* Make sure timer is gone. */ 30169865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe); 30179865SSaurabh.Mishra@Sun.COM 30189865SSaurabh.Mishra@Sun.COM /* 30199865SSaurabh.Mishra@Sun.COM * Free the DMA resources for buffer and then descriptors 30209865SSaurabh.Mishra@Sun.COM */ 30219865SSaurabh.Mishra@Sun.COM if (bfe->bfe_tx_ring.r_flags == BFE_RING_ALLOCATED) { 30229865SSaurabh.Mishra@Sun.COM /* TX */ 30239865SSaurabh.Mishra@Sun.COM bfe_buffer_free(&bfe->bfe_tx_ring); 30249865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(&bfe->bfe_tx_ring); 30259865SSaurabh.Mishra@Sun.COM } 30269865SSaurabh.Mishra@Sun.COM 30279865SSaurabh.Mishra@Sun.COM if (bfe->bfe_rx_ring.r_flags == BFE_RING_ALLOCATED) { 30289865SSaurabh.Mishra@Sun.COM /* RX */ 30299865SSaurabh.Mishra@Sun.COM bfe_buffer_free(&bfe->bfe_rx_ring); 30309865SSaurabh.Mishra@Sun.COM bfe_ring_desc_free(&bfe->bfe_rx_ring); 30319865SSaurabh.Mishra@Sun.COM } 30329865SSaurabh.Mishra@Sun.COM 30339865SSaurabh.Mishra@Sun.COM bfe_remove_intr(bfe); 30349865SSaurabh.Mishra@Sun.COM bfe_unmap_regs(bfe); 30359865SSaurabh.Mishra@Sun.COM pci_config_teardown(&bfe->bfe_conf_handle); 30369865SSaurabh.Mishra@Sun.COM 30379865SSaurabh.Mishra@Sun.COM mutex_destroy(&bfe->bfe_tx_ring.r_lock); 30389865SSaurabh.Mishra@Sun.COM mutex_destroy(&bfe->bfe_rx_ring.r_lock); 30399865SSaurabh.Mishra@Sun.COM rw_destroy(&bfe->bfe_rwlock); 30409865SSaurabh.Mishra@Sun.COM 30419865SSaurabh.Mishra@Sun.COM kmem_free(bfe, sizeof (bfe_t)); 30429865SSaurabh.Mishra@Sun.COM 30439865SSaurabh.Mishra@Sun.COM ddi_set_driver_private(devinfo, NULL); 30449865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 30459865SSaurabh.Mishra@Sun.COM 30469865SSaurabh.Mishra@Sun.COM case DDI_SUSPEND: 30479865SSaurabh.Mishra@Sun.COM /* 30489865SSaurabh.Mishra@Sun.COM * We need to stop the timer before grabbing locks otherwise 30499865SSaurabh.Mishra@Sun.COM * we can land-up in deadlock with untimeout. 30509865SSaurabh.Mishra@Sun.COM */ 30519865SSaurabh.Mishra@Sun.COM bfe_stop_timer(bfe); 30529865SSaurabh.Mishra@Sun.COM 30539865SSaurabh.Mishra@Sun.COM /* 30549865SSaurabh.Mishra@Sun.COM * Grab all the locks first. 30559865SSaurabh.Mishra@Sun.COM */ 30569865SSaurabh.Mishra@Sun.COM bfe_grab_locks(bfe); 30579865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 30589865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 30599865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_SUSPENDED; 30609865SSaurabh.Mishra@Sun.COM bfe_release_locks(bfe); 30619865SSaurabh.Mishra@Sun.COM 30629865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 30639865SSaurabh.Mishra@Sun.COM 30649865SSaurabh.Mishra@Sun.COM default: 30659865SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 30669865SSaurabh.Mishra@Sun.COM } 30679865SSaurabh.Mishra@Sun.COM } 30689865SSaurabh.Mishra@Sun.COM 30699865SSaurabh.Mishra@Sun.COM /* 30709865SSaurabh.Mishra@Sun.COM * Quiesce the card for fast reboot 30719865SSaurabh.Mishra@Sun.COM */ 30729865SSaurabh.Mishra@Sun.COM int 30739865SSaurabh.Mishra@Sun.COM bfe_quiesce(dev_info_t *dev_info) 30749865SSaurabh.Mishra@Sun.COM { 30759865SSaurabh.Mishra@Sun.COM bfe_t *bfe; 30769865SSaurabh.Mishra@Sun.COM 30779865SSaurabh.Mishra@Sun.COM bfe = ddi_get_driver_private(dev_info); 30789865SSaurabh.Mishra@Sun.COM 30799865SSaurabh.Mishra@Sun.COM bfe_chip_halt(bfe); 30809865SSaurabh.Mishra@Sun.COM bfe_stop_phy(bfe); 30819865SSaurabh.Mishra@Sun.COM bfe->bfe_chip_state = BFE_CHIP_QUIESCED; 30829865SSaurabh.Mishra@Sun.COM 30839865SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 30849865SSaurabh.Mishra@Sun.COM } 30859865SSaurabh.Mishra@Sun.COM 30869865SSaurabh.Mishra@Sun.COM static struct cb_ops bfe_cb_ops = { 30879865SSaurabh.Mishra@Sun.COM nulldev, /* cb_open */ 30889865SSaurabh.Mishra@Sun.COM nulldev, /* cb_close */ 30899865SSaurabh.Mishra@Sun.COM nodev, /* cb_strategy */ 30909865SSaurabh.Mishra@Sun.COM nodev, /* cb_print */ 30919865SSaurabh.Mishra@Sun.COM nodev, /* cb_dump */ 30929865SSaurabh.Mishra@Sun.COM nodev, /* cb_read */ 30939865SSaurabh.Mishra@Sun.COM nodev, /* cb_write */ 30949865SSaurabh.Mishra@Sun.COM nodev, /* cb_ioctl */ 30959865SSaurabh.Mishra@Sun.COM nodev, /* cb_devmap */ 30969865SSaurabh.Mishra@Sun.COM nodev, /* cb_mmap */ 30979865SSaurabh.Mishra@Sun.COM nodev, /* cb_segmap */ 30989865SSaurabh.Mishra@Sun.COM nochpoll, /* cb_chpoll */ 30999865SSaurabh.Mishra@Sun.COM ddi_prop_op, /* cb_prop_op */ 31009865SSaurabh.Mishra@Sun.COM NULL, /* cb_stream */ 31019865SSaurabh.Mishra@Sun.COM D_MP | D_HOTPLUG, /* cb_flag */ 31029865SSaurabh.Mishra@Sun.COM CB_REV, /* cb_rev */ 31039865SSaurabh.Mishra@Sun.COM nodev, /* cb_aread */ 31049865SSaurabh.Mishra@Sun.COM nodev /* cb_awrite */ 31059865SSaurabh.Mishra@Sun.COM }; 31069865SSaurabh.Mishra@Sun.COM 31079865SSaurabh.Mishra@Sun.COM static struct dev_ops bfe_dev_ops = { 31089865SSaurabh.Mishra@Sun.COM DEVO_REV, /* devo_rev */ 31099865SSaurabh.Mishra@Sun.COM 0, /* devo_refcnt */ 31109865SSaurabh.Mishra@Sun.COM NULL, /* devo_getinfo */ 31119865SSaurabh.Mishra@Sun.COM nulldev, /* devo_identify */ 31129865SSaurabh.Mishra@Sun.COM nulldev, /* devo_probe */ 31139865SSaurabh.Mishra@Sun.COM bfe_attach, /* devo_attach */ 31149865SSaurabh.Mishra@Sun.COM bfe_detach, /* devo_detach */ 31159865SSaurabh.Mishra@Sun.COM nodev, /* devo_reset */ 31169865SSaurabh.Mishra@Sun.COM &bfe_cb_ops, /* devo_cb_ops */ 31179865SSaurabh.Mishra@Sun.COM NULL, /* devo_bus_ops */ 31189865SSaurabh.Mishra@Sun.COM ddi_power, /* devo_power */ 31199865SSaurabh.Mishra@Sun.COM bfe_quiesce /* devo_quiesce */ 31209865SSaurabh.Mishra@Sun.COM }; 31219865SSaurabh.Mishra@Sun.COM 31229865SSaurabh.Mishra@Sun.COM static struct modldrv bfe_modldrv = { 31239865SSaurabh.Mishra@Sun.COM &mod_driverops, 31249865SSaurabh.Mishra@Sun.COM bfe_ident, 31259865SSaurabh.Mishra@Sun.COM &bfe_dev_ops 31269865SSaurabh.Mishra@Sun.COM }; 31279865SSaurabh.Mishra@Sun.COM 31289865SSaurabh.Mishra@Sun.COM static struct modlinkage modlinkage = { 31299865SSaurabh.Mishra@Sun.COM MODREV_1, (void *)&bfe_modldrv, NULL 31309865SSaurabh.Mishra@Sun.COM }; 31319865SSaurabh.Mishra@Sun.COM 31329865SSaurabh.Mishra@Sun.COM int 31339865SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop) 31349865SSaurabh.Mishra@Sun.COM { 31359865SSaurabh.Mishra@Sun.COM return (mod_info(&modlinkage, modinfop)); 31369865SSaurabh.Mishra@Sun.COM } 31379865SSaurabh.Mishra@Sun.COM 31389865SSaurabh.Mishra@Sun.COM int 31399865SSaurabh.Mishra@Sun.COM _init(void) 31409865SSaurabh.Mishra@Sun.COM { 31419865SSaurabh.Mishra@Sun.COM int status; 31429865SSaurabh.Mishra@Sun.COM 31439865SSaurabh.Mishra@Sun.COM mac_init_ops(&bfe_dev_ops, MODULE_NAME); 31449865SSaurabh.Mishra@Sun.COM status = mod_install(&modlinkage); 31459865SSaurabh.Mishra@Sun.COM if (status == DDI_FAILURE) 31469865SSaurabh.Mishra@Sun.COM mac_fini_ops(&bfe_dev_ops); 31479865SSaurabh.Mishra@Sun.COM return (status); 31489865SSaurabh.Mishra@Sun.COM } 31499865SSaurabh.Mishra@Sun.COM 31509865SSaurabh.Mishra@Sun.COM int 31519865SSaurabh.Mishra@Sun.COM _fini(void) 31529865SSaurabh.Mishra@Sun.COM { 31539865SSaurabh.Mishra@Sun.COM int status; 31549865SSaurabh.Mishra@Sun.COM 31559865SSaurabh.Mishra@Sun.COM status = mod_remove(&modlinkage); 31569865SSaurabh.Mishra@Sun.COM if (status == 0) { 31579865SSaurabh.Mishra@Sun.COM mac_fini_ops(&bfe_dev_ops); 31589865SSaurabh.Mishra@Sun.COM } 31599865SSaurabh.Mishra@Sun.COM return (status); 31609865SSaurabh.Mishra@Sun.COM } 3161