110393SSaurabh.Mishra@Sun.COM /* 210393SSaurabh.Mishra@Sun.COM * CDDL HEADER START 310393SSaurabh.Mishra@Sun.COM * 410393SSaurabh.Mishra@Sun.COM * The contents of this file are subject to the terms of the 510393SSaurabh.Mishra@Sun.COM * Common Development and Distribution License (the "License"). 610393SSaurabh.Mishra@Sun.COM * You may not use this file except in compliance with the License. 710393SSaurabh.Mishra@Sun.COM * 810393SSaurabh.Mishra@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910393SSaurabh.Mishra@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010393SSaurabh.Mishra@Sun.COM * See the License for the specific language governing permissions 1110393SSaurabh.Mishra@Sun.COM * and limitations under the License. 1210393SSaurabh.Mishra@Sun.COM * 1310393SSaurabh.Mishra@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410393SSaurabh.Mishra@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510393SSaurabh.Mishra@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610393SSaurabh.Mishra@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710393SSaurabh.Mishra@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810393SSaurabh.Mishra@Sun.COM * 1910393SSaurabh.Mishra@Sun.COM * CDDL HEADER END 2010393SSaurabh.Mishra@Sun.COM */ 2110393SSaurabh.Mishra@Sun.COM 2210393SSaurabh.Mishra@Sun.COM /* 2310393SSaurabh.Mishra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2410393SSaurabh.Mishra@Sun.COM * Use is subject to license terms. 2510393SSaurabh.Mishra@Sun.COM */ 2610393SSaurabh.Mishra@Sun.COM 2710393SSaurabh.Mishra@Sun.COM #include <sys/types.h> 2810393SSaurabh.Mishra@Sun.COM #include <sys/stream.h> 2910393SSaurabh.Mishra@Sun.COM #include <sys/strsun.h> 3010393SSaurabh.Mishra@Sun.COM #include <sys/stat.h> 3110393SSaurabh.Mishra@Sun.COM #include <sys/modctl.h> 3210393SSaurabh.Mishra@Sun.COM #include <sys/kstat.h> 3310393SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h> 3410393SSaurabh.Mishra@Sun.COM #include <sys/devops.h> 3510393SSaurabh.Mishra@Sun.COM #include <sys/debug.h> 3610393SSaurabh.Mishra@Sun.COM #include <sys/conf.h> 3710393SSaurabh.Mishra@Sun.COM #include <sys/mii.h> 3810393SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h> 3910393SSaurabh.Mishra@Sun.COM #include <sys/mac.h> 4010393SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h> 4110393SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h> 4210393SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h> 4310393SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h> 4410393SSaurabh.Mishra@Sun.COM #include <sys/ddi.h> 4510393SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h> 4610393SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h> 4710393SSaurabh.Mishra@Sun.COM #include <sys/note.h> 4810393SSaurabh.Mishra@Sun.COM #include <sys/vlan.h> 4910393SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h> 5010393SSaurabh.Mishra@Sun.COM #include <sys/crc32.h> 5110393SSaurabh.Mishra@Sun.COM #include <sys/sdt.h> 5210393SSaurabh.Mishra@Sun.COM #include <sys/pci.h> 5310393SSaurabh.Mishra@Sun.COM #include <sys/pci_cap.h> 5410393SSaurabh.Mishra@Sun.COM 5510393SSaurabh.Mishra@Sun.COM #include "atge.h" 5610393SSaurabh.Mishra@Sun.COM #include "atge_cmn_reg.h" 5710393SSaurabh.Mishra@Sun.COM #include "atge_l1e_reg.h" 58*11353SSaurabh.Mishra@Sun.COM #include "atge_l1_reg.h" 5910393SSaurabh.Mishra@Sun.COM 6010393SSaurabh.Mishra@Sun.COM 6110393SSaurabh.Mishra@Sun.COM /* 6210393SSaurabh.Mishra@Sun.COM * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E. 63*11353SSaurabh.Mishra@Sun.COM * This driver is for L1E/L1 but can be extended to support other chips. 64*11353SSaurabh.Mishra@Sun.COM * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit 65*11353SSaurabh.Mishra@Sun.COM * flavors only. 6610393SSaurabh.Mishra@Sun.COM * 6710393SSaurabh.Mishra@Sun.COM * Atheros/Attansic Ethernet controllers have descriptor based TX and RX 6810393SSaurabh.Mishra@Sun.COM * with an exception of L1E. L1E's RX side is not descriptor based ring. 6910393SSaurabh.Mishra@Sun.COM * The L1E's RX uses pages (not to be confused with MMU pages) for 7010393SSaurabh.Mishra@Sun.COM * receiving pkts. The header has four fields : 7110393SSaurabh.Mishra@Sun.COM * 7210393SSaurabh.Mishra@Sun.COM * uint32_t seqno; Sequence number of the frame. 7310393SSaurabh.Mishra@Sun.COM * uint32_t length; Length of the frame. 7410393SSaurabh.Mishra@Sun.COM * uint32_t flags; Flags 7510393SSaurabh.Mishra@Sun.COM * uint32_t vtag; We don't use hardware VTAG. 7610393SSaurabh.Mishra@Sun.COM * 7710393SSaurabh.Mishra@Sun.COM * We use only one queue for RX (each queue can have two pages) and each 7810393SSaurabh.Mishra@Sun.COM * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't 7910393SSaurabh.Mishra@Sun.COM * use zero-copy RX because we are limited to two pages and each page 8010393SSaurabh.Mishra@Sun.COM * accomodates large number of pkts. 8110393SSaurabh.Mishra@Sun.COM * 8210393SSaurabh.Mishra@Sun.COM * The TX side on all three chips is descriptor based ring; and all the 8310393SSaurabh.Mishra@Sun.COM * more reason to have one driver for these chips. 8410393SSaurabh.Mishra@Sun.COM * 8510393SSaurabh.Mishra@Sun.COM * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks 8610393SSaurabh.Mishra@Sun.COM * should be held if the operation has impact on the driver instance. 8710393SSaurabh.Mishra@Sun.COM * 8810393SSaurabh.Mishra@Sun.COM * All the three chips have hash-based multicast filter. 8910393SSaurabh.Mishra@Sun.COM * 9010393SSaurabh.Mishra@Sun.COM * We use CMB (Coalescing Message Block) for RX but not for TX as there 9110393SSaurabh.Mishra@Sun.COM * are some issues with TX. RX CMB is used to get the last descriptor 9210393SSaurabh.Mishra@Sun.COM * posted by the chip. Each CMB is for a RX page (one queue can have two 9310393SSaurabh.Mishra@Sun.COM * pages) and are uint32_t (4 bytes) long. 9410393SSaurabh.Mishra@Sun.COM * 9510393SSaurabh.Mishra@Sun.COM * The descriptor table should have 32-bit physical address limit due to 9610393SSaurabh.Mishra@Sun.COM * the limitation of having same high address for TX/RX/SMB/CMB. The 9710393SSaurabh.Mishra@Sun.COM * TX/RX buffers can be 64-bit. 9810393SSaurabh.Mishra@Sun.COM * 9910393SSaurabh.Mishra@Sun.COM * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers 10010393SSaurabh.Mishra@Sun.COM * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have 10110393SSaurabh.Mishra@Sun.COM * kept sgl as 1 so that we get contingous pages from root complex. 102*11353SSaurabh.Mishra@Sun.COM * 103*11353SSaurabh.Mishra@Sun.COM * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are 104*11353SSaurabh.Mishra@Sun.COM * common with L1E chip (0x1026). 10510393SSaurabh.Mishra@Sun.COM */ 10610393SSaurabh.Mishra@Sun.COM 10710393SSaurabh.Mishra@Sun.COM /* 10810393SSaurabh.Mishra@Sun.COM * Function Prototypes for debugging. 10910393SSaurabh.Mishra@Sun.COM */ 11010393SSaurabh.Mishra@Sun.COM void atge_error(dev_info_t *, char *, ...); 11110393SSaurabh.Mishra@Sun.COM void atge_debug_func(char *, ...); 11210393SSaurabh.Mishra@Sun.COM 11310393SSaurabh.Mishra@Sun.COM /* 11410393SSaurabh.Mishra@Sun.COM * Function Prototypes for driver operations. 11510393SSaurabh.Mishra@Sun.COM */ 11610393SSaurabh.Mishra@Sun.COM static int atge_resume(dev_info_t *); 11710393SSaurabh.Mishra@Sun.COM static int atge_add_intr(atge_t *); 11810393SSaurabh.Mishra@Sun.COM static int atge_alloc_dma(atge_t *); 11910393SSaurabh.Mishra@Sun.COM static void atge_remove_intr(atge_t *); 12010393SSaurabh.Mishra@Sun.COM static void atge_free_dma(atge_t *); 12110393SSaurabh.Mishra@Sun.COM static void atge_device_reset(atge_t *); 12210393SSaurabh.Mishra@Sun.COM static void atge_device_init(atge_t *); 12310393SSaurabh.Mishra@Sun.COM static void atge_device_start(atge_t *); 12410393SSaurabh.Mishra@Sun.COM static void atge_disable_intrs(atge_t *); 12510393SSaurabh.Mishra@Sun.COM atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int); 12610393SSaurabh.Mishra@Sun.COM void atge_free_a_dma_blk(atge_dma_t *); 12710393SSaurabh.Mishra@Sun.COM static void atge_rxfilter(atge_t *); 12810393SSaurabh.Mishra@Sun.COM static void atge_device_reset_l1_l1e(atge_t *); 12910393SSaurabh.Mishra@Sun.COM void atge_program_ether(atge_t *atgep); 13010393SSaurabh.Mishra@Sun.COM void atge_device_restart(atge_t *); 131*11353SSaurabh.Mishra@Sun.COM void atge_device_stop(atge_t *); 13210393SSaurabh.Mishra@Sun.COM static int atge_send_a_packet(atge_t *, mblk_t *); 13310393SSaurabh.Mishra@Sun.COM static uint32_t atge_ether_crc(const uint8_t *, int); 13410393SSaurabh.Mishra@Sun.COM 13510393SSaurabh.Mishra@Sun.COM 13610393SSaurabh.Mishra@Sun.COM /* 137*11353SSaurabh.Mishra@Sun.COM * L1E/L2E specific functions. 13810393SSaurabh.Mishra@Sun.COM */ 13910393SSaurabh.Mishra@Sun.COM void atge_l1e_device_reset(atge_t *); 14010393SSaurabh.Mishra@Sun.COM void atge_l1e_stop_mac(atge_t *); 14110393SSaurabh.Mishra@Sun.COM int atge_l1e_alloc_dma(atge_t *); 14210393SSaurabh.Mishra@Sun.COM void atge_l1e_free_dma(atge_t *); 14310393SSaurabh.Mishra@Sun.COM void atge_l1e_init_tx_ring(atge_t *); 14410393SSaurabh.Mishra@Sun.COM void atge_l1e_init_rx_pages(atge_t *); 14510393SSaurabh.Mishra@Sun.COM void atge_l1e_program_dma(atge_t *); 146*11353SSaurabh.Mishra@Sun.COM void atge_l1e_send_packet(atge_ring_t *); 14710393SSaurabh.Mishra@Sun.COM mblk_t *atge_l1e_receive(atge_t *); 148*11353SSaurabh.Mishra@Sun.COM uint_t atge_l1e_interrupt(caddr_t, caddr_t); 14910393SSaurabh.Mishra@Sun.COM void atge_l1e_gather_stats(atge_t *); 15010393SSaurabh.Mishra@Sun.COM void atge_l1e_clear_stats(atge_t *); 15110393SSaurabh.Mishra@Sun.COM 15210393SSaurabh.Mishra@Sun.COM /* 153*11353SSaurabh.Mishra@Sun.COM * L1 specific functions. 154*11353SSaurabh.Mishra@Sun.COM */ 155*11353SSaurabh.Mishra@Sun.COM int atge_l1_alloc_dma(atge_t *); 156*11353SSaurabh.Mishra@Sun.COM void atge_l1_init_tx_ring(atge_t *); 157*11353SSaurabh.Mishra@Sun.COM void atge_l1_init_rx_ring(atge_t *); 158*11353SSaurabh.Mishra@Sun.COM void atge_l1_init_rr_ring(atge_t *); 159*11353SSaurabh.Mishra@Sun.COM void atge_l1_init_cmb(atge_t *); 160*11353SSaurabh.Mishra@Sun.COM void atge_l1_init_smb(atge_t *); 161*11353SSaurabh.Mishra@Sun.COM void atge_l1_program_dma(atge_t *); 162*11353SSaurabh.Mishra@Sun.COM void atge_l1_stop_tx_mac(atge_t *); 163*11353SSaurabh.Mishra@Sun.COM void atge_l1_stop_rx_mac(atge_t *); 164*11353SSaurabh.Mishra@Sun.COM uint_t atge_l1_interrupt(caddr_t, caddr_t); 165*11353SSaurabh.Mishra@Sun.COM void atge_l1_send_packet(atge_ring_t *); 166*11353SSaurabh.Mishra@Sun.COM 167*11353SSaurabh.Mishra@Sun.COM 168*11353SSaurabh.Mishra@Sun.COM /* 16910393SSaurabh.Mishra@Sun.COM * Function prototyps for MII operations. 17010393SSaurabh.Mishra@Sun.COM */ 17110393SSaurabh.Mishra@Sun.COM uint16_t atge_mii_read(void *, uint8_t, uint8_t); 17210393SSaurabh.Mishra@Sun.COM void atge_mii_write(void *, uint8_t, uint8_t, uint16_t); 17310393SSaurabh.Mishra@Sun.COM void atge_l1e_mii_reset(void *); 174*11353SSaurabh.Mishra@Sun.COM void atge_l1_mii_reset(void *); 17510393SSaurabh.Mishra@Sun.COM static void atge_mii_notify(void *, link_state_t); 176*11353SSaurabh.Mishra@Sun.COM void atge_tx_reclaim(atge_t *atgep, int cons); 177*11353SSaurabh.Mishra@Sun.COM 178*11353SSaurabh.Mishra@Sun.COM /* 179*11353SSaurabh.Mishra@Sun.COM * L1E/L2E chip. 180*11353SSaurabh.Mishra@Sun.COM */ 18110393SSaurabh.Mishra@Sun.COM static mii_ops_t atge_l1e_mii_ops = { 18210393SSaurabh.Mishra@Sun.COM MII_OPS_VERSION, 18310393SSaurabh.Mishra@Sun.COM atge_mii_read, 18410393SSaurabh.Mishra@Sun.COM atge_mii_write, 18510393SSaurabh.Mishra@Sun.COM atge_mii_notify, 18610393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset 18710393SSaurabh.Mishra@Sun.COM }; 18810393SSaurabh.Mishra@Sun.COM 18910393SSaurabh.Mishra@Sun.COM /* 190*11353SSaurabh.Mishra@Sun.COM * L1 chip. 191*11353SSaurabh.Mishra@Sun.COM */ 192*11353SSaurabh.Mishra@Sun.COM static mii_ops_t atge_l1_mii_ops = { 193*11353SSaurabh.Mishra@Sun.COM MII_OPS_VERSION, 194*11353SSaurabh.Mishra@Sun.COM atge_mii_read, 195*11353SSaurabh.Mishra@Sun.COM atge_mii_write, 196*11353SSaurabh.Mishra@Sun.COM atge_mii_notify, 197*11353SSaurabh.Mishra@Sun.COM atge_l1_mii_reset 198*11353SSaurabh.Mishra@Sun.COM }; 199*11353SSaurabh.Mishra@Sun.COM 200*11353SSaurabh.Mishra@Sun.COM /* 20110393SSaurabh.Mishra@Sun.COM * Function Prototypes for MAC callbacks. 20210393SSaurabh.Mishra@Sun.COM */ 20310393SSaurabh.Mishra@Sun.COM static int atge_m_stat(void *, uint_t, uint64_t *); 20410393SSaurabh.Mishra@Sun.COM static int atge_m_start(void *); 20510393SSaurabh.Mishra@Sun.COM static void atge_m_stop(void *); 20610393SSaurabh.Mishra@Sun.COM static int atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 20710393SSaurabh.Mishra@Sun.COM uint_t, void *, uint_t *); 20810393SSaurabh.Mishra@Sun.COM static int atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 20910393SSaurabh.Mishra@Sun.COM const void *); 21010393SSaurabh.Mishra@Sun.COM static int atge_m_unicst(void *, const uint8_t *); 21110393SSaurabh.Mishra@Sun.COM static int atge_m_multicst(void *, boolean_t, const uint8_t *); 21210393SSaurabh.Mishra@Sun.COM static int atge_m_promisc(void *, boolean_t); 21310393SSaurabh.Mishra@Sun.COM static mblk_t *atge_m_tx(void *, mblk_t *); 21410393SSaurabh.Mishra@Sun.COM 21510393SSaurabh.Mishra@Sun.COM static mac_callbacks_t atge_m_callbacks = { 21610393SSaurabh.Mishra@Sun.COM MC_SETPROP | MC_GETPROP, 21710393SSaurabh.Mishra@Sun.COM atge_m_stat, 21810393SSaurabh.Mishra@Sun.COM atge_m_start, 21910393SSaurabh.Mishra@Sun.COM atge_m_stop, 22010393SSaurabh.Mishra@Sun.COM atge_m_promisc, 22110393SSaurabh.Mishra@Sun.COM atge_m_multicst, 22210393SSaurabh.Mishra@Sun.COM atge_m_unicst, 22310393SSaurabh.Mishra@Sun.COM atge_m_tx, 22410393SSaurabh.Mishra@Sun.COM NULL, /* mc_ioctl */ 22510393SSaurabh.Mishra@Sun.COM NULL, /* mc_getcapab */ 22610393SSaurabh.Mishra@Sun.COM NULL, /* mc_open */ 22710393SSaurabh.Mishra@Sun.COM NULL, /* mc_close */ 22810393SSaurabh.Mishra@Sun.COM atge_m_setprop, 22910393SSaurabh.Mishra@Sun.COM atge_m_getprop, 23010393SSaurabh.Mishra@Sun.COM }; 23110393SSaurabh.Mishra@Sun.COM 23210393SSaurabh.Mishra@Sun.COM /* 23310393SSaurabh.Mishra@Sun.COM * DMA Data access requirements. 23410393SSaurabh.Mishra@Sun.COM */ 23510393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_dev_attr = { 23610393SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0, 23710393SSaurabh.Mishra@Sun.COM DDI_STRUCTURE_LE_ACC, 23810393SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC 23910393SSaurabh.Mishra@Sun.COM }; 24010393SSaurabh.Mishra@Sun.COM 24110393SSaurabh.Mishra@Sun.COM /* 24210393SSaurabh.Mishra@Sun.COM * Buffers should be native endianness. 24310393SSaurabh.Mishra@Sun.COM */ 24410393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_buf_attr = { 24510393SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0, 24610393SSaurabh.Mishra@Sun.COM DDI_NEVERSWAP_ACC, /* native endianness */ 24710393SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC 24810393SSaurabh.Mishra@Sun.COM }; 24910393SSaurabh.Mishra@Sun.COM 25010393SSaurabh.Mishra@Sun.COM /* 251*11353SSaurabh.Mishra@Sun.COM * DMA device attributes. Buffer can be 64-bit. 25210393SSaurabh.Mishra@Sun.COM */ 25310393SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t atge_dma_attr_buf = { 25410393SSaurabh.Mishra@Sun.COM DMA_ATTR_V0, /* dma_attr_version */ 25510393SSaurabh.Mishra@Sun.COM 0, /* dma_attr_addr_lo */ 25610393SSaurabh.Mishra@Sun.COM 0x00ffffffffffull, /* dma_attr_addr_hi */ 25710393SSaurabh.Mishra@Sun.COM 0x000000003fffull, /* dma_attr_count_max */ 25810393SSaurabh.Mishra@Sun.COM 8, /* dma_attr_align */ 25910393SSaurabh.Mishra@Sun.COM 0x00003ffc, /* dma_attr_burstsizes */ 26010393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_minxfer */ 26110393SSaurabh.Mishra@Sun.COM 0x0000000027ffull, /* dma_attr_maxxfer */ 26210393SSaurabh.Mishra@Sun.COM 0x0000ffffffffull, /* dma_attr_seg */ 26310393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_sgllen */ 26410393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_granular */ 26510393SSaurabh.Mishra@Sun.COM 0 /* dma_attr_flags */ 26610393SSaurabh.Mishra@Sun.COM }; 26710393SSaurabh.Mishra@Sun.COM 26810393SSaurabh.Mishra@Sun.COM /* 26910393SSaurabh.Mishra@Sun.COM * Table of supported devices. 27010393SSaurabh.Mishra@Sun.COM */ 27110393SSaurabh.Mishra@Sun.COM #define ATGE_VENDOR_ID 0x1969 27210393SSaurabh.Mishra@Sun.COM #define ATGE_L1E_STR "Atheros AR8121/8113/8114" 27310393SSaurabh.Mishra@Sun.COM 27410393SSaurabh.Mishra@Sun.COM static atge_cards_t atge_cards[] = { 27510393SSaurabh.Mishra@Sun.COM {ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E}, 276*11353SSaurabh.Mishra@Sun.COM {ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1}, 27710393SSaurabh.Mishra@Sun.COM }; 27810393SSaurabh.Mishra@Sun.COM 27910393SSaurabh.Mishra@Sun.COM /* 28010393SSaurabh.Mishra@Sun.COM * Global Debugging flag. Developer level debugging is done only in DEBUG mode. 28110393SSaurabh.Mishra@Sun.COM */ 28210393SSaurabh.Mishra@Sun.COM int atge_debug = 1; 28310393SSaurabh.Mishra@Sun.COM 28410393SSaurabh.Mishra@Sun.COM /* 28510393SSaurabh.Mishra@Sun.COM * Debugging and error reporting. 28610393SSaurabh.Mishra@Sun.COM */ 28710393SSaurabh.Mishra@Sun.COM void 28810393SSaurabh.Mishra@Sun.COM atge_debug_func(char *fmt, ...) 28910393SSaurabh.Mishra@Sun.COM { 29010393SSaurabh.Mishra@Sun.COM va_list ap; 29110393SSaurabh.Mishra@Sun.COM char buf[256]; 29210393SSaurabh.Mishra@Sun.COM 29310393SSaurabh.Mishra@Sun.COM va_start(ap, fmt); 29410393SSaurabh.Mishra@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap); 29510393SSaurabh.Mishra@Sun.COM va_end(ap); 29610393SSaurabh.Mishra@Sun.COM 29710393SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(atge__debug, char *, buf); 29810393SSaurabh.Mishra@Sun.COM } 29910393SSaurabh.Mishra@Sun.COM 30010393SSaurabh.Mishra@Sun.COM void 30110393SSaurabh.Mishra@Sun.COM atge_error(dev_info_t *dip, char *fmt, ...) 30210393SSaurabh.Mishra@Sun.COM { 30310393SSaurabh.Mishra@Sun.COM va_list ap; 30410393SSaurabh.Mishra@Sun.COM char buf[256]; 30510393SSaurabh.Mishra@Sun.COM 30610393SSaurabh.Mishra@Sun.COM va_start(ap, fmt); 30710393SSaurabh.Mishra@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap); 30810393SSaurabh.Mishra@Sun.COM va_end(ap); 30910393SSaurabh.Mishra@Sun.COM 31010393SSaurabh.Mishra@Sun.COM if (dip) { 31110393SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "%s%d: %s", 31210393SSaurabh.Mishra@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), buf); 31310393SSaurabh.Mishra@Sun.COM } else { 31410393SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "atge: %s", buf); 31510393SSaurabh.Mishra@Sun.COM } 31610393SSaurabh.Mishra@Sun.COM } 31710393SSaurabh.Mishra@Sun.COM 31810393SSaurabh.Mishra@Sun.COM void 31910393SSaurabh.Mishra@Sun.COM atge_mac_config(atge_t *atgep) 32010393SSaurabh.Mishra@Sun.COM { 32110393SSaurabh.Mishra@Sun.COM uint32_t reg; 32210393SSaurabh.Mishra@Sun.COM int speed; 32310393SSaurabh.Mishra@Sun.COM link_duplex_t ld; 32410393SSaurabh.Mishra@Sun.COM 32510393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MAC_CFG); 32610393SSaurabh.Mishra@Sun.COM reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC | 32710393SSaurabh.Mishra@Sun.COM ATGE_CFG_SPEED_MASK); 32810393SSaurabh.Mishra@Sun.COM 32910393SSaurabh.Mishra@Sun.COM speed = mii_get_speed(atgep->atge_mii); 33010393SSaurabh.Mishra@Sun.COM switch (speed) { 33110393SSaurabh.Mishra@Sun.COM case 10: 33210393SSaurabh.Mishra@Sun.COM case 100: 33310393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_10_100; 33410393SSaurabh.Mishra@Sun.COM break; 33510393SSaurabh.Mishra@Sun.COM case 1000: 33610393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_1000; 33710393SSaurabh.Mishra@Sun.COM break; 33810393SSaurabh.Mishra@Sun.COM } 33910393SSaurabh.Mishra@Sun.COM 34010393SSaurabh.Mishra@Sun.COM ld = mii_get_duplex(atgep->atge_mii); 34110393SSaurabh.Mishra@Sun.COM if (ld == LINK_DUPLEX_FULL) 34210393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_FULL_DUPLEX; 34310393SSaurabh.Mishra@Sun.COM 34410393SSaurabh.Mishra@Sun.COM /* Re-enable TX/RX MACs */ 345*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 346*11353SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC; 347*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 348*11353SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB; 349*11353SSaurabh.Mishra@Sun.COM } 350*11353SSaurabh.Mishra@Sun.COM 35110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, reg); 35210393SSaurabh.Mishra@Sun.COM 35310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 35410393SSaurabh.Mishra@Sun.COM reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT; 35510393SSaurabh.Mishra@Sun.COM reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) << 35610393SSaurabh.Mishra@Sun.COM IM_TIMER_TX_SHIFT; 35710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_IM_TIMER, reg); 35810393SSaurabh.Mishra@Sun.COM } 35910393SSaurabh.Mishra@Sun.COM 36010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mac_cfg is : %x", 36110393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG))); 36210393SSaurabh.Mishra@Sun.COM } 36310393SSaurabh.Mishra@Sun.COM 36410393SSaurabh.Mishra@Sun.COM static void 36510393SSaurabh.Mishra@Sun.COM atge_mii_notify(void *arg, link_state_t link) 36610393SSaurabh.Mishra@Sun.COM { 36710393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 36810393SSaurabh.Mishra@Sun.COM 36910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x", 37010393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_link_state, link)); 37110393SSaurabh.Mishra@Sun.COM 37210393SSaurabh.Mishra@Sun.COM mac_link_update(atgep->atge_mh, link); 37310393SSaurabh.Mishra@Sun.COM 37410393SSaurabh.Mishra@Sun.COM /* 37510393SSaurabh.Mishra@Sun.COM * Reconfigure MAC if link status is UP now. 37610393SSaurabh.Mishra@Sun.COM */ 37710393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 37810393SSaurabh.Mishra@Sun.COM if (link == LINK_STATE_UP) { 379*11353SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_UP; 38010393SSaurabh.Mishra@Sun.COM atge_mac_config(atgep); 38110393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 0; 38210393SSaurabh.Mishra@Sun.COM } else { 38310393SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_DOWN; 384*11353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MII_CHECK; 38510393SSaurabh.Mishra@Sun.COM } 38610393SSaurabh.Mishra@Sun.COM 38710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 38810393SSaurabh.Mishra@Sun.COM 38910393SSaurabh.Mishra@Sun.COM if (link == LINK_STATE_UP) 39010393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh); 39110393SSaurabh.Mishra@Sun.COM } 39210393SSaurabh.Mishra@Sun.COM 393*11353SSaurabh.Mishra@Sun.COM void 394*11353SSaurabh.Mishra@Sun.COM atge_tx_reclaim(atge_t *atgep, int end) 39510393SSaurabh.Mishra@Sun.COM { 396*11353SSaurabh.Mishra@Sun.COM atge_tx_desc_t *txd; 397*11353SSaurabh.Mishra@Sun.COM atge_ring_t *r = atgep->atge_tx_ring; 398*11353SSaurabh.Mishra@Sun.COM uchar_t *c; 399*11353SSaurabh.Mishra@Sun.COM int start; 400*11353SSaurabh.Mishra@Sun.COM 401*11353SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock)); 402*11353SSaurabh.Mishra@Sun.COM ASSERT(r != NULL); 403*11353SSaurabh.Mishra@Sun.COM 404*11353SSaurabh.Mishra@Sun.COM start = r->r_consumer; 405*11353SSaurabh.Mishra@Sun.COM 406*11353SSaurabh.Mishra@Sun.COM if (start == end) 407*11353SSaurabh.Mishra@Sun.COM return; 408*11353SSaurabh.Mishra@Sun.COM 409*11353SSaurabh.Mishra@Sun.COM while (start != end) { 410*11353SSaurabh.Mishra@Sun.COM r->r_avail_desc++; 411*11353SSaurabh.Mishra@Sun.COM if (r->r_avail_desc > ATGE_TX_RING_CNT) { 412*11353SSaurabh.Mishra@Sun.COM 413*11353SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 414*11353SSaurabh.Mishra@Sun.COM "Reclaim : TX descriptor error"); 415*11353SSaurabh.Mishra@Sun.COM 416*11353SSaurabh.Mishra@Sun.COM if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) { 417*11353SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 418*11353SSaurabh.Mishra@Sun.COM break; 419*11353SSaurabh.Mishra@Sun.COM } 42010393SSaurabh.Mishra@Sun.COM } 42110393SSaurabh.Mishra@Sun.COM 422*11353SSaurabh.Mishra@Sun.COM c = (uchar_t *)r->r_desc_ring->addr; 423*11353SSaurabh.Mishra@Sun.COM c += (sizeof (atge_tx_desc_t) * start); 424*11353SSaurabh.Mishra@Sun.COM txd = (atge_tx_desc_t *)c; 425*11353SSaurabh.Mishra@Sun.COM 42610393SSaurabh.Mishra@Sun.COM /* 427*11353SSaurabh.Mishra@Sun.COM * Clearing TX descriptor helps in debugging some strange 428*11353SSaurabh.Mishra@Sun.COM * problems. 42910393SSaurabh.Mishra@Sun.COM */ 430*11353SSaurabh.Mishra@Sun.COM txd->addr = 0; 431*11353SSaurabh.Mishra@Sun.COM txd->len = 0; 432*11353SSaurabh.Mishra@Sun.COM txd->flags = 0; 433*11353SSaurabh.Mishra@Sun.COM 434*11353SSaurabh.Mishra@Sun.COM ATGE_INC_SLOT(start, ATGE_TX_RING_CNT); 43510393SSaurabh.Mishra@Sun.COM } 43610393SSaurabh.Mishra@Sun.COM 437*11353SSaurabh.Mishra@Sun.COM atgep->atge_tx_ring->r_consumer = start; 438*11353SSaurabh.Mishra@Sun.COM 439*11353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV); 44010393SSaurabh.Mishra@Sun.COM } 44110393SSaurabh.Mishra@Sun.COM 44210393SSaurabh.Mishra@Sun.COM /* 44310393SSaurabh.Mishra@Sun.COM * Adds interrupt handler depending upon the type of interrupt supported by 44410393SSaurabh.Mishra@Sun.COM * the chip. 44510393SSaurabh.Mishra@Sun.COM */ 44610393SSaurabh.Mishra@Sun.COM static int 44710393SSaurabh.Mishra@Sun.COM atge_add_intr_handler(atge_t *atgep, int intr_type) 44810393SSaurabh.Mishra@Sun.COM { 44910393SSaurabh.Mishra@Sun.COM int err; 45010393SSaurabh.Mishra@Sun.COM int count = 0; 45110393SSaurabh.Mishra@Sun.COM int avail = 0; 45210393SSaurabh.Mishra@Sun.COM int i; 45310393SSaurabh.Mishra@Sun.COM int flag; 45410393SSaurabh.Mishra@Sun.COM 45510393SSaurabh.Mishra@Sun.COM if (intr_type != DDI_INTR_TYPE_FIXED) { 45610393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count); 45710393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 45810393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 45910393SSaurabh.Mishra@Sun.COM "ddi_intr_get_nintrs failed : %d", err); 460*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 46110393SSaurabh.Mishra@Sun.COM } 46210393SSaurabh.Mishra@Sun.COM 46310393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() count : %d", 46410393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, count)); 46510393SSaurabh.Mishra@Sun.COM 46610393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail); 46710393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 46810393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 46910393SSaurabh.Mishra@Sun.COM "ddi_intr_get_navail failed : %d", err); 470*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 47110393SSaurabh.Mishra@Sun.COM } 47210393SSaurabh.Mishra@Sun.COM 47310393SSaurabh.Mishra@Sun.COM if (avail < count) { 47410393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "count :%d," 47510393SSaurabh.Mishra@Sun.COM " avail : %d", count, avail); 47610393SSaurabh.Mishra@Sun.COM } 47710393SSaurabh.Mishra@Sun.COM 47810393SSaurabh.Mishra@Sun.COM flag = DDI_INTR_ALLOC_STRICT; 47910393SSaurabh.Mishra@Sun.COM } else { 48010393SSaurabh.Mishra@Sun.COM /* 48110393SSaurabh.Mishra@Sun.COM * DDI_INTR_TYPE_FIXED case. 48210393SSaurabh.Mishra@Sun.COM */ 48310393SSaurabh.Mishra@Sun.COM count = 1; 48410393SSaurabh.Mishra@Sun.COM avail = 1; 48510393SSaurabh.Mishra@Sun.COM flag = DDI_INTR_ALLOC_NORMAL; 48610393SSaurabh.Mishra@Sun.COM } 48710393SSaurabh.Mishra@Sun.COM 48810393SSaurabh.Mishra@Sun.COM atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t); 48910393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP); 49010393SSaurabh.Mishra@Sun.COM 49110393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d", 49210393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, avail, count, 49310393SSaurabh.Mishra@Sun.COM intr_type)); 49410393SSaurabh.Mishra@Sun.COM 49510393SSaurabh.Mishra@Sun.COM err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle, 49610393SSaurabh.Mishra@Sun.COM intr_type, 0, avail, &atgep->atge_intr_cnt, flag); 49710393SSaurabh.Mishra@Sun.COM 49810393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 49910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err); 50010393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size); 501*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 50210393SSaurabh.Mishra@Sun.COM } 50310393SSaurabh.Mishra@Sun.COM 50410393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: atge_add_intr_handler() after alloc count" 50510393SSaurabh.Mishra@Sun.COM " :%d, avail : %d", atgep->atge_name, count, avail)); 50610393SSaurabh.Mishra@Sun.COM 50710393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_pri(atgep->atge_intr_handle[0], 50810393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_pri); 50910393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 51010393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err); 51110393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) { 51210393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]); 51310393SSaurabh.Mishra@Sun.COM } 51410393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size); 51510393SSaurabh.Mishra@Sun.COM 516*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 51710393SSaurabh.Mishra@Sun.COM } 51810393SSaurabh.Mishra@Sun.COM 51910393SSaurabh.Mishra@Sun.COM /* 52010393SSaurabh.Mishra@Sun.COM * Add interrupt handler now. 52110393SSaurabh.Mishra@Sun.COM */ 52210393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) { 523*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 524*11353SSaurabh.Mishra@Sun.COM err = ddi_intr_add_handler(atgep->atge_intr_handle[i], 525*11353SSaurabh.Mishra@Sun.COM atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i); 526*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 527*11353SSaurabh.Mishra@Sun.COM err = ddi_intr_add_handler(atgep->atge_intr_handle[i], 528*11353SSaurabh.Mishra@Sun.COM atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i); 529*11353SSaurabh.Mishra@Sun.COM } 53010393SSaurabh.Mishra@Sun.COM 53110393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 53210393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 53310393SSaurabh.Mishra@Sun.COM "ddi_intr_add_handler failed : %d", err); 53410393SSaurabh.Mishra@Sun.COM 53510393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]); 53610393SSaurabh.Mishra@Sun.COM while (--i >= 0) { 53710393SSaurabh.Mishra@Sun.COM (void) ddi_intr_remove_handler( 53810393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle[i]); 53910393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free( 54010393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle[i]); 54110393SSaurabh.Mishra@Sun.COM } 54210393SSaurabh.Mishra@Sun.COM 54310393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, 54410393SSaurabh.Mishra@Sun.COM atgep->atge_intr_size); 54510393SSaurabh.Mishra@Sun.COM 546*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 54710393SSaurabh.Mishra@Sun.COM } 54810393SSaurabh.Mishra@Sun.COM } 54910393SSaurabh.Mishra@Sun.COM 55010393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_cap(atgep->atge_intr_handle[0], 55110393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_cap); 55210393SSaurabh.Mishra@Sun.COM 55310393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 55410393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 55510393SSaurabh.Mishra@Sun.COM "ddi_intr_get_cap failed : %d", err); 55610393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep); 557*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 55810393SSaurabh.Mishra@Sun.COM } 55910393SSaurabh.Mishra@Sun.COM 56010393SSaurabh.Mishra@Sun.COM if (intr_type == DDI_INTR_TYPE_FIXED) 56110393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FIXED_TYPE; 56210393SSaurabh.Mishra@Sun.COM else if (intr_type == DDI_INTR_TYPE_MSI) 56310393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MSI_TYPE; 56410393SSaurabh.Mishra@Sun.COM else if (intr_type == DDI_INTR_TYPE_MSIX) 56510393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MSIX_TYPE; 56610393SSaurabh.Mishra@Sun.COM 567*11353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 56810393SSaurabh.Mishra@Sun.COM } 56910393SSaurabh.Mishra@Sun.COM 57010393SSaurabh.Mishra@Sun.COM void 57110393SSaurabh.Mishra@Sun.COM atge_remove_intr(atge_t *atgep) 57210393SSaurabh.Mishra@Sun.COM { 57310393SSaurabh.Mishra@Sun.COM int i; 57410393SSaurabh.Mishra@Sun.COM int cap = 0; 57510393SSaurabh.Mishra@Sun.COM 57610393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_handle == NULL) 57710393SSaurabh.Mishra@Sun.COM return; 57810393SSaurabh.Mishra@Sun.COM 57910393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) { 58010393SSaurabh.Mishra@Sun.COM (void) ddi_intr_block_disable(atgep->atge_intr_handle, 58110393SSaurabh.Mishra@Sun.COM atgep->atge_intr_cnt); 58210393SSaurabh.Mishra@Sun.COM 58310393SSaurabh.Mishra@Sun.COM cap = 1; 58410393SSaurabh.Mishra@Sun.COM } 58510393SSaurabh.Mishra@Sun.COM 58610393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) { 58710393SSaurabh.Mishra@Sun.COM if (cap == 0) 58810393SSaurabh.Mishra@Sun.COM (void) ddi_intr_disable(atgep->atge_intr_handle[i]); 58910393SSaurabh.Mishra@Sun.COM 59010393SSaurabh.Mishra@Sun.COM (void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]); 59110393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]); 59210393SSaurabh.Mishra@Sun.COM } 59310393SSaurabh.Mishra@Sun.COM 59410393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size); 59510393SSaurabh.Mishra@Sun.COM } 59610393SSaurabh.Mishra@Sun.COM 59710393SSaurabh.Mishra@Sun.COM int 59810393SSaurabh.Mishra@Sun.COM atge_enable_intrs(atge_t *atgep) 59910393SSaurabh.Mishra@Sun.COM { 60010393SSaurabh.Mishra@Sun.COM int err; 60110393SSaurabh.Mishra@Sun.COM int i; 60210393SSaurabh.Mishra@Sun.COM 60310393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) { 60410393SSaurabh.Mishra@Sun.COM /* 60510393SSaurabh.Mishra@Sun.COM * Do block enable. 60610393SSaurabh.Mishra@Sun.COM */ 60710393SSaurabh.Mishra@Sun.COM err = ddi_intr_block_enable(atgep->atge_intr_handle, 60810393SSaurabh.Mishra@Sun.COM atgep->atge_intr_cnt); 60910393SSaurabh.Mishra@Sun.COM 61010393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 61110393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 61210393SSaurabh.Mishra@Sun.COM "Failed to block enable intrs %d", err); 613*11353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE; 61410393SSaurabh.Mishra@Sun.COM } else { 615*11353SSaurabh.Mishra@Sun.COM err = DDI_SUCCESS; 61610393SSaurabh.Mishra@Sun.COM } 61710393SSaurabh.Mishra@Sun.COM } else { 61810393SSaurabh.Mishra@Sun.COM /* 61910393SSaurabh.Mishra@Sun.COM * Call ddi_intr_enable() for MSI non-block enable. 62010393SSaurabh.Mishra@Sun.COM */ 62110393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) { 62210393SSaurabh.Mishra@Sun.COM err = ddi_intr_enable(atgep->atge_intr_handle[i]); 62310393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 62410393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 62510393SSaurabh.Mishra@Sun.COM "Failed to enable intrs on %d with : %d", 62610393SSaurabh.Mishra@Sun.COM i, err); 62710393SSaurabh.Mishra@Sun.COM break; 62810393SSaurabh.Mishra@Sun.COM } 62910393SSaurabh.Mishra@Sun.COM } 63010393SSaurabh.Mishra@Sun.COM 63110393SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) 632*11353SSaurabh.Mishra@Sun.COM err = DDI_SUCCESS; 63310393SSaurabh.Mishra@Sun.COM else 634*11353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE; 63510393SSaurabh.Mishra@Sun.COM } 63610393SSaurabh.Mishra@Sun.COM 63710393SSaurabh.Mishra@Sun.COM return (err); 63810393SSaurabh.Mishra@Sun.COM } 63910393SSaurabh.Mishra@Sun.COM 64010393SSaurabh.Mishra@Sun.COM /* 64110393SSaurabh.Mishra@Sun.COM * Adds interrupt handler depending on the supported interrupt type by the 64210393SSaurabh.Mishra@Sun.COM * chip. 64310393SSaurabh.Mishra@Sun.COM */ 64410393SSaurabh.Mishra@Sun.COM static int 64510393SSaurabh.Mishra@Sun.COM atge_add_intr(atge_t *atgep) 64610393SSaurabh.Mishra@Sun.COM { 64710393SSaurabh.Mishra@Sun.COM int err; 64810393SSaurabh.Mishra@Sun.COM 64910393SSaurabh.Mishra@Sun.COM /* 65010393SSaurabh.Mishra@Sun.COM * Get the supported interrupt types. 65110393SSaurabh.Mishra@Sun.COM */ 65210393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_supported_types(atgep->atge_dip, 65310393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_types); 65410393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 65510393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, 65610393SSaurabh.Mishra@Sun.COM "ddi_intr_get_supported_types failed : %d", err); 657*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 65810393SSaurabh.Mishra@Sun.COM } 65910393SSaurabh.Mishra@Sun.COM 66010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d", 66110393SSaurabh.Mishra@Sun.COM atgep->atge_name, atgep->atge_intr_types)); 66210393SSaurabh.Mishra@Sun.COM 66310393SSaurabh.Mishra@Sun.COM 66410393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) { 66510393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX); 666*11353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) { 66710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using MSIx for interrupt", 66810393SSaurabh.Mishra@Sun.COM atgep->atge_name)); 66910393SSaurabh.Mishra@Sun.COM return (err); 67010393SSaurabh.Mishra@Sun.COM } 67110393SSaurabh.Mishra@Sun.COM } 67210393SSaurabh.Mishra@Sun.COM 67310393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) { 67410393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI); 675*11353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) { 67610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using MSI for interrupt", 67710393SSaurabh.Mishra@Sun.COM atgep->atge_name)); 67810393SSaurabh.Mishra@Sun.COM return (err); 67910393SSaurabh.Mishra@Sun.COM } 68010393SSaurabh.Mishra@Sun.COM } 68110393SSaurabh.Mishra@Sun.COM 682*11353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE; 68310393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) { 68410393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED); 685*11353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) { 68610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using FIXED type for interrupt", 68710393SSaurabh.Mishra@Sun.COM atgep->atge_name)); 68810393SSaurabh.Mishra@Sun.COM return (err); 68910393SSaurabh.Mishra@Sun.COM } 69010393SSaurabh.Mishra@Sun.COM } 69110393SSaurabh.Mishra@Sun.COM 69210393SSaurabh.Mishra@Sun.COM return (err); 69310393SSaurabh.Mishra@Sun.COM } 69410393SSaurabh.Mishra@Sun.COM 69510393SSaurabh.Mishra@Sun.COM int 69610393SSaurabh.Mishra@Sun.COM atge_identify_hardware(atge_t *atgep) 69710393SSaurabh.Mishra@Sun.COM { 69810393SSaurabh.Mishra@Sun.COM uint16_t vid, did; 69910393SSaurabh.Mishra@Sun.COM int i; 70010393SSaurabh.Mishra@Sun.COM 70110393SSaurabh.Mishra@Sun.COM vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID); 70210393SSaurabh.Mishra@Sun.COM did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID); 70310393SSaurabh.Mishra@Sun.COM 70410393SSaurabh.Mishra@Sun.COM atgep->atge_model = 0; 70510393SSaurabh.Mishra@Sun.COM for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) { 70610393SSaurabh.Mishra@Sun.COM if (atge_cards[i].vendor_id == vid && 70710393SSaurabh.Mishra@Sun.COM atge_cards[i].device_id == did) { 70810393SSaurabh.Mishra@Sun.COM atgep->atge_model = atge_cards[i].model; 70910393SSaurabh.Mishra@Sun.COM atgep->atge_revid = 71010393SSaurabh.Mishra@Sun.COM pci_config_get8(atgep->atge_conf_handle, 71110393SSaurabh.Mishra@Sun.COM PCI_CONF_REVID); 71210393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d", 71310393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, vid, did, 71410393SSaurabh.Mishra@Sun.COM atgep->atge_model)); 71510393SSaurabh.Mishra@Sun.COM 716*11353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 71710393SSaurabh.Mishra@Sun.COM } 71810393SSaurabh.Mishra@Sun.COM } 71910393SSaurabh.Mishra@Sun.COM 72010393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "atge driver is attaching to unknown" 72110393SSaurabh.Mishra@Sun.COM " pci%d,%d vendor/device-id card", vid, did); 72210393SSaurabh.Mishra@Sun.COM 72310393SSaurabh.Mishra@Sun.COM /* 724*11353SSaurabh.Mishra@Sun.COM * Assume it's L1 chip. 72510393SSaurabh.Mishra@Sun.COM */ 726*11353SSaurabh.Mishra@Sun.COM atgep->atge_model = ATGE_CHIP_L1; 72710393SSaurabh.Mishra@Sun.COM atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle, 72810393SSaurabh.Mishra@Sun.COM PCI_CONF_REVID); 72910393SSaurabh.Mishra@Sun.COM 73010393SSaurabh.Mishra@Sun.COM /* 73110393SSaurabh.Mishra@Sun.COM * We will leave the decision to caller. 73210393SSaurabh.Mishra@Sun.COM */ 733*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 73410393SSaurabh.Mishra@Sun.COM } 73510393SSaurabh.Mishra@Sun.COM 73610393SSaurabh.Mishra@Sun.COM int 73710393SSaurabh.Mishra@Sun.COM atge_get_macaddr(atge_t *atgep) 73810393SSaurabh.Mishra@Sun.COM { 73910393SSaurabh.Mishra@Sun.COM uint32_t reg; 74010393SSaurabh.Mishra@Sun.COM 74110393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_SPI_CTRL); 74210393SSaurabh.Mishra@Sun.COM if ((reg & SPI_VPD_ENB) != 0) { 74310393SSaurabh.Mishra@Sun.COM /* 74410393SSaurabh.Mishra@Sun.COM * Get VPD stored in TWSI EEPROM. 74510393SSaurabh.Mishra@Sun.COM */ 74610393SSaurabh.Mishra@Sun.COM reg &= ~SPI_VPD_ENB; 74710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_SPI_CTRL, reg); 74810393SSaurabh.Mishra@Sun.COM 74910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__)); 75010393SSaurabh.Mishra@Sun.COM } 75110393SSaurabh.Mishra@Sun.COM 75210393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0); 75310393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1); 75410393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2); 75510393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3); 75610393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0); 75710393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1); 75810393SSaurabh.Mishra@Sun.COM 75910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x", 76010393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, 76110393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[0], 76210393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[1], 76310393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[2], 76410393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[3], 76510393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[4], 76610393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[5])); 76710393SSaurabh.Mishra@Sun.COM 76810393SSaurabh.Mishra@Sun.COM bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL); 76910393SSaurabh.Mishra@Sun.COM 770*11353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 77110393SSaurabh.Mishra@Sun.COM } 77210393SSaurabh.Mishra@Sun.COM 77310393SSaurabh.Mishra@Sun.COM /* 77410393SSaurabh.Mishra@Sun.COM * Reset functionality for L1 and L1E. It's same. 77510393SSaurabh.Mishra@Sun.COM */ 77610393SSaurabh.Mishra@Sun.COM static void 77710393SSaurabh.Mishra@Sun.COM atge_device_reset(atge_t *atgep) 77810393SSaurabh.Mishra@Sun.COM { 77910393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E || 78010393SSaurabh.Mishra@Sun.COM ATGE_MODEL(atgep) == ATGE_CHIP_L1) 78110393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atgep); 78210393SSaurabh.Mishra@Sun.COM } 78310393SSaurabh.Mishra@Sun.COM 78410393SSaurabh.Mishra@Sun.COM void 78510393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atge_t *atgep) 78610393SSaurabh.Mishra@Sun.COM { 78710393SSaurabh.Mishra@Sun.COM uint32_t reg; 78810393SSaurabh.Mishra@Sun.COM int t; 78910393SSaurabh.Mishra@Sun.COM 79010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET); 79110393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MASTER_CFG); 79210393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) { 79310393SSaurabh.Mishra@Sun.COM drv_usecwait(10); 79410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MASTER_CFG); 79510393SSaurabh.Mishra@Sun.COM if ((reg & MASTER_RESET) == 0) 79610393SSaurabh.Mishra@Sun.COM break; 79710393SSaurabh.Mishra@Sun.COM } 79810393SSaurabh.Mishra@Sun.COM 79910393SSaurabh.Mishra@Sun.COM if (t == 0) { 80010393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, " master reset timeout reg : %x", 80110393SSaurabh.Mishra@Sun.COM reg); 80210393SSaurabh.Mishra@Sun.COM } 80310393SSaurabh.Mishra@Sun.COM 80410393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) { 80510393SSaurabh.Mishra@Sun.COM if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0) 80610393SSaurabh.Mishra@Sun.COM break; 80710393SSaurabh.Mishra@Sun.COM 80810393SSaurabh.Mishra@Sun.COM drv_usecwait(10); 80910393SSaurabh.Mishra@Sun.COM } 81010393SSaurabh.Mishra@Sun.COM 81110393SSaurabh.Mishra@Sun.COM if (t == 0) { 81210393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "device reset timeout reg : %x", 81310393SSaurabh.Mishra@Sun.COM reg); 81410393SSaurabh.Mishra@Sun.COM } 81510393SSaurabh.Mishra@Sun.COM 81610393SSaurabh.Mishra@Sun.COM /* 81710393SSaurabh.Mishra@Sun.COM * Initialize PCIe module. These values came from FreeBSD and 81810393SSaurabh.Mishra@Sun.COM * we don't know the meaning of it. 81910393SSaurabh.Mishra@Sun.COM */ 82010393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x12FC, 0x6500); 82110393SSaurabh.Mishra@Sun.COM reg = INL(atgep, 0x1008) | 0x8000; 82210393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x1008, reg); 82310393SSaurabh.Mishra@Sun.COM 82410393SSaurabh.Mishra@Sun.COM /* 82510393SSaurabh.Mishra@Sun.COM * Get chip revision. 82610393SSaurabh.Mishra@Sun.COM */ 82710393SSaurabh.Mishra@Sun.COM atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >> 82810393SSaurabh.Mishra@Sun.COM MASTER_CHIP_REV_SHIFT; 82910393SSaurabh.Mishra@Sun.COM 83010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name, 83110393SSaurabh.Mishra@Sun.COM __func__, atgep->atge_chip_rev)); 83210393SSaurabh.Mishra@Sun.COM } 83310393SSaurabh.Mishra@Sun.COM 83410393SSaurabh.Mishra@Sun.COM /* 83510393SSaurabh.Mishra@Sun.COM * DMA allocation for L1 and L1E is bit different since L1E uses RX pages 83610393SSaurabh.Mishra@Sun.COM * instead of descriptor based RX model. 83710393SSaurabh.Mishra@Sun.COM */ 83810393SSaurabh.Mishra@Sun.COM static int 83910393SSaurabh.Mishra@Sun.COM atge_alloc_dma(atge_t *atgep) 84010393SSaurabh.Mishra@Sun.COM { 841*11353SSaurabh.Mishra@Sun.COM int err = DDI_FAILURE; 84210393SSaurabh.Mishra@Sun.COM 84310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 84410393SSaurabh.Mishra@Sun.COM err = atge_l1e_alloc_dma(atgep); 845*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 846*11353SSaurabh.Mishra@Sun.COM err = atge_l1_alloc_dma(atgep); 84710393SSaurabh.Mishra@Sun.COM } 84810393SSaurabh.Mishra@Sun.COM 84910393SSaurabh.Mishra@Sun.COM return (err); 85010393SSaurabh.Mishra@Sun.COM } 85110393SSaurabh.Mishra@Sun.COM 85210393SSaurabh.Mishra@Sun.COM static void 85310393SSaurabh.Mishra@Sun.COM atge_free_dma(atge_t *atgep) 85410393SSaurabh.Mishra@Sun.COM { 85510393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 85610393SSaurabh.Mishra@Sun.COM atge_l1e_free_dma(atgep); 85710393SSaurabh.Mishra@Sun.COM } 85810393SSaurabh.Mishra@Sun.COM } 85910393SSaurabh.Mishra@Sun.COM 86010393SSaurabh.Mishra@Sun.COM /* 86110393SSaurabh.Mishra@Sun.COM * Attach entry point in the driver. 86210393SSaurabh.Mishra@Sun.COM */ 86310393SSaurabh.Mishra@Sun.COM static int 86410393SSaurabh.Mishra@Sun.COM atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 86510393SSaurabh.Mishra@Sun.COM { 86610393SSaurabh.Mishra@Sun.COM atge_t *atgep; 86710393SSaurabh.Mishra@Sun.COM mac_register_t *macreg; 86810393SSaurabh.Mishra@Sun.COM int instance; 86910393SSaurabh.Mishra@Sun.COM uint16_t cap_ptr; 87010393SSaurabh.Mishra@Sun.COM uint16_t burst; 87110393SSaurabh.Mishra@Sun.COM int err; 87210393SSaurabh.Mishra@Sun.COM mii_ops_t *mii_ops; 87310393SSaurabh.Mishra@Sun.COM 87410393SSaurabh.Mishra@Sun.COM instance = ddi_get_instance(devinfo); 87510393SSaurabh.Mishra@Sun.COM 87610393SSaurabh.Mishra@Sun.COM switch (cmd) { 87710393SSaurabh.Mishra@Sun.COM default: 87810393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 87910393SSaurabh.Mishra@Sun.COM 88010393SSaurabh.Mishra@Sun.COM case DDI_RESUME: 88110393SSaurabh.Mishra@Sun.COM return (atge_resume(devinfo)); 88210393SSaurabh.Mishra@Sun.COM 88310393SSaurabh.Mishra@Sun.COM case DDI_ATTACH: 88410393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(devinfo, NULL); 88510393SSaurabh.Mishra@Sun.COM break; 88610393SSaurabh.Mishra@Sun.COM } 88710393SSaurabh.Mishra@Sun.COM 88810393SSaurabh.Mishra@Sun.COM atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP); 88910393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(devinfo, atgep); 89010393SSaurabh.Mishra@Sun.COM atgep->atge_dip = devinfo; 89110393SSaurabh.Mishra@Sun.COM 89210393SSaurabh.Mishra@Sun.COM /* 89310393SSaurabh.Mishra@Sun.COM * Setup name and instance number to be used for debugging and 89410393SSaurabh.Mishra@Sun.COM * error reporting. 89510393SSaurabh.Mishra@Sun.COM */ 89610393SSaurabh.Mishra@Sun.COM (void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d", 89710393SSaurabh.Mishra@Sun.COM "atge", instance); 89810393SSaurabh.Mishra@Sun.COM 89910393SSaurabh.Mishra@Sun.COM 90010393SSaurabh.Mishra@Sun.COM /* 90110393SSaurabh.Mishra@Sun.COM * Map PCI config space. 90210393SSaurabh.Mishra@Sun.COM */ 90310393SSaurabh.Mishra@Sun.COM err = pci_config_setup(devinfo, &atgep->atge_conf_handle); 90410393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 90510393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "pci_config_setup() failed"); 90610393SSaurabh.Mishra@Sun.COM goto fail1; 90710393SSaurabh.Mishra@Sun.COM } 90810393SSaurabh.Mishra@Sun.COM 90910393SSaurabh.Mishra@Sun.COM (void) atge_identify_hardware(atgep); 91010393SSaurabh.Mishra@Sun.COM 91110393SSaurabh.Mishra@Sun.COM /* 91210393SSaurabh.Mishra@Sun.COM * Map Device registers. 91310393SSaurabh.Mishra@Sun.COM */ 91410393SSaurabh.Mishra@Sun.COM err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER, 91510393SSaurabh.Mishra@Sun.COM &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle); 91610393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 91710393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "ddi_regs_map_setup() failed"); 91810393SSaurabh.Mishra@Sun.COM goto fail2; 91910393SSaurabh.Mishra@Sun.COM } 92010393SSaurabh.Mishra@Sun.COM 92110393SSaurabh.Mishra@Sun.COM /* 92210393SSaurabh.Mishra@Sun.COM * Add interrupt and its associated handler. 92310393SSaurabh.Mishra@Sun.COM */ 92410393SSaurabh.Mishra@Sun.COM err = atge_add_intr(atgep); 925*11353SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 92610393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "Failed to add interrupt handler"); 92710393SSaurabh.Mishra@Sun.COM goto fail3; 92810393SSaurabh.Mishra@Sun.COM } 92910393SSaurabh.Mishra@Sun.COM 93010393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_intr_lock, NULL, MUTEX_DRIVER, 93110393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri)); 93210393SSaurabh.Mishra@Sun.COM 93310393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_tx_lock, NULL, MUTEX_DRIVER, 93410393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri)); 93510393SSaurabh.Mishra@Sun.COM 93610393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_rx_lock, NULL, MUTEX_DRIVER, 93710393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri)); 93810393SSaurabh.Mishra@Sun.COM 93910393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL); 94010393SSaurabh.Mishra@Sun.COM 941*11353SSaurabh.Mishra@Sun.COM /* 942*11353SSaurabh.Mishra@Sun.COM * Used to lock down MBOX register on L1 chip since RX consumer, 943*11353SSaurabh.Mishra@Sun.COM * TX producer and RX return ring consumer are shared. 944*11353SSaurabh.Mishra@Sun.COM */ 945*11353SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER, 946*11353SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri)); 947*11353SSaurabh.Mishra@Sun.COM 94810393SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_DOWN; 94910393SSaurabh.Mishra@Sun.COM atgep->atge_mtu = ETHERMTU; 95010393SSaurabh.Mishra@Sun.COM 951*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 952*11353SSaurabh.Mishra@Sun.COM if (atgep->atge_revid > 0xF0) { 953*11353SSaurabh.Mishra@Sun.COM /* L2E Rev. B. AR8114 */ 954*11353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_FASTETHER; 95510393SSaurabh.Mishra@Sun.COM } else { 956*11353SSaurabh.Mishra@Sun.COM if ((INL(atgep, L1E_PHY_STATUS) & 957*11353SSaurabh.Mishra@Sun.COM PHY_STATUS_100M) != 0) { 958*11353SSaurabh.Mishra@Sun.COM /* L1E AR8121 */ 959*11353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_JUMBO; 960*11353SSaurabh.Mishra@Sun.COM } else { 961*11353SSaurabh.Mishra@Sun.COM /* L2E Rev. A. AR8113 */ 962*11353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_FASTETHER; 963*11353SSaurabh.Mishra@Sun.COM } 96410393SSaurabh.Mishra@Sun.COM } 96510393SSaurabh.Mishra@Sun.COM } 96610393SSaurabh.Mishra@Sun.COM 96710393SSaurabh.Mishra@Sun.COM /* 96810393SSaurabh.Mishra@Sun.COM * Get DMA parameters from PCIe device control register. 96910393SSaurabh.Mishra@Sun.COM */ 97010393SSaurabh.Mishra@Sun.COM err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E, 97110393SSaurabh.Mishra@Sun.COM &cap_ptr); 97210393SSaurabh.Mishra@Sun.COM 97310393SSaurabh.Mishra@Sun.COM if (err == DDI_FAILURE) { 97410393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128; 97510393SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128; 97610393SSaurabh.Mishra@Sun.COM } else { 97710393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_PCIE; 97810393SSaurabh.Mishra@Sun.COM burst = pci_config_get16(atgep->atge_conf_handle, 97910393SSaurabh.Mishra@Sun.COM cap_ptr + 0x08); 98010393SSaurabh.Mishra@Sun.COM 98110393SSaurabh.Mishra@Sun.COM /* 98210393SSaurabh.Mishra@Sun.COM * Max read request size. 98310393SSaurabh.Mishra@Sun.COM */ 98410393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) << 98510393SSaurabh.Mishra@Sun.COM DMA_CFG_RD_BURST_SHIFT; 98610393SSaurabh.Mishra@Sun.COM 98710393SSaurabh.Mishra@Sun.COM /* 98810393SSaurabh.Mishra@Sun.COM * Max Payload Size. 98910393SSaurabh.Mishra@Sun.COM */ 99010393SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) << 99110393SSaurabh.Mishra@Sun.COM DMA_CFG_WR_BURST_SHIFT; 99210393SSaurabh.Mishra@Sun.COM 99310393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() MRR : %d, MPS : %d", 99410393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, 99510393SSaurabh.Mishra@Sun.COM (128 << ((burst >> 12) & 0x07)), 99610393SSaurabh.Mishra@Sun.COM (128 << ((burst >> 5) & 0x07)))); 99710393SSaurabh.Mishra@Sun.COM } 99810393SSaurabh.Mishra@Sun.COM 99910393SSaurabh.Mishra@Sun.COM /* 100010393SSaurabh.Mishra@Sun.COM * Allocate DMA resources. 100110393SSaurabh.Mishra@Sun.COM */ 100210393SSaurabh.Mishra@Sun.COM err = atge_alloc_dma(atgep); 1003*11353SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 100410393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "Failed to allocate DMA resources"); 100510393SSaurabh.Mishra@Sun.COM goto fail4; 100610393SSaurabh.Mishra@Sun.COM } 100710393SSaurabh.Mishra@Sun.COM 100810393SSaurabh.Mishra@Sun.COM /* 100910393SSaurabh.Mishra@Sun.COM * Get station address. 101010393SSaurabh.Mishra@Sun.COM */ 101110393SSaurabh.Mishra@Sun.COM (void) atge_get_macaddr(atgep); 101210393SSaurabh.Mishra@Sun.COM 101310393SSaurabh.Mishra@Sun.COM /* 101410393SSaurabh.Mishra@Sun.COM * Setup MII. 101510393SSaurabh.Mishra@Sun.COM */ 101610393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 101710393SSaurabh.Mishra@Sun.COM mii_ops = &atge_l1e_mii_ops; 1018*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1019*11353SSaurabh.Mishra@Sun.COM mii_ops = &atge_l1_mii_ops; 102010393SSaurabh.Mishra@Sun.COM } 102110393SSaurabh.Mishra@Sun.COM 102210393SSaurabh.Mishra@Sun.COM if ((atgep->atge_mii = mii_alloc(atgep, devinfo, 102310393SSaurabh.Mishra@Sun.COM mii_ops)) == NULL) { 102410393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mii_alloc() failed"); 102510393SSaurabh.Mishra@Sun.COM goto fail4; 102610393SSaurabh.Mishra@Sun.COM } 102710393SSaurabh.Mishra@Sun.COM 102810393SSaurabh.Mishra@Sun.COM /* 102910393SSaurabh.Mishra@Sun.COM * Register with MAC layer. 103010393SSaurabh.Mishra@Sun.COM */ 103110393SSaurabh.Mishra@Sun.COM if ((macreg = mac_alloc(MAC_VERSION)) == NULL) { 103210393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mac_alloc() failed due to version"); 103310393SSaurabh.Mishra@Sun.COM goto fail4; 103410393SSaurabh.Mishra@Sun.COM } 103510393SSaurabh.Mishra@Sun.COM 103610393SSaurabh.Mishra@Sun.COM macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 103710393SSaurabh.Mishra@Sun.COM macreg->m_driver = atgep; 103810393SSaurabh.Mishra@Sun.COM macreg->m_dip = devinfo; 103910393SSaurabh.Mishra@Sun.COM macreg->m_instance = instance; 104010393SSaurabh.Mishra@Sun.COM macreg->m_src_addr = atgep->atge_ether_addr; 104110393SSaurabh.Mishra@Sun.COM macreg->m_callbacks = &atge_m_callbacks; 104210393SSaurabh.Mishra@Sun.COM macreg->m_min_sdu = 0; 104310393SSaurabh.Mishra@Sun.COM macreg->m_max_sdu = atgep->atge_mtu; 104410393SSaurabh.Mishra@Sun.COM macreg->m_margin = VLAN_TAGSZ; 104510393SSaurabh.Mishra@Sun.COM 104610393SSaurabh.Mishra@Sun.COM if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) { 104710393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mac_register() failed with :%d", err); 104810393SSaurabh.Mishra@Sun.COM mac_free(macreg); 104910393SSaurabh.Mishra@Sun.COM goto fail4; 105010393SSaurabh.Mishra@Sun.COM } 105110393SSaurabh.Mishra@Sun.COM 105210393SSaurabh.Mishra@Sun.COM mac_free(macreg); 105310393SSaurabh.Mishra@Sun.COM 105410393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() driver attached successfully", 105510393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__)); 105610393SSaurabh.Mishra@Sun.COM 105710393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep); 105810393SSaurabh.Mishra@Sun.COM 105910393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state = ATGE_CHIP_INITIALIZED; 106010393SSaurabh.Mishra@Sun.COM 106110393SSaurabh.Mishra@Sun.COM /* 106210393SSaurabh.Mishra@Sun.COM * At last - enable interrupts. 106310393SSaurabh.Mishra@Sun.COM */ 106410393SSaurabh.Mishra@Sun.COM err = atge_enable_intrs(atgep); 1065*11353SSaurabh.Mishra@Sun.COM if (err == DDI_FAILURE) { 106610393SSaurabh.Mishra@Sun.COM goto fail5; 106710393SSaurabh.Mishra@Sun.COM } 106810393SSaurabh.Mishra@Sun.COM 106910393SSaurabh.Mishra@Sun.COM /* 107010393SSaurabh.Mishra@Sun.COM * Reset the PHY before starting. 107110393SSaurabh.Mishra@Sun.COM */ 107210393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 107310393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset(atgep); 1074*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1075*11353SSaurabh.Mishra@Sun.COM atge_l1_mii_reset(atgep); 107610393SSaurabh.Mishra@Sun.COM } 107710393SSaurabh.Mishra@Sun.COM 107810393SSaurabh.Mishra@Sun.COM /* 107910393SSaurabh.Mishra@Sun.COM * Let the PHY run. 108010393SSaurabh.Mishra@Sun.COM */ 108110393SSaurabh.Mishra@Sun.COM mii_start(atgep->atge_mii); 108210393SSaurabh.Mishra@Sun.COM 108310393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 108410393SSaurabh.Mishra@Sun.COM 108510393SSaurabh.Mishra@Sun.COM fail5: 108610393SSaurabh.Mishra@Sun.COM (void) mac_unregister(atgep->atge_mh); 108710393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 108810393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii); 108910393SSaurabh.Mishra@Sun.COM mii_free(atgep->atge_mii); 109010393SSaurabh.Mishra@Sun.COM fail4: 109110393SSaurabh.Mishra@Sun.COM atge_free_dma(atgep); 109210393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_intr_lock); 109310393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_tx_lock); 109410393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_rx_lock); 109510393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep); 109610393SSaurabh.Mishra@Sun.COM fail3: 109710393SSaurabh.Mishra@Sun.COM ddi_regs_map_free(&atgep->atge_io_handle); 109810393SSaurabh.Mishra@Sun.COM fail2: 109910393SSaurabh.Mishra@Sun.COM pci_config_teardown(&atgep->atge_conf_handle); 110010393SSaurabh.Mishra@Sun.COM fail1: 110110393SSaurabh.Mishra@Sun.COM if (atgep) 110210393SSaurabh.Mishra@Sun.COM kmem_free(atgep, sizeof (atge_t)); 110310393SSaurabh.Mishra@Sun.COM 110410393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 110510393SSaurabh.Mishra@Sun.COM } 110610393SSaurabh.Mishra@Sun.COM 110710393SSaurabh.Mishra@Sun.COM static int 110810393SSaurabh.Mishra@Sun.COM atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 110910393SSaurabh.Mishra@Sun.COM { 111010393SSaurabh.Mishra@Sun.COM atge_t *atgep; 111110393SSaurabh.Mishra@Sun.COM 111210393SSaurabh.Mishra@Sun.COM atgep = ddi_get_driver_private(dip); 111310393SSaurabh.Mishra@Sun.COM if (atgep == NULL) { 111410393SSaurabh.Mishra@Sun.COM atge_error(dip, "No soft state in detach"); 111510393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 111610393SSaurabh.Mishra@Sun.COM } 111710393SSaurabh.Mishra@Sun.COM 111810393SSaurabh.Mishra@Sun.COM switch (cmd) { 111910393SSaurabh.Mishra@Sun.COM case DDI_DETACH: 112010393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii); 112110393SSaurabh.Mishra@Sun.COM 112210393SSaurabh.Mishra@Sun.COM /* 112310393SSaurabh.Mishra@Sun.COM * First unregister with MAC layer before stopping DMA 112410393SSaurabh.Mishra@Sun.COM */ 112510393SSaurabh.Mishra@Sun.COM if (mac_unregister(atgep->atge_mh) != DDI_SUCCESS) 112610393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 112710393SSaurabh.Mishra@Sun.COM 112810393SSaurabh.Mishra@Sun.COM atgep->atge_mh = NULL; 112910393SSaurabh.Mishra@Sun.COM 113010393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 113110393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 113210393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 113310393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 113410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 113510393SSaurabh.Mishra@Sun.COM 113610393SSaurabh.Mishra@Sun.COM mii_free(atgep->atge_mii); 113710393SSaurabh.Mishra@Sun.COM atge_free_dma(atgep); 113810393SSaurabh.Mishra@Sun.COM 113910393SSaurabh.Mishra@Sun.COM ddi_regs_map_free(&atgep->atge_io_handle); 114010393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep); 114110393SSaurabh.Mishra@Sun.COM pci_config_teardown(&atgep->atge_conf_handle); 114210393SSaurabh.Mishra@Sun.COM 114310393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_intr_lock); 114410393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_tx_lock); 114510393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_rx_lock); 114610393SSaurabh.Mishra@Sun.COM kmem_free(atgep, sizeof (atge_t)); 114710393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(dip, NULL); 114810393SSaurabh.Mishra@Sun.COM 114910393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 115010393SSaurabh.Mishra@Sun.COM 115110393SSaurabh.Mishra@Sun.COM case DDI_SUSPEND: 115210393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() is being suspended", 115310393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__)); 115410393SSaurabh.Mishra@Sun.COM 115510393SSaurabh.Mishra@Sun.COM /* 115610393SSaurabh.Mishra@Sun.COM * Suspend monitoring MII. 115710393SSaurabh.Mishra@Sun.COM */ 115810393SSaurabh.Mishra@Sun.COM mii_suspend(atgep->atge_mii); 115910393SSaurabh.Mishra@Sun.COM 116010393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 116110393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 116210393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED; 116310393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 116410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 116510393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 116610393SSaurabh.Mishra@Sun.COM 116710393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 116810393SSaurabh.Mishra@Sun.COM 116910393SSaurabh.Mishra@Sun.COM default: 117010393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 117110393SSaurabh.Mishra@Sun.COM } 117210393SSaurabh.Mishra@Sun.COM } 117310393SSaurabh.Mishra@Sun.COM 117410393SSaurabh.Mishra@Sun.COM int 117510393SSaurabh.Mishra@Sun.COM atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f) 117610393SSaurabh.Mishra@Sun.COM { 117710393SSaurabh.Mishra@Sun.COM atge_dma_t *dma; 117810393SSaurabh.Mishra@Sun.COM atge_dma_t **tbl; 1179*11353SSaurabh.Mishra@Sun.COM int err = DDI_SUCCESS; 118010393SSaurabh.Mishra@Sun.COM int i; 118110393SSaurabh.Mishra@Sun.COM 118210393SSaurabh.Mishra@Sun.COM tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP); 118310393SSaurabh.Mishra@Sun.COM r->r_buf_tbl = tbl; 118410393SSaurabh.Mishra@Sun.COM 118510393SSaurabh.Mishra@Sun.COM for (i = 0; i < rcnt; i++) { 118610393SSaurabh.Mishra@Sun.COM dma = atge_buf_alloc(r->r_atge, buflen, f); 118710393SSaurabh.Mishra@Sun.COM if (dma == NULL) { 1188*11353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE; 118910393SSaurabh.Mishra@Sun.COM break; 119010393SSaurabh.Mishra@Sun.COM } 119110393SSaurabh.Mishra@Sun.COM 119210393SSaurabh.Mishra@Sun.COM tbl[i] = dma; 119310393SSaurabh.Mishra@Sun.COM } 119410393SSaurabh.Mishra@Sun.COM 119510393SSaurabh.Mishra@Sun.COM return (err); 119610393SSaurabh.Mishra@Sun.COM } 119710393SSaurabh.Mishra@Sun.COM 119810393SSaurabh.Mishra@Sun.COM void 119910393SSaurabh.Mishra@Sun.COM atge_free_buffers(atge_ring_t *r, size_t rcnt) 120010393SSaurabh.Mishra@Sun.COM { 120110393SSaurabh.Mishra@Sun.COM atge_dma_t **tbl; 120210393SSaurabh.Mishra@Sun.COM int i; 120310393SSaurabh.Mishra@Sun.COM 120410393SSaurabh.Mishra@Sun.COM if (r == NULL || r->r_buf_tbl == NULL) 120510393SSaurabh.Mishra@Sun.COM return; 120610393SSaurabh.Mishra@Sun.COM 120710393SSaurabh.Mishra@Sun.COM tbl = r->r_buf_tbl; 120810393SSaurabh.Mishra@Sun.COM for (i = 0; i < rcnt; i++) { 120910393SSaurabh.Mishra@Sun.COM if (tbl[i] != NULL) { 121010393SSaurabh.Mishra@Sun.COM atge_buf_free(tbl[i]); 121110393SSaurabh.Mishra@Sun.COM } 121210393SSaurabh.Mishra@Sun.COM } 121310393SSaurabh.Mishra@Sun.COM 121410393SSaurabh.Mishra@Sun.COM kmem_free(tbl, rcnt * sizeof (atge_dma_t *)); 121510393SSaurabh.Mishra@Sun.COM } 121610393SSaurabh.Mishra@Sun.COM 121710393SSaurabh.Mishra@Sun.COM atge_dma_t * 121810393SSaurabh.Mishra@Sun.COM atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d) 121910393SSaurabh.Mishra@Sun.COM { 122010393SSaurabh.Mishra@Sun.COM int err; 122110393SSaurabh.Mishra@Sun.COM atge_dma_t *dma; 122210393SSaurabh.Mishra@Sun.COM 122310393SSaurabh.Mishra@Sun.COM dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP); 122410393SSaurabh.Mishra@Sun.COM 122510393SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(atgep->atge_dip, attr, 122610393SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &dma->hdl); 122710393SSaurabh.Mishra@Sun.COM 122810393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 122910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 123010393SSaurabh.Mishra@Sun.COM " in ddi_dma_alloc_handle() : %d", __func__, err); 123110393SSaurabh.Mishra@Sun.COM goto fail; 123210393SSaurabh.Mishra@Sun.COM } 123310393SSaurabh.Mishra@Sun.COM 123410393SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(dma->hdl, 123510393SSaurabh.Mishra@Sun.COM size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 123610393SSaurabh.Mishra@Sun.COM &dma->addr, &dma->len, &dma->acchdl); 123710393SSaurabh.Mishra@Sun.COM 123810393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 123910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 124010393SSaurabh.Mishra@Sun.COM " in ddi_dma_mem_alloc() : %d", __func__, err); 124110393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 124210393SSaurabh.Mishra@Sun.COM goto fail; 124310393SSaurabh.Mishra@Sun.COM } 124410393SSaurabh.Mishra@Sun.COM 124510393SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, 124610393SSaurabh.Mishra@Sun.COM dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 124710393SSaurabh.Mishra@Sun.COM NULL, &dma->cookie, &dma->count); 124810393SSaurabh.Mishra@Sun.COM 124910393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 125010393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 125110393SSaurabh.Mishra@Sun.COM " in ddi_dma_addr_bind_handle() : %d", __func__, err); 125210393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl); 125310393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 125410393SSaurabh.Mishra@Sun.COM goto fail; 125510393SSaurabh.Mishra@Sun.COM } 125610393SSaurabh.Mishra@Sun.COM 125710393SSaurabh.Mishra@Sun.COM return (dma); 125810393SSaurabh.Mishra@Sun.COM fail: 125910393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t)); 126010393SSaurabh.Mishra@Sun.COM return (NULL); 126110393SSaurabh.Mishra@Sun.COM } 126210393SSaurabh.Mishra@Sun.COM 126310393SSaurabh.Mishra@Sun.COM void 126410393SSaurabh.Mishra@Sun.COM atge_free_a_dma_blk(atge_dma_t *dma) 126510393SSaurabh.Mishra@Sun.COM { 126610393SSaurabh.Mishra@Sun.COM if (dma != NULL) { 126710393SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(dma->hdl); 126810393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl); 126910393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 127010393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t)); 127110393SSaurabh.Mishra@Sun.COM } 127210393SSaurabh.Mishra@Sun.COM } 127310393SSaurabh.Mishra@Sun.COM 127410393SSaurabh.Mishra@Sun.COM atge_dma_t * 127510393SSaurabh.Mishra@Sun.COM atge_buf_alloc(atge_t *atgep, size_t len, int f) 127610393SSaurabh.Mishra@Sun.COM { 127710393SSaurabh.Mishra@Sun.COM atge_dma_t *dma = NULL; 127810393SSaurabh.Mishra@Sun.COM int err; 127910393SSaurabh.Mishra@Sun.COM 128010393SSaurabh.Mishra@Sun.COM dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP); 128110393SSaurabh.Mishra@Sun.COM 128210393SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf, 128310393SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &dma->hdl); 128410393SSaurabh.Mishra@Sun.COM 128510393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 128610393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 128710393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err); 128810393SSaurabh.Mishra@Sun.COM goto fail; 128910393SSaurabh.Mishra@Sun.COM } 129010393SSaurabh.Mishra@Sun.COM 129110393SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr, 129210393SSaurabh.Mishra@Sun.COM DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr, 129310393SSaurabh.Mishra@Sun.COM &dma->len, &dma->acchdl); 129410393SSaurabh.Mishra@Sun.COM 129510393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 129610393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 129710393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err); 129810393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 129910393SSaurabh.Mishra@Sun.COM goto fail; 130010393SSaurabh.Mishra@Sun.COM } 130110393SSaurabh.Mishra@Sun.COM 130210393SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len, 130310393SSaurabh.Mishra@Sun.COM (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie, 130410393SSaurabh.Mishra@Sun.COM &dma->count); 130510393SSaurabh.Mishra@Sun.COM 130610393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) { 130710393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed" 130810393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err); 130910393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl); 131010393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 131110393SSaurabh.Mishra@Sun.COM goto fail; 131210393SSaurabh.Mishra@Sun.COM } 131310393SSaurabh.Mishra@Sun.COM 131410393SSaurabh.Mishra@Sun.COM /* 131510393SSaurabh.Mishra@Sun.COM * Number of return'ed cookie should be one. 131610393SSaurabh.Mishra@Sun.COM */ 131710393SSaurabh.Mishra@Sun.COM ASSERT(dma->count == 1); 131810393SSaurabh.Mishra@Sun.COM 131910393SSaurabh.Mishra@Sun.COM return (dma); 132010393SSaurabh.Mishra@Sun.COM fail: 132110393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t)); 132210393SSaurabh.Mishra@Sun.COM return (NULL); 132310393SSaurabh.Mishra@Sun.COM } 132410393SSaurabh.Mishra@Sun.COM 132510393SSaurabh.Mishra@Sun.COM void 132610393SSaurabh.Mishra@Sun.COM atge_buf_free(atge_dma_t *dma) 132710393SSaurabh.Mishra@Sun.COM { 132810393SSaurabh.Mishra@Sun.COM ASSERT(dma != NULL); 132910393SSaurabh.Mishra@Sun.COM 133010393SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(dma->hdl); 133110393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl); 133210393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl); 133310393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t)); 133410393SSaurabh.Mishra@Sun.COM } 133510393SSaurabh.Mishra@Sun.COM 133610393SSaurabh.Mishra@Sun.COM static int 133710393SSaurabh.Mishra@Sun.COM atge_resume(dev_info_t *dip) 133810393SSaurabh.Mishra@Sun.COM { 133910393SSaurabh.Mishra@Sun.COM atge_t *atgep; 134010393SSaurabh.Mishra@Sun.COM 134110393SSaurabh.Mishra@Sun.COM if ((atgep = ddi_get_driver_private(dip)) == NULL) { 134210393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 134310393SSaurabh.Mishra@Sun.COM } 134410393SSaurabh.Mishra@Sun.COM 134510393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 134610393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 134710393SSaurabh.Mishra@Sun.COM 134810393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED; 134910393SSaurabh.Mishra@Sun.COM 135010393SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) { 135110393SSaurabh.Mishra@Sun.COM atge_device_restart(atgep); 135210393SSaurabh.Mishra@Sun.COM } else { 135310393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep); 135410393SSaurabh.Mishra@Sun.COM } 135510393SSaurabh.Mishra@Sun.COM 135610393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 135710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 135810393SSaurabh.Mishra@Sun.COM 135910393SSaurabh.Mishra@Sun.COM /* 136010393SSaurabh.Mishra@Sun.COM * Reset the PHY before resuming MII. 136110393SSaurabh.Mishra@Sun.COM */ 136210393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 136310393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset(atgep); 136410393SSaurabh.Mishra@Sun.COM } 136510393SSaurabh.Mishra@Sun.COM 136610393SSaurabh.Mishra@Sun.COM mii_resume(atgep->atge_mii); 136710393SSaurabh.Mishra@Sun.COM 136810393SSaurabh.Mishra@Sun.COM /* kick-off downstream */ 136910393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh); 137010393SSaurabh.Mishra@Sun.COM 137110393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 137210393SSaurabh.Mishra@Sun.COM } 137310393SSaurabh.Mishra@Sun.COM 137410393SSaurabh.Mishra@Sun.COM static int 137510393SSaurabh.Mishra@Sun.COM atge_quiesce(dev_info_t *dip) 137610393SSaurabh.Mishra@Sun.COM { 137710393SSaurabh.Mishra@Sun.COM atge_t *atgep; 137810393SSaurabh.Mishra@Sun.COM 137910393SSaurabh.Mishra@Sun.COM if ((atgep = ddi_get_driver_private(dip)) == NULL) { 138010393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 138110393SSaurabh.Mishra@Sun.COM } 138210393SSaurabh.Mishra@Sun.COM 138310393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 138410393SSaurabh.Mishra@Sun.COM 138510393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 138610393SSaurabh.Mishra@Sun.COM } 138710393SSaurabh.Mishra@Sun.COM 138810393SSaurabh.Mishra@Sun.COM void 138910393SSaurabh.Mishra@Sun.COM atge_add_multicst(atge_t *atgep, uint8_t *macaddr) 139010393SSaurabh.Mishra@Sun.COM { 139110393SSaurabh.Mishra@Sun.COM uint32_t crc; 139210393SSaurabh.Mishra@Sun.COM int bit; 139310393SSaurabh.Mishra@Sun.COM 139410393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock)); 139510393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock)); 139610393SSaurabh.Mishra@Sun.COM 139710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x", 139810393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2], 139910393SSaurabh.Mishra@Sun.COM macaddr[3], macaddr[4], macaddr[5])); 140010393SSaurabh.Mishra@Sun.COM 140110393SSaurabh.Mishra@Sun.COM crc = atge_ether_crc(macaddr, ETHERADDRL); 140210393SSaurabh.Mishra@Sun.COM bit = (crc >> 26); 140310393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]++; 140410393SSaurabh.Mishra@Sun.COM atgep->atge_mchash |= (1ULL << (crc >> 26)); 140510393SSaurabh.Mishra@Sun.COM 140610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mchash :%llx, bit : %d," 140710393SSaurabh.Mishra@Sun.COM " atge_mchash_ref_cnt[bit] :%d", 140810393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_mchash, bit, 140910393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit])); 141010393SSaurabh.Mishra@Sun.COM } 141110393SSaurabh.Mishra@Sun.COM 141210393SSaurabh.Mishra@Sun.COM void 141310393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atge_t *atgep, uint8_t *macaddr) 141410393SSaurabh.Mishra@Sun.COM { 141510393SSaurabh.Mishra@Sun.COM uint32_t crc; 141610393SSaurabh.Mishra@Sun.COM int bit; 141710393SSaurabh.Mishra@Sun.COM 141810393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock)); 141910393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock)); 142010393SSaurabh.Mishra@Sun.COM 142110393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x", 142210393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2], 142310393SSaurabh.Mishra@Sun.COM macaddr[3], macaddr[4], macaddr[5])); 142410393SSaurabh.Mishra@Sun.COM 142510393SSaurabh.Mishra@Sun.COM crc = atge_ether_crc(macaddr, ETHERADDRL); 142610393SSaurabh.Mishra@Sun.COM bit = (crc >> 26); 142710393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]--; 142810393SSaurabh.Mishra@Sun.COM if (atgep->atge_mchash_ref_cnt[bit] == 0) 142910393SSaurabh.Mishra@Sun.COM atgep->atge_mchash &= ~(1ULL << (crc >> 26)); 143010393SSaurabh.Mishra@Sun.COM 143110393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mchash :%llx, bit : %d," 143210393SSaurabh.Mishra@Sun.COM " atge_mchash_ref_cnt[bit] :%d", 143310393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_mchash, bit, 143410393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit])); 143510393SSaurabh.Mishra@Sun.COM } 143610393SSaurabh.Mishra@Sun.COM 143710393SSaurabh.Mishra@Sun.COM int 143810393SSaurabh.Mishra@Sun.COM atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 143910393SSaurabh.Mishra@Sun.COM { 144010393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 144110393SSaurabh.Mishra@Sun.COM 144210393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 144310393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 144410393SSaurabh.Mishra@Sun.COM 144510393SSaurabh.Mishra@Sun.COM if (add) { 144610393SSaurabh.Mishra@Sun.COM atge_add_multicst(atgep, (uint8_t *)macaddr); 144710393SSaurabh.Mishra@Sun.COM } else { 144810393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atgep, (uint8_t *)macaddr); 144910393SSaurabh.Mishra@Sun.COM } 145010393SSaurabh.Mishra@Sun.COM 145110393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep); 145210393SSaurabh.Mishra@Sun.COM 145310393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 145410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 145510393SSaurabh.Mishra@Sun.COM 145610393SSaurabh.Mishra@Sun.COM return (0); 145710393SSaurabh.Mishra@Sun.COM } 145810393SSaurabh.Mishra@Sun.COM 145910393SSaurabh.Mishra@Sun.COM int 146010393SSaurabh.Mishra@Sun.COM atge_m_promisc(void *arg, boolean_t on) 146110393SSaurabh.Mishra@Sun.COM { 146210393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 146310393SSaurabh.Mishra@Sun.COM 146410393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 146510393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 146610393SSaurabh.Mishra@Sun.COM 146710393SSaurabh.Mishra@Sun.COM if (on) { 146810393SSaurabh.Mishra@Sun.COM atgep->atge_filter_flags |= ATGE_PROMISC; 146910393SSaurabh.Mishra@Sun.COM } else { 147010393SSaurabh.Mishra@Sun.COM atgep->atge_filter_flags &= ~ATGE_PROMISC; 147110393SSaurabh.Mishra@Sun.COM } 147210393SSaurabh.Mishra@Sun.COM 147310393SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) { 147410393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep); 147510393SSaurabh.Mishra@Sun.COM } 147610393SSaurabh.Mishra@Sun.COM 147710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 147810393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 147910393SSaurabh.Mishra@Sun.COM 148010393SSaurabh.Mishra@Sun.COM return (0); 148110393SSaurabh.Mishra@Sun.COM } 148210393SSaurabh.Mishra@Sun.COM 148310393SSaurabh.Mishra@Sun.COM int 148410393SSaurabh.Mishra@Sun.COM atge_m_unicst(void *arg, const uint8_t *macaddr) 148510393SSaurabh.Mishra@Sun.COM { 148610393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 148710393SSaurabh.Mishra@Sun.COM 148810393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 148910393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 149010393SSaurabh.Mishra@Sun.COM bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL); 149110393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep); 149210393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep); 149310393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 149410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 149510393SSaurabh.Mishra@Sun.COM 149610393SSaurabh.Mishra@Sun.COM return (0); 149710393SSaurabh.Mishra@Sun.COM } 149810393SSaurabh.Mishra@Sun.COM 149910393SSaurabh.Mishra@Sun.COM mblk_t * 150010393SSaurabh.Mishra@Sun.COM atge_m_tx(void *arg, mblk_t *mp) 150110393SSaurabh.Mishra@Sun.COM { 150210393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 150310393SSaurabh.Mishra@Sun.COM mblk_t *nmp; 150410393SSaurabh.Mishra@Sun.COM 150510393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 150610393SSaurabh.Mishra@Sun.COM 150710393SSaurabh.Mishra@Sun.COM /* 150810393SSaurabh.Mishra@Sun.COM * This NIC does not like us to send pkt when link is down. 150910393SSaurabh.Mishra@Sun.COM */ 151010393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_link_state & LINK_STATE_UP)) { 151110393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1; 1512*11353SSaurabh.Mishra@Sun.COM 151310393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 151410393SSaurabh.Mishra@Sun.COM return (mp); 151510393SSaurabh.Mishra@Sun.COM } 151610393SSaurabh.Mishra@Sun.COM 151710393SSaurabh.Mishra@Sun.COM /* 151810393SSaurabh.Mishra@Sun.COM * Don't send a pkt if chip isn't running or in suspended state. 151910393SSaurabh.Mishra@Sun.COM */ 152010393SSaurabh.Mishra@Sun.COM if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 || 152110393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) { 152210393SSaurabh.Mishra@Sun.COM atgep->atge_carrier_errors++; 152310393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1; 1524*11353SSaurabh.Mishra@Sun.COM 152510393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 152610393SSaurabh.Mishra@Sun.COM return (mp); 152710393SSaurabh.Mishra@Sun.COM } 152810393SSaurabh.Mishra@Sun.COM 152910393SSaurabh.Mishra@Sun.COM while (mp != NULL) { 153010393SSaurabh.Mishra@Sun.COM nmp = mp->b_next; 153110393SSaurabh.Mishra@Sun.COM mp->b_next = NULL; 153210393SSaurabh.Mishra@Sun.COM 1533*11353SSaurabh.Mishra@Sun.COM if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) { 153410393SSaurabh.Mishra@Sun.COM mp->b_next = nmp; 153510393SSaurabh.Mishra@Sun.COM break; 153610393SSaurabh.Mishra@Sun.COM } 153710393SSaurabh.Mishra@Sun.COM 153810393SSaurabh.Mishra@Sun.COM mp = nmp; 153910393SSaurabh.Mishra@Sun.COM } 154010393SSaurabh.Mishra@Sun.COM 154110393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 154210393SSaurabh.Mishra@Sun.COM return (mp); 154310393SSaurabh.Mishra@Sun.COM } 154410393SSaurabh.Mishra@Sun.COM 154510393SSaurabh.Mishra@Sun.COM int 154610393SSaurabh.Mishra@Sun.COM atge_m_start(void *arg) 154710393SSaurabh.Mishra@Sun.COM { 154810393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 154910393SSaurabh.Mishra@Sun.COM int started = 0; 155010393SSaurabh.Mishra@Sun.COM 155110393SSaurabh.Mishra@Sun.COM ASSERT(atgep != NULL); 155210393SSaurabh.Mishra@Sun.COM 155310393SSaurabh.Mishra@Sun.COM 155410393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii); 155510393SSaurabh.Mishra@Sun.COM 155610393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 155710393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 155810393SSaurabh.Mishra@Sun.COM 155910393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) { 156010393SSaurabh.Mishra@Sun.COM atge_device_restart(atgep); 156110393SSaurabh.Mishra@Sun.COM started = 1; 156210393SSaurabh.Mishra@Sun.COM } 156310393SSaurabh.Mishra@Sun.COM 156410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 156510393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 156610393SSaurabh.Mishra@Sun.COM 156710393SSaurabh.Mishra@Sun.COM mii_start(atgep->atge_mii); 156810393SSaurabh.Mishra@Sun.COM 156910393SSaurabh.Mishra@Sun.COM /* kick-off downstream */ 157010393SSaurabh.Mishra@Sun.COM if (started) 157110393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh); 157210393SSaurabh.Mishra@Sun.COM 157310393SSaurabh.Mishra@Sun.COM return (0); 157410393SSaurabh.Mishra@Sun.COM } 157510393SSaurabh.Mishra@Sun.COM 157610393SSaurabh.Mishra@Sun.COM void 157710393SSaurabh.Mishra@Sun.COM atge_m_stop(void *arg) 157810393SSaurabh.Mishra@Sun.COM { 157910393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 158010393SSaurabh.Mishra@Sun.COM 158110393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii); 158210393SSaurabh.Mishra@Sun.COM 158310393SSaurabh.Mishra@Sun.COM /* 158410393SSaurabh.Mishra@Sun.COM * Cancel any pending I/O. 158510393SSaurabh.Mishra@Sun.COM */ 158610393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 158710393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING; 158810393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) 158910393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 159010393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 159110393SSaurabh.Mishra@Sun.COM } 159210393SSaurabh.Mishra@Sun.COM 159310393SSaurabh.Mishra@Sun.COM int 159410393SSaurabh.Mishra@Sun.COM atge_m_stat(void *arg, uint_t stat, uint64_t *val) 159510393SSaurabh.Mishra@Sun.COM { 159610393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 159710393SSaurabh.Mishra@Sun.COM 159810393SSaurabh.Mishra@Sun.COM if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) { 159910393SSaurabh.Mishra@Sun.COM return (0); 160010393SSaurabh.Mishra@Sun.COM } 160110393SSaurabh.Mishra@Sun.COM 160210393SSaurabh.Mishra@Sun.COM switch (stat) { 160310393SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIRCV: 160410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multircv; 160510393SSaurabh.Mishra@Sun.COM break; 160610393SSaurabh.Mishra@Sun.COM 160710393SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTRCV: 160810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_brdcstrcv; 160910393SSaurabh.Mishra@Sun.COM break; 161010393SSaurabh.Mishra@Sun.COM 161110393SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIXMT: 161210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multixmt; 161310393SSaurabh.Mishra@Sun.COM break; 161410393SSaurabh.Mishra@Sun.COM 161510393SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTXMT: 161610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_brdcstxmt; 161710393SSaurabh.Mishra@Sun.COM break; 161810393SSaurabh.Mishra@Sun.COM 161910393SSaurabh.Mishra@Sun.COM case MAC_STAT_IPACKETS: 162010393SSaurabh.Mishra@Sun.COM *val = atgep->atge_ipackets; 162110393SSaurabh.Mishra@Sun.COM break; 162210393SSaurabh.Mishra@Sun.COM 162310393SSaurabh.Mishra@Sun.COM case MAC_STAT_RBYTES: 162410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_rbytes; 162510393SSaurabh.Mishra@Sun.COM break; 162610393SSaurabh.Mishra@Sun.COM 162710393SSaurabh.Mishra@Sun.COM case MAC_STAT_OPACKETS: 162810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_opackets; 162910393SSaurabh.Mishra@Sun.COM break; 163010393SSaurabh.Mishra@Sun.COM 163110393SSaurabh.Mishra@Sun.COM case MAC_STAT_OBYTES: 163210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_obytes; 163310393SSaurabh.Mishra@Sun.COM break; 163410393SSaurabh.Mishra@Sun.COM 163510393SSaurabh.Mishra@Sun.COM case MAC_STAT_NORCVBUF: 163610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_norcvbuf; 163710393SSaurabh.Mishra@Sun.COM break; 163810393SSaurabh.Mishra@Sun.COM 163910393SSaurabh.Mishra@Sun.COM case MAC_STAT_NOXMTBUF: 164010393SSaurabh.Mishra@Sun.COM *val = 0; 164110393SSaurabh.Mishra@Sun.COM break; 164210393SSaurabh.Mishra@Sun.COM 164310393SSaurabh.Mishra@Sun.COM case MAC_STAT_COLLISIONS: 164410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_collisions; 164510393SSaurabh.Mishra@Sun.COM break; 164610393SSaurabh.Mishra@Sun.COM 164710393SSaurabh.Mishra@Sun.COM case MAC_STAT_IERRORS: 164810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_errrcv; 164910393SSaurabh.Mishra@Sun.COM break; 165010393SSaurabh.Mishra@Sun.COM 165110393SSaurabh.Mishra@Sun.COM case MAC_STAT_OERRORS: 165210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_errxmt; 165310393SSaurabh.Mishra@Sun.COM break; 165410393SSaurabh.Mishra@Sun.COM 165510393SSaurabh.Mishra@Sun.COM case ETHER_STAT_ALIGN_ERRORS: 165610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_align_errors; 165710393SSaurabh.Mishra@Sun.COM break; 165810393SSaurabh.Mishra@Sun.COM 165910393SSaurabh.Mishra@Sun.COM case ETHER_STAT_FCS_ERRORS: 166010393SSaurabh.Mishra@Sun.COM *val = atgep->atge_fcs_errors; 166110393SSaurabh.Mishra@Sun.COM break; 166210393SSaurabh.Mishra@Sun.COM 166310393SSaurabh.Mishra@Sun.COM case ETHER_STAT_SQE_ERRORS: 166410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_sqe_errors; 166510393SSaurabh.Mishra@Sun.COM break; 166610393SSaurabh.Mishra@Sun.COM 166710393SSaurabh.Mishra@Sun.COM case ETHER_STAT_DEFER_XMTS: 166810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_defer_xmts; 166910393SSaurabh.Mishra@Sun.COM break; 167010393SSaurabh.Mishra@Sun.COM 167110393SSaurabh.Mishra@Sun.COM case ETHER_STAT_FIRST_COLLISIONS: 167210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_first_collisions; 167310393SSaurabh.Mishra@Sun.COM break; 167410393SSaurabh.Mishra@Sun.COM 167510393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MULTI_COLLISIONS: 167610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multi_collisions; 167710393SSaurabh.Mishra@Sun.COM break; 167810393SSaurabh.Mishra@Sun.COM 167910393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS: 168010393SSaurabh.Mishra@Sun.COM *val = atgep->atge_tx_late_collisions; 168110393SSaurabh.Mishra@Sun.COM break; 168210393SSaurabh.Mishra@Sun.COM 168310393SSaurabh.Mishra@Sun.COM case ETHER_STAT_EX_COLLISIONS: 168410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_ex_collisions; 168510393SSaurabh.Mishra@Sun.COM break; 168610393SSaurabh.Mishra@Sun.COM 168710393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACXMT_ERRORS: 168810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_macxmt_errors; 168910393SSaurabh.Mishra@Sun.COM break; 169010393SSaurabh.Mishra@Sun.COM 169110393SSaurabh.Mishra@Sun.COM case ETHER_STAT_CARRIER_ERRORS: 169210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_carrier_errors; 169310393SSaurabh.Mishra@Sun.COM break; 169410393SSaurabh.Mishra@Sun.COM 169510393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOLONG_ERRORS: 169610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_toolong_errors; 169710393SSaurabh.Mishra@Sun.COM break; 169810393SSaurabh.Mishra@Sun.COM 169910393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACRCV_ERRORS: 170010393SSaurabh.Mishra@Sun.COM *val = atgep->atge_macrcv_errors; 170110393SSaurabh.Mishra@Sun.COM break; 170210393SSaurabh.Mishra@Sun.COM 170310393SSaurabh.Mishra@Sun.COM case MAC_STAT_OVERFLOWS: 170410393SSaurabh.Mishra@Sun.COM *val = atgep->atge_overflow; 170510393SSaurabh.Mishra@Sun.COM break; 170610393SSaurabh.Mishra@Sun.COM 170710393SSaurabh.Mishra@Sun.COM case MAC_STAT_UNDERFLOWS: 170810393SSaurabh.Mishra@Sun.COM *val = atgep->atge_underflow; 170910393SSaurabh.Mishra@Sun.COM break; 171010393SSaurabh.Mishra@Sun.COM 171110393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS: 171210393SSaurabh.Mishra@Sun.COM *val = atgep->atge_runt; 171310393SSaurabh.Mishra@Sun.COM break; 171410393SSaurabh.Mishra@Sun.COM 171510393SSaurabh.Mishra@Sun.COM case ETHER_STAT_JABBER_ERRORS: 171610393SSaurabh.Mishra@Sun.COM *val = atgep->atge_jabber; 171710393SSaurabh.Mishra@Sun.COM break; 171810393SSaurabh.Mishra@Sun.COM 171910393SSaurabh.Mishra@Sun.COM default: 172010393SSaurabh.Mishra@Sun.COM return (ENOTSUP); 172110393SSaurabh.Mishra@Sun.COM } 172210393SSaurabh.Mishra@Sun.COM 172310393SSaurabh.Mishra@Sun.COM return (0); 172410393SSaurabh.Mishra@Sun.COM } 172510393SSaurabh.Mishra@Sun.COM 172610393SSaurabh.Mishra@Sun.COM int 172710393SSaurabh.Mishra@Sun.COM atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 172810393SSaurabh.Mishra@Sun.COM uint_t sz, void *val, uint_t *perm) 172910393SSaurabh.Mishra@Sun.COM { 173010393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 173110393SSaurabh.Mishra@Sun.COM 173210393SSaurabh.Mishra@Sun.COM return (mii_m_getprop(atgep->atge_mii, name, num, flags, sz, val, 173310393SSaurabh.Mishra@Sun.COM perm)); 173410393SSaurabh.Mishra@Sun.COM } 173510393SSaurabh.Mishra@Sun.COM 173610393SSaurabh.Mishra@Sun.COM int 173710393SSaurabh.Mishra@Sun.COM atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 173810393SSaurabh.Mishra@Sun.COM const void *val) 173910393SSaurabh.Mishra@Sun.COM { 174010393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg; 1741*11353SSaurabh.Mishra@Sun.COM int r; 1742*11353SSaurabh.Mishra@Sun.COM 1743*11353SSaurabh.Mishra@Sun.COM r = mii_m_setprop(atgep->atge_mii, name, num, sz, val); 1744*11353SSaurabh.Mishra@Sun.COM 1745*11353SSaurabh.Mishra@Sun.COM if (r == 0) { 1746*11353SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock); 1747*11353SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock); 1748*11353SSaurabh.Mishra@Sun.COM 1749*11353SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) { 1750*11353SSaurabh.Mishra@Sun.COM atge_device_restart(atgep); 1751*11353SSaurabh.Mishra@Sun.COM } 1752*11353SSaurabh.Mishra@Sun.COM 1753*11353SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock); 1754*11353SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock); 1755*11353SSaurabh.Mishra@Sun.COM } 1756*11353SSaurabh.Mishra@Sun.COM 1757*11353SSaurabh.Mishra@Sun.COM return (r); 175810393SSaurabh.Mishra@Sun.COM } 175910393SSaurabh.Mishra@Sun.COM 176010393SSaurabh.Mishra@Sun.COM 176110393SSaurabh.Mishra@Sun.COM void 176210393SSaurabh.Mishra@Sun.COM atge_program_ether(atge_t *atgep) 176310393SSaurabh.Mishra@Sun.COM { 176410393SSaurabh.Mishra@Sun.COM ether_addr_t e; 176510393SSaurabh.Mishra@Sun.COM 176610393SSaurabh.Mishra@Sun.COM /* 176710393SSaurabh.Mishra@Sun.COM * Reprogram the Station address. 176810393SSaurabh.Mishra@Sun.COM */ 176910393SSaurabh.Mishra@Sun.COM bcopy(atgep->atge_ether_addr, e, ETHERADDRL); 177010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_PAR0, 177110393SSaurabh.Mishra@Sun.COM ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5])); 177210393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]); 177310393SSaurabh.Mishra@Sun.COM } 177410393SSaurabh.Mishra@Sun.COM 177510393SSaurabh.Mishra@Sun.COM /* 177610393SSaurabh.Mishra@Sun.COM * Device specific operations. 177710393SSaurabh.Mishra@Sun.COM */ 177810393SSaurabh.Mishra@Sun.COM void 177910393SSaurabh.Mishra@Sun.COM atge_device_start(atge_t *atgep) 178010393SSaurabh.Mishra@Sun.COM { 1781*11353SSaurabh.Mishra@Sun.COM uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo; 178210393SSaurabh.Mishra@Sun.COM uint32_t reg; 178310393SSaurabh.Mishra@Sun.COM uint32_t fsize; 178410393SSaurabh.Mishra@Sun.COM 178510393SSaurabh.Mishra@Sun.COM /* 178610393SSaurabh.Mishra@Sun.COM * Reprogram the Station address. 178710393SSaurabh.Mishra@Sun.COM */ 178810393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep); 178910393SSaurabh.Mishra@Sun.COM 179010393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 179110393SSaurabh.Mishra@Sun.COM atge_l1e_program_dma(atgep); 1792*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1793*11353SSaurabh.Mishra@Sun.COM atge_l1_program_dma(atgep); 179410393SSaurabh.Mishra@Sun.COM } 179510393SSaurabh.Mishra@Sun.COM 179610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name, 179710393SSaurabh.Mishra@Sun.COM __func__)); 179810393SSaurabh.Mishra@Sun.COM 179910393SSaurabh.Mishra@Sun.COM OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2); 180010393SSaurabh.Mishra@Sun.COM 180110393SSaurabh.Mishra@Sun.COM /* 1802*11353SSaurabh.Mishra@Sun.COM * Set Maximum frame size but don't let MTU be less than ETHER_MTU. 180310393SSaurabh.Mishra@Sun.COM */ 180410393SSaurabh.Mishra@Sun.COM if (atgep->atge_mtu < ETHERMTU) 180510393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size = ETHERMTU; 180610393SSaurabh.Mishra@Sun.COM else 180710393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size = atgep->atge_mtu; 180810393SSaurabh.Mishra@Sun.COM 180910393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size += sizeof (struct ether_header) + 181010393SSaurabh.Mishra@Sun.COM VLAN_TAGSZ + ETHERFCSL; 181110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size); 181210393SSaurabh.Mishra@Sun.COM 181310393SSaurabh.Mishra@Sun.COM 181410393SSaurabh.Mishra@Sun.COM /* 181510393SSaurabh.Mishra@Sun.COM * Configure IPG/IFG parameters. 181610393SSaurabh.Mishra@Sun.COM */ 181710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_IPG_IFG_CFG, 181810393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) | 181910393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) | 182010393SSaurabh.Mishra@Sun.COM ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) | 182110393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK)); 182210393SSaurabh.Mishra@Sun.COM 182310393SSaurabh.Mishra@Sun.COM /* 182410393SSaurabh.Mishra@Sun.COM * Set parameters for half-duplex media. 182510393SSaurabh.Mishra@Sun.COM */ 182610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_HDPX_CFG, 182710393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 182810393SSaurabh.Mishra@Sun.COM HDPX_CFG_LCOL_MASK) | 182910393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 183010393SSaurabh.Mishra@Sun.COM HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 183110393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 183210393SSaurabh.Mishra@Sun.COM HDPX_CFG_ABEBT_MASK) | 183310393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 183410393SSaurabh.Mishra@Sun.COM HDPX_CFG_JAMIPG_MASK)); 183510393SSaurabh.Mishra@Sun.COM 183610393SSaurabh.Mishra@Sun.COM /* 183710393SSaurabh.Mishra@Sun.COM * Configure jumbo frame. 183810393SSaurabh.Mishra@Sun.COM */ 183910393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 184010393SSaurabh.Mishra@Sun.COM fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t)); 184110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_JUMBO_CFG, 184210393SSaurabh.Mishra@Sun.COM (((fsize / sizeof (uint64_t)) << 184310393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) & 184410393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_SZ_THRESH_MASK) | 184510393SSaurabh.Mishra@Sun.COM ((RXQ_JUMBO_CFG_LKAH_DEFAULT << 184610393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) | 184710393SSaurabh.Mishra@Sun.COM ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) & 184810393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_RRD_TIMER_MASK)); 184910393SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E && 185010393SSaurabh.Mishra@Sun.COM atgep->atge_flags & ATGE_FLAG_JUMBO) { 185110393SSaurabh.Mishra@Sun.COM 185210393SSaurabh.Mishra@Sun.COM if (atgep->atge_mtu < ETHERMTU) 185310393SSaurabh.Mishra@Sun.COM reg = atgep->atge_max_frame_size; 185410393SSaurabh.Mishra@Sun.COM else if (atgep->atge_mtu < 6 * 1024) 185510393SSaurabh.Mishra@Sun.COM reg = (atgep->atge_max_frame_size * 2) / 3; 185610393SSaurabh.Mishra@Sun.COM else 185710393SSaurabh.Mishra@Sun.COM reg = atgep->atge_max_frame_size / 2; 185810393SSaurabh.Mishra@Sun.COM 185910393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_TX_JUMBO_THRESH, 186010393SSaurabh.Mishra@Sun.COM ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >> 186110393SSaurabh.Mishra@Sun.COM TX_JUMBO_THRESH_UNIT_SHIFT); 186210393SSaurabh.Mishra@Sun.COM } 186310393SSaurabh.Mishra@Sun.COM 186410393SSaurabh.Mishra@Sun.COM /* 186510393SSaurabh.Mishra@Sun.COM * Configure flow-control parameters. 186610393SSaurabh.Mishra@Sun.COM */ 186710393SSaurabh.Mishra@Sun.COM if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) { 186810393SSaurabh.Mishra@Sun.COM /* 186910393SSaurabh.Mishra@Sun.COM * Some hardware version require this magic. 187010393SSaurabh.Mishra@Sun.COM */ 187110393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x12FC, 0x6500); 187210393SSaurabh.Mishra@Sun.COM reg = INL(atgep, 0x1008); 187310393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x1008, reg | 0x8000); 187410393SSaurabh.Mishra@Sun.COM } 187510393SSaurabh.Mishra@Sun.COM 187610393SSaurabh.Mishra@Sun.COM /* 187710393SSaurabh.Mishra@Sun.COM * These are all magic parameters which came from FreeBSD. 187810393SSaurabh.Mishra@Sun.COM */ 1879*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1880*11353SSaurabh.Mishra@Sun.COM switch (atgep->atge_chip_rev) { 1881*11353SSaurabh.Mishra@Sun.COM case 0x8001: 1882*11353SSaurabh.Mishra@Sun.COM case 0x9001: 1883*11353SSaurabh.Mishra@Sun.COM case 0x9002: 1884*11353SSaurabh.Mishra@Sun.COM case 0x9003: 1885*11353SSaurabh.Mishra@Sun.COM rxf_hi = L1_RX_RING_CNT / 16; 1886*11353SSaurabh.Mishra@Sun.COM rxf_lo = (L1_RX_RING_CNT * 7) / 8; 1887*11353SSaurabh.Mishra@Sun.COM rrd_hi = (L1_RR_RING_CNT * 7) / 8; 1888*11353SSaurabh.Mishra@Sun.COM rrd_lo = L1_RR_RING_CNT / 16; 1889*11353SSaurabh.Mishra@Sun.COM break; 1890*11353SSaurabh.Mishra@Sun.COM default: 1891*11353SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1_SRAM_RX_FIFO_LEN); 1892*11353SSaurabh.Mishra@Sun.COM rxf_lo = reg / 16; 1893*11353SSaurabh.Mishra@Sun.COM if (rxf_lo > 192) 1894*11353SSaurabh.Mishra@Sun.COM rxf_lo = 192; 1895*11353SSaurabh.Mishra@Sun.COM rxf_hi = (reg * 7) / 8; 1896*11353SSaurabh.Mishra@Sun.COM if (rxf_hi < rxf_lo) 1897*11353SSaurabh.Mishra@Sun.COM rxf_hi = rxf_lo + 16; 1898*11353SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1_SRAM_RRD_LEN); 1899*11353SSaurabh.Mishra@Sun.COM rrd_lo = reg / 8; 1900*11353SSaurabh.Mishra@Sun.COM rrd_hi = (reg * 7) / 8; 1901*11353SSaurabh.Mishra@Sun.COM if (rrd_lo > 2) 1902*11353SSaurabh.Mishra@Sun.COM rrd_lo = 2; 1903*11353SSaurabh.Mishra@Sun.COM if (rrd_hi < rrd_lo) 1904*11353SSaurabh.Mishra@Sun.COM rrd_hi = rrd_lo + 3; 1905*11353SSaurabh.Mishra@Sun.COM break; 1906*11353SSaurabh.Mishra@Sun.COM } 1907*11353SSaurabh.Mishra@Sun.COM 1908*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH, 1909*11353SSaurabh.Mishra@Sun.COM ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) & 1910*11353SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_LO_MASK) | 1911*11353SSaurabh.Mishra@Sun.COM ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) & 1912*11353SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_HI_MASK)); 1913*11353SSaurabh.Mishra@Sun.COM 1914*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH, 1915*11353SSaurabh.Mishra@Sun.COM ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) & 1916*11353SSaurabh.Mishra@Sun.COM RXQ_RRD_PAUSE_THRESH_LO_MASK) | 1917*11353SSaurabh.Mishra@Sun.COM ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) & 1918*11353SSaurabh.Mishra@Sun.COM RXQ_RRD_PAUSE_THRESH_HI_MASK)); 1919*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 192010393SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN); 192110393SSaurabh.Mishra@Sun.COM rxf_hi = (reg * 4) / 5; 192210393SSaurabh.Mishra@Sun.COM rxf_lo = reg/ 5; 192310393SSaurabh.Mishra@Sun.COM 192410393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH, 192510393SSaurabh.Mishra@Sun.COM ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) & 192610393SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_LO_MASK) | 192710393SSaurabh.Mishra@Sun.COM ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) & 192810393SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_HI_MASK)); 192910393SSaurabh.Mishra@Sun.COM } 193010393SSaurabh.Mishra@Sun.COM 193110393SSaurabh.Mishra@Sun.COM /* Configure RxQ. */ 193210393SSaurabh.Mishra@Sun.COM reg = 0; 1933*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1934*11353SSaurabh.Mishra@Sun.COM reg = 1935*11353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) & 1936*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_BURST_MASK) | 1937*11353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT << 1938*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_RRD_BURST_THRESH_SHIFT) & 1939*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_RRD_BURST_THRESH_MASK) | 1940*11353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT << 1941*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) & 1942*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_PREF_MIN_IPG_MASK) | 1943*11353SSaurabh.Mishra@Sun.COM RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB; 1944*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg); 1945*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 194610393SSaurabh.Mishra@Sun.COM reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB | 194710393SSaurabh.Mishra@Sun.COM RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB; 194810393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg); 194910393SSaurabh.Mishra@Sun.COM } 195010393SSaurabh.Mishra@Sun.COM 195110393SSaurabh.Mishra@Sun.COM /* 195210393SSaurabh.Mishra@Sun.COM * Configure TxQ. 195310393SSaurabh.Mishra@Sun.COM */ 1954*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1955*11353SSaurabh.Mishra@Sun.COM reg = 1956*11353SSaurabh.Mishra@Sun.COM (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) & 1957*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_BURST_MASK) | 1958*11353SSaurabh.Mishra@Sun.COM ((TXQ_CFG_TX_FIFO_BURST_DEFAULT << 1959*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_SHIFT) & 1960*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_MASK) | 1961*11353SSaurabh.Mishra@Sun.COM ((TXQ_CFG_TPD_FETCH_DEFAULT << 1962*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_FETCH_THRESH_SHIFT) & 1963*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_FETCH_THRESH_MASK) | 1964*11353SSaurabh.Mishra@Sun.COM TXQ_CFG_ENB); 1965*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg); 1966*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 196710393SSaurabh.Mishra@Sun.COM reg = (128 << 196810393SSaurabh.Mishra@Sun.COM (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) << 196910393SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_SHIFT; 197010393SSaurabh.Mishra@Sun.COM 197110393SSaurabh.Mishra@Sun.COM reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) & 197210393SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_BURST_MASK; 197310393SSaurabh.Mishra@Sun.COM 197410393SSaurabh.Mishra@Sun.COM reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB; 197510393SSaurabh.Mishra@Sun.COM 197610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg); 197710393SSaurabh.Mishra@Sun.COM } 197810393SSaurabh.Mishra@Sun.COM 1979*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1980*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG, 1981*11353SSaurabh.Mishra@Sun.COM (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) & 1982*11353SSaurabh.Mishra@Sun.COM TX_JUMBO_TPD_TH_MASK) | 1983*11353SSaurabh.Mishra@Sun.COM ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) & 1984*11353SSaurabh.Mishra@Sun.COM TX_JUMBO_TPD_IPG_MASK)); 1985*11353SSaurabh.Mishra@Sun.COM } 1986*11353SSaurabh.Mishra@Sun.COM 198710393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 198810393SSaurabh.Mishra@Sun.COM /* Disable RSS. */ 198910393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_RSS_IDT_TABLE0, 0); 199010393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_RSS_CPU, 0); 199110393SSaurabh.Mishra@Sun.COM } 199210393SSaurabh.Mishra@Sun.COM 199310393SSaurabh.Mishra@Sun.COM /* 199410393SSaurabh.Mishra@Sun.COM * Configure DMA parameters. 199510393SSaurabh.Mishra@Sun.COM */ 1996*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 1997*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, 1998*11353SSaurabh.Mishra@Sun.COM DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 | 1999*11353SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB | 2000*11353SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB); 2001*11353SSaurabh.Mishra@Sun.COM 2002*11353SSaurabh.Mishra@Sun.COM /* Configure CMB DMA write threshold. */ 2003*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CMB_WR_THRESH, 2004*11353SSaurabh.Mishra@Sun.COM ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) & 2005*11353SSaurabh.Mishra@Sun.COM CMB_WR_THRESH_RRD_MASK) | 2006*11353SSaurabh.Mishra@Sun.COM ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) & 2007*11353SSaurabh.Mishra@Sun.COM CMB_WR_THRESH_TPD_MASK)); 2008*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 200910393SSaurabh.Mishra@Sun.COM /* 201010393SSaurabh.Mishra@Sun.COM * Don't use Tx CMB. It is known to cause RRS update failure 201110393SSaurabh.Mishra@Sun.COM * under certain circumstances. Typical phenomenon of the 201210393SSaurabh.Mishra@Sun.COM * issue would be unexpected sequence number encountered in 201310393SSaurabh.Mishra@Sun.COM * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB. 201410393SSaurabh.Mishra@Sun.COM */ 201510393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, 201610393SSaurabh.Mishra@Sun.COM DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 | 201710393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst | 201810393SSaurabh.Mishra@Sun.COM DMA_CFG_RXCMB_ENB | 201910393SSaurabh.Mishra@Sun.COM ((DMA_CFG_RD_DELAY_CNT_DEFAULT << 202010393SSaurabh.Mishra@Sun.COM DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) | 202110393SSaurabh.Mishra@Sun.COM ((DMA_CFG_WR_DELAY_CNT_DEFAULT << 202210393SSaurabh.Mishra@Sun.COM DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK)); 202310393SSaurabh.Mishra@Sun.COM } 202410393SSaurabh.Mishra@Sun.COM 202510393SSaurabh.Mishra@Sun.COM /* 2026*11353SSaurabh.Mishra@Sun.COM * Enable CMB/SMB timer. 202710393SSaurabh.Mishra@Sun.COM */ 2028*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 2029*11353SSaurabh.Mishra@Sun.COM /* Set CMB/SMB timer and enable them. */ 2030*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CMB_WR_TIMER, 2031*11353SSaurabh.Mishra@Sun.COM ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) & 2032*11353SSaurabh.Mishra@Sun.COM CMB_WR_TIMER_TX_MASK) | 2033*11353SSaurabh.Mishra@Sun.COM ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) & 2034*11353SSaurabh.Mishra@Sun.COM CMB_WR_TIMER_RX_MASK)); 2035*11353SSaurabh.Mishra@Sun.COM 2036*11353SSaurabh.Mishra@Sun.COM /* Request SMB updates for every seconds. */ 2037*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000)); 2038*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CSMB_CTRL, 2039*11353SSaurabh.Mishra@Sun.COM CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB); 2040*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 204110393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_SMB_STAT_TIMER, 100000); 204210393SSaurabh.Mishra@Sun.COM atge_l1e_clear_stats(atgep); 204310393SSaurabh.Mishra@Sun.COM } 204410393SSaurabh.Mishra@Sun.COM 2045*11353SSaurabh.Mishra@Sun.COM 204610393SSaurabh.Mishra@Sun.COM /* 204710393SSaurabh.Mishra@Sun.COM * Disable all WOL bits as WOL can interfere normal Rx 204810393SSaurabh.Mishra@Sun.COM * operation. 204910393SSaurabh.Mishra@Sun.COM */ 205010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_WOL_CFG, 0); 205110393SSaurabh.Mishra@Sun.COM 205210393SSaurabh.Mishra@Sun.COM /* 205310393SSaurabh.Mishra@Sun.COM * Configure Tx/Rx MACs. 205410393SSaurabh.Mishra@Sun.COM * - Auto-padding for short frames. 205510393SSaurabh.Mishra@Sun.COM * - Enable CRC generation. 205610393SSaurabh.Mishra@Sun.COM * 205710393SSaurabh.Mishra@Sun.COM * Start with full-duplex/1000Mbps media. Actual reconfiguration 205810393SSaurabh.Mishra@Sun.COM * of MAC is followed after link establishment. 205910393SSaurabh.Mishra@Sun.COM */ 206010393SSaurabh.Mishra@Sun.COM reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD | 206110393SSaurabh.Mishra@Sun.COM ATGE_CFG_FULL_DUPLEX | 206210393SSaurabh.Mishra@Sun.COM ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) & 206310393SSaurabh.Mishra@Sun.COM ATGE_CFG_PREAMBLE_MASK)); 206410393SSaurabh.Mishra@Sun.COM 206510393SSaurabh.Mishra@Sun.COM if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) { 206610393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_10_100; 206710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__)); 206810393SSaurabh.Mishra@Sun.COM } else { 206910393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_1000; 207010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__)); 207110393SSaurabh.Mishra@Sun.COM } 207210393SSaurabh.Mishra@Sun.COM 207310393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, reg); 207410393SSaurabh.Mishra@Sun.COM 207510393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_RUNNING; 207610393SSaurabh.Mishra@Sun.COM 207710393SSaurabh.Mishra@Sun.COM /* 207810393SSaurabh.Mishra@Sun.COM * Set up the receive filter. 207910393SSaurabh.Mishra@Sun.COM */ 208010393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep); 208110393SSaurabh.Mishra@Sun.COM 2082*11353SSaurabh.Mishra@Sun.COM /* 2083*11353SSaurabh.Mishra@Sun.COM * Acknowledge all pending interrupts and clear it. 2084*11353SSaurabh.Mishra@Sun.COM */ 2085*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 2086*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0); 2087*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs); 2088*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 208910393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS); 209010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF); 209110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0); 209210393SSaurabh.Mishra@Sun.COM } 209310393SSaurabh.Mishra@Sun.COM 2094*11353SSaurabh.Mishra@Sun.COM atge_mac_config(atgep); 2095*11353SSaurabh.Mishra@Sun.COM 209610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__)); 209710393SSaurabh.Mishra@Sun.COM } 209810393SSaurabh.Mishra@Sun.COM 209910393SSaurabh.Mishra@Sun.COM /* 210010393SSaurabh.Mishra@Sun.COM * Generic functions. 210110393SSaurabh.Mishra@Sun.COM */ 210210393SSaurabh.Mishra@Sun.COM 210310393SSaurabh.Mishra@Sun.COM #define CRC32_POLY_BE 0x04c11db7 210410393SSaurabh.Mishra@Sun.COM uint32_t 210510393SSaurabh.Mishra@Sun.COM atge_ether_crc(const uint8_t *addr, int len) 210610393SSaurabh.Mishra@Sun.COM { 210710393SSaurabh.Mishra@Sun.COM int idx; 210810393SSaurabh.Mishra@Sun.COM int bit; 210910393SSaurabh.Mishra@Sun.COM uint_t data; 211010393SSaurabh.Mishra@Sun.COM uint32_t crc; 211110393SSaurabh.Mishra@Sun.COM 211210393SSaurabh.Mishra@Sun.COM crc = 0xffffffff; 211310393SSaurabh.Mishra@Sun.COM for (idx = 0; idx < len; idx++) { 211410393SSaurabh.Mishra@Sun.COM for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { 211510393SSaurabh.Mishra@Sun.COM crc = (crc << 1) 211610393SSaurabh.Mishra@Sun.COM ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0); 211710393SSaurabh.Mishra@Sun.COM } 211810393SSaurabh.Mishra@Sun.COM } 211910393SSaurabh.Mishra@Sun.COM 212010393SSaurabh.Mishra@Sun.COM return (crc); 212110393SSaurabh.Mishra@Sun.COM } 212210393SSaurabh.Mishra@Sun.COM 212310393SSaurabh.Mishra@Sun.COM 212410393SSaurabh.Mishra@Sun.COM /* 212510393SSaurabh.Mishra@Sun.COM * Programs RX filter. We use a link-list to keep track of all multicast 212610393SSaurabh.Mishra@Sun.COM * addressess. 212710393SSaurabh.Mishra@Sun.COM */ 212810393SSaurabh.Mishra@Sun.COM void 212910393SSaurabh.Mishra@Sun.COM atge_rxfilter(atge_t *atgep) 213010393SSaurabh.Mishra@Sun.COM { 213110393SSaurabh.Mishra@Sun.COM uint32_t rxcfg; 213210393SSaurabh.Mishra@Sun.COM uint64_t mchash; 213310393SSaurabh.Mishra@Sun.COM 213410393SSaurabh.Mishra@Sun.COM rxcfg = INL(atgep, ATGE_MAC_CFG); 213510393SSaurabh.Mishra@Sun.COM rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC); 213610393SSaurabh.Mishra@Sun.COM 213710393SSaurabh.Mishra@Sun.COM /* 213810393SSaurabh.Mishra@Sun.COM * Accept broadcast frames. 213910393SSaurabh.Mishra@Sun.COM */ 214010393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_BCAST; 214110393SSaurabh.Mishra@Sun.COM 214210393SSaurabh.Mishra@Sun.COM /* 214310393SSaurabh.Mishra@Sun.COM * We don't use Hardware VLAN tagging. 214410393SSaurabh.Mishra@Sun.COM */ 214510393SSaurabh.Mishra@Sun.COM rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP; 214610393SSaurabh.Mishra@Sun.COM 214710393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) { 214810393SSaurabh.Mishra@Sun.COM mchash = ~0ULL; 214910393SSaurabh.Mishra@Sun.COM 215010393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & ATGE_PROMISC) 215110393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_PROMISC; 215210393SSaurabh.Mishra@Sun.COM 215310393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & ATGE_ALL_MULTICST) 215410393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_ALLMULTI; 215510393SSaurabh.Mishra@Sun.COM } else { 215610393SSaurabh.Mishra@Sun.COM mchash = atgep->atge_mchash; 215710393SSaurabh.Mishra@Sun.COM } 215810393SSaurabh.Mishra@Sun.COM 215910393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep); 216010393SSaurabh.Mishra@Sun.COM 216110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAR0, (uint32_t)mchash); 216210393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32)); 216310393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, rxcfg); 216410393SSaurabh.Mishra@Sun.COM 216510393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx", 216610393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, rxcfg, mchash)); 216710393SSaurabh.Mishra@Sun.COM } 216810393SSaurabh.Mishra@Sun.COM 216910393SSaurabh.Mishra@Sun.COM void 217010393SSaurabh.Mishra@Sun.COM atge_device_stop(atge_t *atgep) 217110393SSaurabh.Mishra@Sun.COM { 217210393SSaurabh.Mishra@Sun.COM uint32_t reg; 217310393SSaurabh.Mishra@Sun.COM int t; 217410393SSaurabh.Mishra@Sun.COM 217510393SSaurabh.Mishra@Sun.COM /* 217610393SSaurabh.Mishra@Sun.COM * If the chip is being suspended, then don't touch the state. Caller 217710393SSaurabh.Mishra@Sun.COM * will take care of setting the correct state. 217810393SSaurabh.Mishra@Sun.COM */ 217910393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) { 218010393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_STOPPED; 218110393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING; 218210393SSaurabh.Mishra@Sun.COM } 218310393SSaurabh.Mishra@Sun.COM 218410393SSaurabh.Mishra@Sun.COM /* 218510393SSaurabh.Mishra@Sun.COM * Collect stats for L1E. L1 chip's stats are collected by interrupt. 218610393SSaurabh.Mishra@Sun.COM */ 218710393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 218810393SSaurabh.Mishra@Sun.COM atge_l1e_gather_stats(atgep); 218910393SSaurabh.Mishra@Sun.COM } 219010393SSaurabh.Mishra@Sun.COM 219110393SSaurabh.Mishra@Sun.COM /* 219210393SSaurabh.Mishra@Sun.COM * Disable interrupts. 219310393SSaurabh.Mishra@Sun.COM */ 219410393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atgep); 219510393SSaurabh.Mishra@Sun.COM 2196*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) 2197*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CSMB_CTRL, 0); 2198*11353SSaurabh.Mishra@Sun.COM 2199*11353SSaurabh.Mishra@Sun.COM /* Stop DMA Engine */ 2200*11353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 2201*11353SSaurabh.Mishra@Sun.COM atge_l1_stop_tx_mac(atgep); 2202*11353SSaurabh.Mishra@Sun.COM atge_l1_stop_rx_mac(atgep); 2203*11353SSaurabh.Mishra@Sun.COM 2204*11353SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_DMA_CFG); 2205*11353SSaurabh.Mishra@Sun.COM reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB); 2206*11353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, reg); 2207*11353SSaurabh.Mishra@Sun.COM 2208*11353SSaurabh.Mishra@Sun.COM } 2209*11353SSaurabh.Mishra@Sun.COM 221010393SSaurabh.Mishra@Sun.COM /* 221110393SSaurabh.Mishra@Sun.COM * Disable queue processing. 221210393SSaurabh.Mishra@Sun.COM */ 221310393SSaurabh.Mishra@Sun.COM /* Stop TxQ */ 221410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_TXQ_CFG); 221510393SSaurabh.Mishra@Sun.COM reg = reg & ~TXQ_CFG_ENB; 221610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg); 221710393SSaurabh.Mishra@Sun.COM 221810393SSaurabh.Mishra@Sun.COM /* Stop RxQ */ 221910393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_RXQ_CFG); 222010393SSaurabh.Mishra@Sun.COM reg = reg & ~RXQ_CFG_ENB; 222110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg); 222210393SSaurabh.Mishra@Sun.COM 222310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 222410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_DMA_CFG); 222510393SSaurabh.Mishra@Sun.COM reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB); 222610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, reg); 222710393SSaurabh.Mishra@Sun.COM drv_usecwait(1000); 222810393SSaurabh.Mishra@Sun.COM atge_l1e_stop_mac(atgep); 222910393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF); 223010393SSaurabh.Mishra@Sun.COM } 223110393SSaurabh.Mishra@Sun.COM 223210393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) { 223310393SSaurabh.Mishra@Sun.COM if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0) 223410393SSaurabh.Mishra@Sun.COM break; 223510393SSaurabh.Mishra@Sun.COM drv_usecwait(10); 223610393SSaurabh.Mishra@Sun.COM } 223710393SSaurabh.Mishra@Sun.COM 223810393SSaurabh.Mishra@Sun.COM if (t == 0) { 223910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout", 224010393SSaurabh.Mishra@Sun.COM __func__); 224110393SSaurabh.Mishra@Sun.COM } 224210393SSaurabh.Mishra@Sun.COM } 224310393SSaurabh.Mishra@Sun.COM 224410393SSaurabh.Mishra@Sun.COM void 224510393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atge_t *atgep) 224610393SSaurabh.Mishra@Sun.COM { 224710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, 0); 224810393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF); 224910393SSaurabh.Mishra@Sun.COM } 225010393SSaurabh.Mishra@Sun.COM 225110393SSaurabh.Mishra@Sun.COM void 225210393SSaurabh.Mishra@Sun.COM atge_device_init(atge_t *atgep) 225310393SSaurabh.Mishra@Sun.COM { 225410393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 225510393SSaurabh.Mishra@Sun.COM atgep->atge_intrs = L1E_INTRS; 225610393SSaurabh.Mishra@Sun.COM atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT; 225710393SSaurabh.Mishra@Sun.COM 225810393SSaurabh.Mishra@Sun.COM atge_l1e_init_tx_ring(atgep); 225910393SSaurabh.Mishra@Sun.COM atge_l1e_init_rx_pages(atgep); 2260*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 2261*11353SSaurabh.Mishra@Sun.COM atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN | 2262*11353SSaurabh.Mishra@Sun.COM INTR_LINK_CHG; 2263*11353SSaurabh.Mishra@Sun.COM atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT; 2264*11353SSaurabh.Mishra@Sun.COM 2265*11353SSaurabh.Mishra@Sun.COM atge_l1_init_tx_ring(atgep); 2266*11353SSaurabh.Mishra@Sun.COM atge_l1_init_rx_ring(atgep); 2267*11353SSaurabh.Mishra@Sun.COM atge_l1_init_rr_ring(atgep); 2268*11353SSaurabh.Mishra@Sun.COM atge_l1_init_cmb(atgep); 2269*11353SSaurabh.Mishra@Sun.COM atge_l1_init_smb(atgep); 227010393SSaurabh.Mishra@Sun.COM } 227110393SSaurabh.Mishra@Sun.COM } 227210393SSaurabh.Mishra@Sun.COM 227310393SSaurabh.Mishra@Sun.COM void 227410393SSaurabh.Mishra@Sun.COM atge_device_restart(atge_t *atgep) 227510393SSaurabh.Mishra@Sun.COM { 227610393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock)); 227710393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock)); 227810393SSaurabh.Mishra@Sun.COM 227910393SSaurabh.Mishra@Sun.COM /* 228010393SSaurabh.Mishra@Sun.COM * Cancel any pending I/O. 228110393SSaurabh.Mishra@Sun.COM */ 228210393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep); 228310393SSaurabh.Mishra@Sun.COM 228410393SSaurabh.Mishra@Sun.COM /* 228510393SSaurabh.Mishra@Sun.COM * Reset the chip to a known state. 228610393SSaurabh.Mishra@Sun.COM */ 228710393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep); 228810393SSaurabh.Mishra@Sun.COM 228910393SSaurabh.Mishra@Sun.COM /* 229010393SSaurabh.Mishra@Sun.COM * Initialize the ring and other descriptor like CMB/SMB/Rx return. 229110393SSaurabh.Mishra@Sun.COM */ 229210393SSaurabh.Mishra@Sun.COM atge_device_init(atgep); 229310393SSaurabh.Mishra@Sun.COM 229410393SSaurabh.Mishra@Sun.COM /* 229510393SSaurabh.Mishra@Sun.COM * Start the chip. 229610393SSaurabh.Mishra@Sun.COM */ 229710393SSaurabh.Mishra@Sun.COM atge_device_start(atgep); 229810393SSaurabh.Mishra@Sun.COM 229910393SSaurabh.Mishra@Sun.COM } 230010393SSaurabh.Mishra@Sun.COM 230110393SSaurabh.Mishra@Sun.COM static int 230210393SSaurabh.Mishra@Sun.COM atge_send_a_packet(atge_t *atgep, mblk_t *mp) 230310393SSaurabh.Mishra@Sun.COM { 2304*11353SSaurabh.Mishra@Sun.COM atge_tx_desc_t *txd; 2305*11353SSaurabh.Mishra@Sun.COM uchar_t *c; 2306*11353SSaurabh.Mishra@Sun.COM uint32_t cflags = 0; 230710393SSaurabh.Mishra@Sun.COM atge_ring_t *r; 230810393SSaurabh.Mishra@Sun.COM size_t pktlen; 230910393SSaurabh.Mishra@Sun.COM uchar_t *buf; 231010393SSaurabh.Mishra@Sun.COM int start; 231110393SSaurabh.Mishra@Sun.COM 231210393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock)); 231310393SSaurabh.Mishra@Sun.COM ASSERT(mp != NULL); 231410393SSaurabh.Mishra@Sun.COM 231510393SSaurabh.Mishra@Sun.COM pktlen = msgsize(mp); 231610393SSaurabh.Mishra@Sun.COM if (pktlen > atgep->atge_tx_buf_len) { 231710393SSaurabh.Mishra@Sun.COM atgep->atge_macxmt_errors++; 231810393SSaurabh.Mishra@Sun.COM 231910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)", 232010393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, 232110393SSaurabh.Mishra@Sun.COM pktlen, atgep->atge_rx_buf_len)); 232210393SSaurabh.Mishra@Sun.COM 232310393SSaurabh.Mishra@Sun.COM freemsg(mp); 2324*11353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 232510393SSaurabh.Mishra@Sun.COM } 232610393SSaurabh.Mishra@Sun.COM 232710393SSaurabh.Mishra@Sun.COM r = atgep->atge_tx_ring; 232810393SSaurabh.Mishra@Sun.COM 232910393SSaurabh.Mishra@Sun.COM if (r->r_avail_desc <= 1) { 233010393SSaurabh.Mishra@Sun.COM atgep->atge_noxmtbuf++; 233110393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1; 2332*11353SSaurabh.Mishra@Sun.COM 2333*11353SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() No transmit buf", 2334*11353SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__)); 2335*11353SSaurabh.Mishra@Sun.COM 2336*11353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE); 233710393SSaurabh.Mishra@Sun.COM } 233810393SSaurabh.Mishra@Sun.COM 233910393SSaurabh.Mishra@Sun.COM start = r->r_producer; 234010393SSaurabh.Mishra@Sun.COM 234110393SSaurabh.Mishra@Sun.COM /* 234210393SSaurabh.Mishra@Sun.COM * Get the DMA buffer to hold a packet. 234310393SSaurabh.Mishra@Sun.COM */ 234410393SSaurabh.Mishra@Sun.COM buf = (uchar_t *)r->r_buf_tbl[start]->addr; 234510393SSaurabh.Mishra@Sun.COM 234610393SSaurabh.Mishra@Sun.COM /* 234710393SSaurabh.Mishra@Sun.COM * Copy the msg and free mp 234810393SSaurabh.Mishra@Sun.COM */ 234910393SSaurabh.Mishra@Sun.COM mcopymsg(mp, buf); 235010393SSaurabh.Mishra@Sun.COM 235110393SSaurabh.Mishra@Sun.COM r->r_avail_desc--; 235210393SSaurabh.Mishra@Sun.COM 2353*11353SSaurabh.Mishra@Sun.COM c = (uchar_t *)r->r_desc_ring->addr; 2354*11353SSaurabh.Mishra@Sun.COM c += (sizeof (atge_tx_desc_t) * start); 2355*11353SSaurabh.Mishra@Sun.COM txd = (atge_tx_desc_t *)c; 2356*11353SSaurabh.Mishra@Sun.COM 2357*11353SSaurabh.Mishra@Sun.COM ATGE_PUT64(r->r_desc_ring, &txd->addr, 2358*11353SSaurabh.Mishra@Sun.COM r->r_buf_tbl[start]->cookie.dmac_laddress); 2359*11353SSaurabh.Mishra@Sun.COM 2360*11353SSaurabh.Mishra@Sun.COM ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen)); 2361*11353SSaurabh.Mishra@Sun.COM 2362*11353SSaurabh.Mishra@Sun.COM cflags |= ATGE_TD_EOP; 2363*11353SSaurabh.Mishra@Sun.COM ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags); 2364*11353SSaurabh.Mishra@Sun.COM 2365*11353SSaurabh.Mishra@Sun.COM /* 2366*11353SSaurabh.Mishra@Sun.COM * Sync buffer first. 2367*11353SSaurabh.Mishra@Sun.COM */ 2368*11353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV); 2369*11353SSaurabh.Mishra@Sun.COM 2370*11353SSaurabh.Mishra@Sun.COM /* 2371*11353SSaurabh.Mishra@Sun.COM * Increment TX producer count by one. 2372*11353SSaurabh.Mishra@Sun.COM */ 2373*11353SSaurabh.Mishra@Sun.COM ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT); 2374*11353SSaurabh.Mishra@Sun.COM 2375*11353SSaurabh.Mishra@Sun.COM /* 2376*11353SSaurabh.Mishra@Sun.COM * Sync descriptor table. 2377*11353SSaurabh.Mishra@Sun.COM */ 2378*11353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV); 2379*11353SSaurabh.Mishra@Sun.COM 238010393SSaurabh.Mishra@Sun.COM /* 238110393SSaurabh.Mishra@Sun.COM * Program TX descriptor to send a packet. 238210393SSaurabh.Mishra@Sun.COM */ 238310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) { 2384*11353SSaurabh.Mishra@Sun.COM atge_l1e_send_packet(r); 2385*11353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) { 2386*11353SSaurabh.Mishra@Sun.COM atge_l1_send_packet(r); 238710393SSaurabh.Mishra@Sun.COM } 238810393SSaurabh.Mishra@Sun.COM 2389*11353SSaurabh.Mishra@Sun.COM r->r_atge->atge_opackets++; 2390*11353SSaurabh.Mishra@Sun.COM r->r_atge->atge_obytes += pktlen; 2391*11353SSaurabh.Mishra@Sun.COM 2392*11353SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer :%d, " 2393*11353SSaurabh.Mishra@Sun.COM "consumer : %d", atgep->atge_name, __func__, pktlen, 2394*11353SSaurabh.Mishra@Sun.COM r->r_avail_desc, r->r_producer, r->r_consumer)); 2395*11353SSaurabh.Mishra@Sun.COM 2396*11353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS); 239710393SSaurabh.Mishra@Sun.COM } 239810393SSaurabh.Mishra@Sun.COM 239910393SSaurabh.Mishra@Sun.COM /* 240010393SSaurabh.Mishra@Sun.COM * Stream Information. 240110393SSaurabh.Mishra@Sun.COM */ 240210393SSaurabh.Mishra@Sun.COM DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach, 240310393SSaurabh.Mishra@Sun.COM nodev, NULL, D_MP, NULL, atge_quiesce); 240410393SSaurabh.Mishra@Sun.COM 240510393SSaurabh.Mishra@Sun.COM /* 240610393SSaurabh.Mishra@Sun.COM * Module linkage information. 240710393SSaurabh.Mishra@Sun.COM */ 240810393SSaurabh.Mishra@Sun.COM static struct modldrv atge_modldrv = { 240910393SSaurabh.Mishra@Sun.COM &mod_driverops, /* Type of Module */ 241010393SSaurabh.Mishra@Sun.COM "Atheros/Attansic Gb Ethernet", /* Description */ 241110393SSaurabh.Mishra@Sun.COM &atge_devops /* drv_dev_ops */ 241210393SSaurabh.Mishra@Sun.COM }; 241310393SSaurabh.Mishra@Sun.COM 241410393SSaurabh.Mishra@Sun.COM static struct modlinkage atge_modlinkage = { 241510393SSaurabh.Mishra@Sun.COM MODREV_1, /* ml_rev */ 241610393SSaurabh.Mishra@Sun.COM (void *)&atge_modldrv, 241710393SSaurabh.Mishra@Sun.COM NULL 241810393SSaurabh.Mishra@Sun.COM }; 241910393SSaurabh.Mishra@Sun.COM 242010393SSaurabh.Mishra@Sun.COM /* 242110393SSaurabh.Mishra@Sun.COM * DDI Entry points. 242210393SSaurabh.Mishra@Sun.COM */ 242310393SSaurabh.Mishra@Sun.COM int 242410393SSaurabh.Mishra@Sun.COM _init(void) 242510393SSaurabh.Mishra@Sun.COM { 242610393SSaurabh.Mishra@Sun.COM int r; 242710393SSaurabh.Mishra@Sun.COM mac_init_ops(&atge_devops, "atge"); 242810393SSaurabh.Mishra@Sun.COM if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) { 242910393SSaurabh.Mishra@Sun.COM mac_fini_ops(&atge_devops); 243010393SSaurabh.Mishra@Sun.COM } 243110393SSaurabh.Mishra@Sun.COM 243210393SSaurabh.Mishra@Sun.COM return (r); 243310393SSaurabh.Mishra@Sun.COM } 243410393SSaurabh.Mishra@Sun.COM 243510393SSaurabh.Mishra@Sun.COM int 243610393SSaurabh.Mishra@Sun.COM _fini(void) 243710393SSaurabh.Mishra@Sun.COM { 243810393SSaurabh.Mishra@Sun.COM int r; 243910393SSaurabh.Mishra@Sun.COM 244010393SSaurabh.Mishra@Sun.COM if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) { 244110393SSaurabh.Mishra@Sun.COM mac_fini_ops(&atge_devops); 244210393SSaurabh.Mishra@Sun.COM } 244310393SSaurabh.Mishra@Sun.COM 244410393SSaurabh.Mishra@Sun.COM return (r); 244510393SSaurabh.Mishra@Sun.COM } 244610393SSaurabh.Mishra@Sun.COM 244710393SSaurabh.Mishra@Sun.COM int 244810393SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop) 244910393SSaurabh.Mishra@Sun.COM { 245010393SSaurabh.Mishra@Sun.COM return (mod_info(&atge_modlinkage, modinfop)); 245110393SSaurabh.Mishra@Sun.COM } 2452