12ca5b659SJoost Mulders /* 22ca5b659SJoost Mulders * CDDL HEADER START 32ca5b659SJoost Mulders * 42ca5b659SJoost Mulders * The contents of this file are subject to the terms of the 52ca5b659SJoost Mulders * Common Development and Distribution License (the "License"). 62ca5b659SJoost Mulders * You may not use this file except in compliance with the License. 72ca5b659SJoost Mulders * 82ca5b659SJoost Mulders * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92ca5b659SJoost Mulders * or http://www.opensolaris.org/os/licensing. 102ca5b659SJoost Mulders * See the License for the specific language governing permissions 112ca5b659SJoost Mulders * and limitations under the License. 122ca5b659SJoost Mulders * 132ca5b659SJoost Mulders * When distributing Covered Code, include this CDDL HEADER in each 142ca5b659SJoost Mulders * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152ca5b659SJoost Mulders * If applicable, add the following below this CDDL HEADER, with the 162ca5b659SJoost Mulders * fields enclosed by brackets "[]" replaced with your own identifying 172ca5b659SJoost Mulders * information: Portions Copyright [yyyy] [name of copyright owner] 182ca5b659SJoost Mulders * 192ca5b659SJoost Mulders * CDDL HEADER END 202ca5b659SJoost Mulders */ 212ca5b659SJoost Mulders 222ca5b659SJoost Mulders /* 230dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 242ca5b659SJoost Mulders * Use is subject to license terms. 252ca5b659SJoost Mulders */ 262ca5b659SJoost Mulders 272ca5b659SJoost Mulders #include <sys/types.h> 282ca5b659SJoost Mulders #include <sys/stream.h> 292ca5b659SJoost Mulders #include <sys/strsun.h> 302ca5b659SJoost Mulders #include <sys/stat.h> 312ca5b659SJoost Mulders #include <sys/pci.h> 322ca5b659SJoost Mulders #include <sys/modctl.h> 332ca5b659SJoost Mulders #include <sys/kstat.h> 342ca5b659SJoost Mulders #include <sys/ethernet.h> 352ca5b659SJoost Mulders #include <sys/devops.h> 362ca5b659SJoost Mulders #include <sys/debug.h> 372ca5b659SJoost Mulders #include <sys/conf.h> 382ca5b659SJoost Mulders #include <sys/mac.h> 392ca5b659SJoost Mulders #include <sys/mac_provider.h> 402ca5b659SJoost Mulders #include <sys/mac_ether.h> 412ca5b659SJoost Mulders #include <sys/sysmacros.h> 422ca5b659SJoost Mulders #include <sys/dditypes.h> 432ca5b659SJoost Mulders #include <sys/ddi.h> 442ca5b659SJoost Mulders #include <sys/sunddi.h> 452ca5b659SJoost Mulders #include <sys/miiregs.h> 462ca5b659SJoost Mulders #include <sys/byteorder.h> 472ca5b659SJoost Mulders #include <sys/note.h> 482ca5b659SJoost Mulders #include <sys/vlan.h> 492ca5b659SJoost Mulders 502ca5b659SJoost Mulders #include "vr.h" 512ca5b659SJoost Mulders #include "vr_impl.h" 522ca5b659SJoost Mulders 532ca5b659SJoost Mulders /* 542ca5b659SJoost Mulders * VR in a nutshell 552ca5b659SJoost Mulders * The card uses two rings of data structures to communicate with the host. 562ca5b659SJoost Mulders * These are referred to as "descriptor rings" and there is one for transmit 572ca5b659SJoost Mulders * (TX) and one for receive (RX). 582ca5b659SJoost Mulders * 592ca5b659SJoost Mulders * The driver uses a "DMA buffer" data type for mapping to those descriptor 602ca5b659SJoost Mulders * rings. This is a structure with handles and a DMA'able buffer attached to it. 612ca5b659SJoost Mulders * 622ca5b659SJoost Mulders * Receive 632ca5b659SJoost Mulders * The receive ring is filled with DMA buffers. Received packets are copied into 642ca5b659SJoost Mulders * a newly allocated mblk's and passed upstream. 652ca5b659SJoost Mulders * 662ca5b659SJoost Mulders * Transmit 672ca5b659SJoost Mulders * Each transmit descriptor has a DMA buffer attached to it. The data of TX 682ca5b659SJoost Mulders * packets is copied into the DMA buffer which is then enqueued for 692ca5b659SJoost Mulders * transmission. 702ca5b659SJoost Mulders * 712ca5b659SJoost Mulders * Reclaim of transmitted packets is done as a result of a transmit completion 722ca5b659SJoost Mulders * interrupt which is generated 3 times per ring at minimum. 732ca5b659SJoost Mulders */ 742ca5b659SJoost Mulders 752ca5b659SJoost Mulders #if defined(DEBUG) 762ca5b659SJoost Mulders uint32_t vrdebug = 1; 772ca5b659SJoost Mulders #define VR_DEBUG(args) do { \ 782ca5b659SJoost Mulders if (vrdebug > 0) \ 792ca5b659SJoost Mulders (*vr_debug()) args; \ 802ca5b659SJoost Mulders _NOTE(CONSTANTCONDITION) \ 812ca5b659SJoost Mulders } while (0) 822ca5b659SJoost Mulders static void vr_prt(const char *fmt, ...); 832ca5b659SJoost Mulders void (*vr_debug())(const char *fmt, ...); 842ca5b659SJoost Mulders #else 852ca5b659SJoost Mulders #define VR_DEBUG(args) do ; _NOTE(CONSTANTCONDITION) while (0) 862ca5b659SJoost Mulders #endif 872ca5b659SJoost Mulders 88*5815e35bSjoostmnl@gmail.com static char vr_ident[] = "VIA Rhine Ethernet"; 892ca5b659SJoost Mulders 902ca5b659SJoost Mulders /* 912ca5b659SJoost Mulders * Attributes for accessing registers and memory descriptors for this device. 922ca5b659SJoost Mulders */ 932ca5b659SJoost Mulders static ddi_device_acc_attr_t vr_dev_dma_accattr = { 942ca5b659SJoost Mulders DDI_DEVICE_ATTR_V0, 952ca5b659SJoost Mulders DDI_STRUCTURE_LE_ACC, 962ca5b659SJoost Mulders DDI_STRICTORDER_ACC 972ca5b659SJoost Mulders }; 982ca5b659SJoost Mulders 992ca5b659SJoost Mulders /* 1002ca5b659SJoost Mulders * Attributes for accessing data. 1012ca5b659SJoost Mulders */ 1022ca5b659SJoost Mulders static ddi_device_acc_attr_t vr_data_dma_accattr = { 1032ca5b659SJoost Mulders DDI_DEVICE_ATTR_V0, 1042ca5b659SJoost Mulders DDI_NEVERSWAP_ACC, 1052ca5b659SJoost Mulders DDI_STRICTORDER_ACC 1062ca5b659SJoost Mulders }; 1072ca5b659SJoost Mulders 1082ca5b659SJoost Mulders /* 1092ca5b659SJoost Mulders * DMA attributes for descriptors for communication with the device 1102ca5b659SJoost Mulders * This driver assumes that all descriptors of one ring fit in one consequitive 1112ca5b659SJoost Mulders * memory area of max 4K (256 descriptors) that does not cross a page boundary. 1122ca5b659SJoost Mulders * Therefore, we request 4K alignement. 1132ca5b659SJoost Mulders */ 1142ca5b659SJoost Mulders static ddi_dma_attr_t vr_dev_dma_attr = { 1152ca5b659SJoost Mulders DMA_ATTR_V0, /* version number */ 1162ca5b659SJoost Mulders 0, /* low DMA address range */ 1172ca5b659SJoost Mulders 0xFFFFFFFF, /* high DMA address range */ 1182ca5b659SJoost Mulders 0x7FFFFFFF, /* DMA counter register */ 1192ca5b659SJoost Mulders 0x1000, /* DMA address alignment */ 1202ca5b659SJoost Mulders 0x7F, /* DMA burstsizes */ 1212ca5b659SJoost Mulders 1, /* min effective DMA size */ 1222ca5b659SJoost Mulders 0xFFFFFFFF, /* max DMA xfer size */ 1232ca5b659SJoost Mulders 0xFFFFFFFF, /* segment boundary */ 1242ca5b659SJoost Mulders 1, /* s/g list length */ 1252ca5b659SJoost Mulders 1, /* granularity of device */ 1262ca5b659SJoost Mulders 0 /* DMA transfer flags */ 1272ca5b659SJoost Mulders }; 1282ca5b659SJoost Mulders 1292ca5b659SJoost Mulders /* 1302ca5b659SJoost Mulders * DMA attributes for the data moved to/from the device 1312ca5b659SJoost Mulders * Note that the alignement is set to 2K so hat a 1500 byte packet never 1322ca5b659SJoost Mulders * crosses a page boundary and thus that a DMA transfer is not split up in 1332ca5b659SJoost Mulders * multiple cookies with a 4K/8K pagesize 1342ca5b659SJoost Mulders */ 1352ca5b659SJoost Mulders static ddi_dma_attr_t vr_data_dma_attr = { 1362ca5b659SJoost Mulders DMA_ATTR_V0, /* version number */ 1372ca5b659SJoost Mulders 0, /* low DMA address range */ 1382ca5b659SJoost Mulders 0xFFFFFFFF, /* high DMA address range */ 1392ca5b659SJoost Mulders 0x7FFFFFFF, /* DMA counter register */ 1402ca5b659SJoost Mulders 0x800, /* DMA address alignment */ 1412ca5b659SJoost Mulders 0xfff, /* DMA burstsizes */ 1422ca5b659SJoost Mulders 1, /* min effective DMA size */ 1432ca5b659SJoost Mulders 0xFFFFFFFF, /* max DMA xfer size */ 1442ca5b659SJoost Mulders 0xFFFFFFFF, /* segment boundary */ 1452ca5b659SJoost Mulders 1, /* s/g list length */ 1462ca5b659SJoost Mulders 1, /* granularity of device */ 1472ca5b659SJoost Mulders 0 /* DMA transfer flags */ 1482ca5b659SJoost Mulders }; 1492ca5b659SJoost Mulders 1502ca5b659SJoost Mulders static mac_callbacks_t vr_mac_callbacks = { 1510dc2366fSVenugopal Iyer MC_SETPROP|MC_GETPROP|MC_PROPINFO, /* Which callbacks are set */ 1522ca5b659SJoost Mulders vr_mac_getstat, /* Get the value of a statistic */ 1532ca5b659SJoost Mulders vr_mac_start, /* Start the device */ 1542ca5b659SJoost Mulders vr_mac_stop, /* Stop the device */ 1552ca5b659SJoost Mulders vr_mac_set_promisc, /* Enable or disable promiscuous mode */ 1562ca5b659SJoost Mulders vr_mac_set_multicast, /* Enable or disable a multicast addr */ 1572ca5b659SJoost Mulders vr_mac_set_ether_addr, /* Set the unicast MAC address */ 1582ca5b659SJoost Mulders vr_mac_tx_enqueue_list, /* Transmit a packet */ 1590dc2366fSVenugopal Iyer NULL, 1602ca5b659SJoost Mulders NULL, /* Process an unknown ioctl */ 1612ca5b659SJoost Mulders NULL, /* Get capability information */ 1622ca5b659SJoost Mulders NULL, /* Open the device */ 1632ca5b659SJoost Mulders NULL, /* Close the device */ 1642ca5b659SJoost Mulders vr_mac_setprop, /* Set properties of the device */ 1650dc2366fSVenugopal Iyer vr_mac_getprop, /* Get properties of the device */ 1660dc2366fSVenugopal Iyer vr_mac_propinfo /* Get properties attributes */ 1672ca5b659SJoost Mulders }; 1682ca5b659SJoost Mulders 1692ca5b659SJoost Mulders /* 1702ca5b659SJoost Mulders * Table with bugs and features for each incarnation of the card. 1712ca5b659SJoost Mulders */ 1722ca5b659SJoost Mulders static const chip_info_t vr_chip_info [] = { 1732ca5b659SJoost Mulders { 1742ca5b659SJoost Mulders 0x0, 0x0, 1752ca5b659SJoost Mulders "VIA Rhine Fast Ethernet", 1762ca5b659SJoost Mulders (VR_BUG_NO_MEMIO), 1772ca5b659SJoost Mulders (VR_FEATURE_NONE) 1782ca5b659SJoost Mulders }, 1792ca5b659SJoost Mulders { 1802ca5b659SJoost Mulders 0x04, 0x21, 1812ca5b659SJoost Mulders "VIA VT86C100A Fast Ethernet", 1822ca5b659SJoost Mulders (VR_BUG_NEEDMODE2PCEROPT | VR_BUG_NO_TXQUEUEING | 1832ca5b659SJoost Mulders VR_BUG_NEEDMODE10T | VR_BUG_TXALIGN | VR_BUG_NO_MEMIO | 1842ca5b659SJoost Mulders VR_BUG_MIIPOLLSTOP), 1852ca5b659SJoost Mulders (VR_FEATURE_NONE) 1862ca5b659SJoost Mulders }, 1872ca5b659SJoost Mulders { 1882ca5b659SJoost Mulders 0x40, 0x41, 1892ca5b659SJoost Mulders "VIA VT6102-A Rhine II Fast Ethernet", 1902ca5b659SJoost Mulders (VR_BUG_NEEDMODE2PCEROPT), 1912ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP) 1922ca5b659SJoost Mulders }, 1932ca5b659SJoost Mulders { 1942ca5b659SJoost Mulders 0x42, 0x7f, 1952ca5b659SJoost Mulders "VIA VT6102-C Rhine II Fast Ethernet", 1962ca5b659SJoost Mulders (VR_BUG_NEEDMODE2PCEROPT), 1972ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP) 1982ca5b659SJoost Mulders }, 1992ca5b659SJoost Mulders { 2002ca5b659SJoost Mulders 0x80, 0x82, 2012ca5b659SJoost Mulders "VIA VT6105-A Rhine III Fast Ethernet", 2022ca5b659SJoost Mulders (VR_BUG_NONE), 2032ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP) 2042ca5b659SJoost Mulders }, 2052ca5b659SJoost Mulders { 2062ca5b659SJoost Mulders 0x83, 0x89, 2072ca5b659SJoost Mulders "VIA VT6105-B Rhine III Fast Ethernet", 2082ca5b659SJoost Mulders (VR_BUG_NONE), 2092ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP) 2102ca5b659SJoost Mulders }, 2112ca5b659SJoost Mulders { 2122ca5b659SJoost Mulders 0x8a, 0x8b, 2132ca5b659SJoost Mulders "VIA VT6105-LOM Rhine III Fast Ethernet", 2142ca5b659SJoost Mulders (VR_BUG_NONE), 2152ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP) 2162ca5b659SJoost Mulders }, 2172ca5b659SJoost Mulders { 2182ca5b659SJoost Mulders 0x8c, 0x8c, 2192ca5b659SJoost Mulders "VIA VT6107-A0 Rhine III Fast Ethernet", 2202ca5b659SJoost Mulders (VR_BUG_NONE), 2212ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP) 2222ca5b659SJoost Mulders }, 2232ca5b659SJoost Mulders { 2242ca5b659SJoost Mulders 0x8d, 0x8f, 2252ca5b659SJoost Mulders "VIA VT6107-A1 Rhine III Fast Ethernet", 2262ca5b659SJoost Mulders (VR_BUG_NONE), 2272ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP | 2282ca5b659SJoost Mulders VR_FEATURE_MRDLNMULTIPLE) 2292ca5b659SJoost Mulders }, 2302ca5b659SJoost Mulders { 2312ca5b659SJoost Mulders 0x90, 0x93, 2322ca5b659SJoost Mulders "VIA VT6105M-A0 Rhine III Fast Ethernet Management Adapter", 2332ca5b659SJoost Mulders (VR_BUG_NONE), 2342ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP | 2352ca5b659SJoost Mulders VR_FEATURE_TXCHKSUM | VR_FEATURE_RXCHKSUM | 2362ca5b659SJoost Mulders VR_FEATURE_CAMSUPPORT | VR_FEATURE_VLANTAGGING | 2372ca5b659SJoost Mulders VR_FEATURE_MIBCOUNTER) 2382ca5b659SJoost Mulders }, 2392ca5b659SJoost Mulders { 2402ca5b659SJoost Mulders 0x94, 0xff, 2412ca5b659SJoost Mulders "VIA VT6105M-B1 Rhine III Fast Ethernet Management Adapter", 2422ca5b659SJoost Mulders (VR_BUG_NONE), 2432ca5b659SJoost Mulders (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP | 2442ca5b659SJoost Mulders VR_FEATURE_TXCHKSUM | VR_FEATURE_RXCHKSUM | 2452ca5b659SJoost Mulders VR_FEATURE_CAMSUPPORT | VR_FEATURE_VLANTAGGING | 2462ca5b659SJoost Mulders VR_FEATURE_MIBCOUNTER) 2472ca5b659SJoost Mulders } 2482ca5b659SJoost Mulders }; 2492ca5b659SJoost Mulders 2502ca5b659SJoost Mulders /* 2512ca5b659SJoost Mulders * Function prototypes 2522ca5b659SJoost Mulders */ 2532ca5b659SJoost Mulders static vr_result_t vr_add_intr(vr_t *vrp); 2542ca5b659SJoost Mulders static void vr_remove_intr(vr_t *vrp); 2552ca5b659SJoost Mulders static int32_t vr_cam_index(vr_t *vrp, const uint8_t *maddr); 2562ca5b659SJoost Mulders static uint32_t ether_crc_be(const uint8_t *address); 2572ca5b659SJoost Mulders static void vr_tx_enqueue_msg(vr_t *vrp, mblk_t *mp); 2582ca5b659SJoost Mulders static void vr_log(vr_t *vrp, int level, const char *fmt, ...); 2592ca5b659SJoost Mulders static int vr_resume(dev_info_t *devinfo); 2602ca5b659SJoost Mulders static int vr_suspend(dev_info_t *devinfo); 2612ca5b659SJoost Mulders static vr_result_t vr_bus_config(vr_t *vrp); 2622ca5b659SJoost Mulders static void vr_bus_unconfig(vr_t *vrp); 2632ca5b659SJoost Mulders static void vr_reset(vr_t *vrp); 2642ca5b659SJoost Mulders static int vr_start(vr_t *vrp); 2652ca5b659SJoost Mulders static int vr_stop(vr_t *vrp); 2662ca5b659SJoost Mulders static vr_result_t vr_rings_init(vr_t *vrp); 2672ca5b659SJoost Mulders static void vr_rings_fini(vr_t *vrp); 2682ca5b659SJoost Mulders static vr_result_t vr_alloc_ring(vr_t *vrp, vr_ring_t *r, size_t n); 2692ca5b659SJoost Mulders static void vr_free_ring(vr_ring_t *r, size_t n); 2702ca5b659SJoost Mulders static vr_result_t vr_rxring_init(vr_t *vrp); 2712ca5b659SJoost Mulders static void vr_rxring_fini(vr_t *vrp); 2722ca5b659SJoost Mulders static vr_result_t vr_txring_init(vr_t *vrp); 2732ca5b659SJoost Mulders static void vr_txring_fini(vr_t *vrp); 2742ca5b659SJoost Mulders static vr_result_t vr_alloc_dmabuf(vr_t *vrp, vr_data_dma_t *dmap, 2752ca5b659SJoost Mulders uint_t flags); 2762ca5b659SJoost Mulders static void vr_free_dmabuf(vr_data_dma_t *dmap); 2772ca5b659SJoost Mulders static void vr_param_init(vr_t *vrp); 2782ca5b659SJoost Mulders static mblk_t *vr_receive(vr_t *vrp); 2792ca5b659SJoost Mulders static void vr_tx_reclaim(vr_t *vrp); 2802ca5b659SJoost Mulders static void vr_periodic(void *p); 2812ca5b659SJoost Mulders static void vr_error(vr_t *vrp); 2822ca5b659SJoost Mulders static void vr_phy_read(vr_t *vrp, int offset, uint16_t *value); 2832ca5b659SJoost Mulders static void vr_phy_write(vr_t *vrp, int offset, uint16_t value); 2842ca5b659SJoost Mulders static void vr_phy_autopoll_disable(vr_t *vrp); 2852ca5b659SJoost Mulders static void vr_phy_autopoll_enable(vr_t *vrp); 2862ca5b659SJoost Mulders static void vr_link_init(vr_t *vrp); 2872ca5b659SJoost Mulders static void vr_link_state(vr_t *vrp); 2882ca5b659SJoost Mulders static void vr_kstats_init(vr_t *vrp); 2892ca5b659SJoost Mulders static int vr_update_kstats(kstat_t *ksp, int access); 2902ca5b659SJoost Mulders static void vr_remove_kstats(vr_t *vrp); 2912ca5b659SJoost Mulders 2922ca5b659SJoost Mulders static int 2932ca5b659SJoost Mulders vr_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 2942ca5b659SJoost Mulders { 2952ca5b659SJoost Mulders vr_t *vrp; 2962ca5b659SJoost Mulders mac_register_t *macreg; 2972ca5b659SJoost Mulders 2982ca5b659SJoost Mulders if (cmd == DDI_RESUME) 2992ca5b659SJoost Mulders return (vr_resume(devinfo)); 3002ca5b659SJoost Mulders else if (cmd != DDI_ATTACH) 3012ca5b659SJoost Mulders return (DDI_FAILURE); 3022ca5b659SJoost Mulders 3032ca5b659SJoost Mulders /* 3042ca5b659SJoost Mulders * Attach. 3052ca5b659SJoost Mulders */ 3062ca5b659SJoost Mulders vrp = kmem_zalloc(sizeof (vr_t), KM_SLEEP); 3072ca5b659SJoost Mulders ddi_set_driver_private(devinfo, vrp); 3082ca5b659SJoost Mulders vrp->devinfo = devinfo; 3092ca5b659SJoost Mulders 3102ca5b659SJoost Mulders /* 3112ca5b659SJoost Mulders * Store the name+instance of the module. 3122ca5b659SJoost Mulders */ 3132ca5b659SJoost Mulders (void) snprintf(vrp->ifname, sizeof (vrp->ifname), "%s%d", 3142ca5b659SJoost Mulders MODULENAME, ddi_get_instance(devinfo)); 3152ca5b659SJoost Mulders 3162ca5b659SJoost Mulders /* 3172ca5b659SJoost Mulders * Bus initialization. 3182ca5b659SJoost Mulders */ 3192ca5b659SJoost Mulders if (vr_bus_config(vrp) != VR_SUCCESS) { 3202ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "vr_bus_config failed"); 3212ca5b659SJoost Mulders goto fail0; 3222ca5b659SJoost Mulders } 3232ca5b659SJoost Mulders 3242ca5b659SJoost Mulders /* 3252ca5b659SJoost Mulders * Initialize default parameters. 3262ca5b659SJoost Mulders */ 3272ca5b659SJoost Mulders vr_param_init(vrp); 3282ca5b659SJoost Mulders 3292ca5b659SJoost Mulders /* 3302ca5b659SJoost Mulders * Setup the descriptor rings. 3312ca5b659SJoost Mulders */ 3322ca5b659SJoost Mulders if (vr_rings_init(vrp) != VR_SUCCESS) { 3332ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "vr_rings_init failed"); 3342ca5b659SJoost Mulders goto fail1; 3352ca5b659SJoost Mulders } 3362ca5b659SJoost Mulders 3372ca5b659SJoost Mulders /* 3382ca5b659SJoost Mulders * Initialize kstats. 3392ca5b659SJoost Mulders */ 3402ca5b659SJoost Mulders vr_kstats_init(vrp); 3412ca5b659SJoost Mulders 3422ca5b659SJoost Mulders /* 3432ca5b659SJoost Mulders * Add interrupt to the OS. 3442ca5b659SJoost Mulders */ 3452ca5b659SJoost Mulders if (vr_add_intr(vrp) != VR_SUCCESS) { 3462ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "vr_add_intr failed in attach"); 3472ca5b659SJoost Mulders goto fail3; 3482ca5b659SJoost Mulders } 3492ca5b659SJoost Mulders 3502ca5b659SJoost Mulders /* 3512ca5b659SJoost Mulders * Add mutexes. 3522ca5b659SJoost Mulders */ 3532ca5b659SJoost Mulders mutex_init(&vrp->intrlock, NULL, MUTEX_DRIVER, 3542ca5b659SJoost Mulders DDI_INTR_PRI(vrp->intr_pri)); 3552ca5b659SJoost Mulders mutex_init(&vrp->oplock, NULL, MUTEX_DRIVER, NULL); 3562ca5b659SJoost Mulders mutex_init(&vrp->tx.lock, NULL, MUTEX_DRIVER, NULL); 3572ca5b659SJoost Mulders 3582ca5b659SJoost Mulders /* 3592ca5b659SJoost Mulders * Enable interrupt. 3602ca5b659SJoost Mulders */ 3612ca5b659SJoost Mulders if (ddi_intr_enable(vrp->intr_hdl) != DDI_SUCCESS) { 3622ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_enable failed"); 3632ca5b659SJoost Mulders goto fail5; 3642ca5b659SJoost Mulders } 3652ca5b659SJoost Mulders 3662ca5b659SJoost Mulders /* 3672ca5b659SJoost Mulders * Register with parent, mac. 3682ca5b659SJoost Mulders */ 3692ca5b659SJoost Mulders if ((macreg = mac_alloc(MAC_VERSION)) == NULL) { 3702ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "mac_alloc failed in attach"); 3712ca5b659SJoost Mulders goto fail6; 3722ca5b659SJoost Mulders } 3732ca5b659SJoost Mulders 3742ca5b659SJoost Mulders macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 3752ca5b659SJoost Mulders macreg->m_driver = vrp; 3762ca5b659SJoost Mulders macreg->m_dip = devinfo; 3772ca5b659SJoost Mulders macreg->m_src_addr = vrp->vendor_ether_addr; 3782ca5b659SJoost Mulders macreg->m_callbacks = &vr_mac_callbacks; 3792ca5b659SJoost Mulders macreg->m_min_sdu = 0; 3802ca5b659SJoost Mulders macreg->m_max_sdu = ETHERMTU; 3812ca5b659SJoost Mulders macreg->m_margin = VLAN_TAGSZ; 3822ca5b659SJoost Mulders 3832ca5b659SJoost Mulders if (mac_register(macreg, &vrp->machdl) != 0) { 3842ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "mac_register failed in attach"); 3852ca5b659SJoost Mulders goto fail7; 3862ca5b659SJoost Mulders } 3872ca5b659SJoost Mulders mac_free(macreg); 3882ca5b659SJoost Mulders return (DDI_SUCCESS); 3892ca5b659SJoost Mulders 3902ca5b659SJoost Mulders fail7: 3912ca5b659SJoost Mulders mac_free(macreg); 3922ca5b659SJoost Mulders fail6: 3932ca5b659SJoost Mulders (void) ddi_intr_disable(vrp->intr_hdl); 3942ca5b659SJoost Mulders fail5: 3952ca5b659SJoost Mulders mutex_destroy(&vrp->tx.lock); 3962ca5b659SJoost Mulders mutex_destroy(&vrp->oplock); 3972ca5b659SJoost Mulders mutex_destroy(&vrp->intrlock); 3982ca5b659SJoost Mulders vr_remove_intr(vrp); 3992ca5b659SJoost Mulders fail3: 4002ca5b659SJoost Mulders vr_remove_kstats(vrp); 4012ca5b659SJoost Mulders fail2: 4022ca5b659SJoost Mulders vr_rings_fini(vrp); 4032ca5b659SJoost Mulders fail1: 4042ca5b659SJoost Mulders vr_bus_unconfig(vrp); 4052ca5b659SJoost Mulders fail0: 4062ca5b659SJoost Mulders kmem_free(vrp, sizeof (vr_t)); 4072ca5b659SJoost Mulders return (DDI_FAILURE); 4082ca5b659SJoost Mulders } 4092ca5b659SJoost Mulders 4102ca5b659SJoost Mulders static int 4112ca5b659SJoost Mulders vr_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 4122ca5b659SJoost Mulders { 4132ca5b659SJoost Mulders vr_t *vrp; 4142ca5b659SJoost Mulders 4152ca5b659SJoost Mulders vrp = ddi_get_driver_private(devinfo); 4162ca5b659SJoost Mulders 4172ca5b659SJoost Mulders if (cmd == DDI_SUSPEND) 4182ca5b659SJoost Mulders return (vr_suspend(devinfo)); 4192ca5b659SJoost Mulders else if (cmd != DDI_DETACH) 4202ca5b659SJoost Mulders return (DDI_FAILURE); 4212ca5b659SJoost Mulders 4222ca5b659SJoost Mulders if (vrp->chip.state == CHIPSTATE_RUNNING) 4232ca5b659SJoost Mulders return (DDI_FAILURE); 4242ca5b659SJoost Mulders 4252ca5b659SJoost Mulders /* 4262ca5b659SJoost Mulders * Try to un-register from the MAC layer. 4272ca5b659SJoost Mulders */ 4282ca5b659SJoost Mulders if (mac_unregister(vrp->machdl) != 0) 4292ca5b659SJoost Mulders return (DDI_FAILURE); 4302ca5b659SJoost Mulders 4312ca5b659SJoost Mulders (void) ddi_intr_disable(vrp->intr_hdl); 4322ca5b659SJoost Mulders vr_remove_intr(vrp); 4332ca5b659SJoost Mulders mutex_destroy(&vrp->tx.lock); 4342ca5b659SJoost Mulders mutex_destroy(&vrp->oplock); 4352ca5b659SJoost Mulders mutex_destroy(&vrp->intrlock); 4362ca5b659SJoost Mulders vr_remove_kstats(vrp); 4372ca5b659SJoost Mulders vr_rings_fini(vrp); 4382ca5b659SJoost Mulders vr_bus_unconfig(vrp); 4392ca5b659SJoost Mulders kmem_free(vrp, sizeof (vr_t)); 4402ca5b659SJoost Mulders return (DDI_SUCCESS); 4412ca5b659SJoost Mulders } 4422ca5b659SJoost Mulders 4432ca5b659SJoost Mulders /* 4442ca5b659SJoost Mulders * quiesce the card for fast reboot. 4452ca5b659SJoost Mulders */ 4462ca5b659SJoost Mulders int 4472ca5b659SJoost Mulders vr_quiesce(dev_info_t *dev_info) 4482ca5b659SJoost Mulders { 4492ca5b659SJoost Mulders vr_t *vrp; 4502ca5b659SJoost Mulders 4512ca5b659SJoost Mulders vrp = (vr_t *)ddi_get_driver_private(dev_info); 4522ca5b659SJoost Mulders 4532ca5b659SJoost Mulders /* 4542ca5b659SJoost Mulders * Stop interrupts. 4552ca5b659SJoost Mulders */ 4562ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_ICR0, 0); 4572ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_ICR1, 0); 4582ca5b659SJoost Mulders 4592ca5b659SJoost Mulders /* 4602ca5b659SJoost Mulders * Stop DMA. 4612ca5b659SJoost Mulders */ 4622ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_STOP); 4632ca5b659SJoost Mulders return (DDI_SUCCESS); 4642ca5b659SJoost Mulders } 4652ca5b659SJoost Mulders 4662ca5b659SJoost Mulders /* 4672ca5b659SJoost Mulders * Add an interrupt for our device to the OS. 4682ca5b659SJoost Mulders */ 4692ca5b659SJoost Mulders static vr_result_t 4702ca5b659SJoost Mulders vr_add_intr(vr_t *vrp) 4712ca5b659SJoost Mulders { 4722ca5b659SJoost Mulders int nintrs; 4732ca5b659SJoost Mulders int rc; 4742ca5b659SJoost Mulders 4752ca5b659SJoost Mulders rc = ddi_intr_alloc(vrp->devinfo, &vrp->intr_hdl, 4762ca5b659SJoost Mulders DDI_INTR_TYPE_FIXED, /* type */ 4772ca5b659SJoost Mulders 0, /* number */ 4782ca5b659SJoost Mulders 1, /* count */ 4792ca5b659SJoost Mulders &nintrs, /* actualp */ 4802ca5b659SJoost Mulders DDI_INTR_ALLOC_STRICT); 4812ca5b659SJoost Mulders 4822ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 4832ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_alloc failed: %d", rc); 4842ca5b659SJoost Mulders return (VR_FAILURE); 4852ca5b659SJoost Mulders } 4862ca5b659SJoost Mulders 4872ca5b659SJoost Mulders rc = ddi_intr_add_handler(vrp->intr_hdl, vr_intr, vrp, NULL); 4882ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 4892ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_add_handler failed"); 4902ca5b659SJoost Mulders if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS) 4912ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_free failed"); 4922ca5b659SJoost Mulders return (VR_FAILURE); 4932ca5b659SJoost Mulders } 4942ca5b659SJoost Mulders 4952ca5b659SJoost Mulders rc = ddi_intr_get_pri(vrp->intr_hdl, &vrp->intr_pri); 4962ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 4972ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_get_pri failed"); 4982ca5b659SJoost Mulders if (ddi_intr_remove_handler(vrp->intr_hdl) != DDI_SUCCESS) 4992ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_remove_handler failed"); 5002ca5b659SJoost Mulders 5012ca5b659SJoost Mulders if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS) 5022ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_free failed"); 5032ca5b659SJoost Mulders 5042ca5b659SJoost Mulders return (VR_FAILURE); 5052ca5b659SJoost Mulders } 5062ca5b659SJoost Mulders return (VR_SUCCESS); 5072ca5b659SJoost Mulders } 5082ca5b659SJoost Mulders 5092ca5b659SJoost Mulders /* 5102ca5b659SJoost Mulders * Remove our interrupt from the OS. 5112ca5b659SJoost Mulders */ 5122ca5b659SJoost Mulders static void 5132ca5b659SJoost Mulders vr_remove_intr(vr_t *vrp) 5142ca5b659SJoost Mulders { 5152ca5b659SJoost Mulders if (ddi_intr_remove_handler(vrp->intr_hdl) != DDI_SUCCESS) 5162ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_remove_handler failed"); 5172ca5b659SJoost Mulders 5182ca5b659SJoost Mulders if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS) 5192ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "ddi_intr_free failed"); 5202ca5b659SJoost Mulders } 5212ca5b659SJoost Mulders 5222ca5b659SJoost Mulders /* 5232ca5b659SJoost Mulders * Resume operation after suspend. 5242ca5b659SJoost Mulders */ 5252ca5b659SJoost Mulders static int 5262ca5b659SJoost Mulders vr_resume(dev_info_t *devinfo) 5272ca5b659SJoost Mulders { 5282ca5b659SJoost Mulders vr_t *vrp; 5292ca5b659SJoost Mulders 5302ca5b659SJoost Mulders vrp = (vr_t *)ddi_get_driver_private(devinfo); 5312ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 5322ca5b659SJoost Mulders if (vrp->chip.state == CHIPSTATE_SUSPENDED_RUNNING) 533c1374a13SSurya Prakki (void) vr_start(vrp); 5342ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 5352ca5b659SJoost Mulders return (DDI_SUCCESS); 5362ca5b659SJoost Mulders } 5372ca5b659SJoost Mulders 5382ca5b659SJoost Mulders /* 5392ca5b659SJoost Mulders * Suspend operation. 5402ca5b659SJoost Mulders */ 5412ca5b659SJoost Mulders static int 5422ca5b659SJoost Mulders vr_suspend(dev_info_t *devinfo) 5432ca5b659SJoost Mulders { 5442ca5b659SJoost Mulders vr_t *vrp; 5452ca5b659SJoost Mulders 5462ca5b659SJoost Mulders vrp = (vr_t *)ddi_get_driver_private(devinfo); 5472ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 5482ca5b659SJoost Mulders if (vrp->chip.state == CHIPSTATE_RUNNING) { 5492ca5b659SJoost Mulders (void) vr_stop(vrp); 5502ca5b659SJoost Mulders vrp->chip.state = CHIPSTATE_SUSPENDED_RUNNING; 5512ca5b659SJoost Mulders } 5522ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 5532ca5b659SJoost Mulders return (DDI_SUCCESS); 5542ca5b659SJoost Mulders } 5552ca5b659SJoost Mulders 5562ca5b659SJoost Mulders /* 5572ca5b659SJoost Mulders * Initial bus- and device configuration during attach(9E). 5582ca5b659SJoost Mulders */ 5592ca5b659SJoost Mulders static vr_result_t 5602ca5b659SJoost Mulders vr_bus_config(vr_t *vrp) 5612ca5b659SJoost Mulders { 5622ca5b659SJoost Mulders uint32_t addr; 5632ca5b659SJoost Mulders int n, nsets, rc; 5642ca5b659SJoost Mulders uint_t elem; 5652ca5b659SJoost Mulders pci_regspec_t *regs; 5662ca5b659SJoost Mulders 5672ca5b659SJoost Mulders /* 5682ca5b659SJoost Mulders * Get the reg property which describes the various access methods. 5692ca5b659SJoost Mulders */ 5702ca5b659SJoost Mulders if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, vrp->devinfo, 5712ca5b659SJoost Mulders 0, "reg", (int **)®s, &elem) != DDI_PROP_SUCCESS) { 5722ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "Can't get reg property"); 5732ca5b659SJoost Mulders return (VR_FAILURE); 5742ca5b659SJoost Mulders } 5752ca5b659SJoost Mulders nsets = (elem * sizeof (uint_t)) / sizeof (pci_regspec_t); 5762ca5b659SJoost Mulders 5772ca5b659SJoost Mulders /* 5782ca5b659SJoost Mulders * Setup access to all available sets. 5792ca5b659SJoost Mulders */ 5802ca5b659SJoost Mulders vrp->nsets = nsets; 5812ca5b659SJoost Mulders vrp->regset = kmem_zalloc(nsets * sizeof (vr_acc_t), KM_SLEEP); 5822ca5b659SJoost Mulders for (n = 0; n < nsets; n++) { 5832ca5b659SJoost Mulders rc = ddi_regs_map_setup(vrp->devinfo, n, 5842ca5b659SJoost Mulders &vrp->regset[n].addr, 0, 0, 5852ca5b659SJoost Mulders &vr_dev_dma_accattr, 5862ca5b659SJoost Mulders &vrp->regset[n].hdl); 5872ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 5882ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, 5892ca5b659SJoost Mulders "Setup of register set %d failed", n); 5902ca5b659SJoost Mulders while (--n >= 0) 5912ca5b659SJoost Mulders ddi_regs_map_free(&vrp->regset[n].hdl); 5922ca5b659SJoost Mulders kmem_free(vrp->regset, nsets * sizeof (vr_acc_t)); 5932ca5b659SJoost Mulders ddi_prop_free(regs); 5942ca5b659SJoost Mulders return (VR_FAILURE); 5952ca5b659SJoost Mulders } 5962ca5b659SJoost Mulders bcopy(®s[n], &vrp->regset[n].reg, sizeof (pci_regspec_t)); 5972ca5b659SJoost Mulders } 5982ca5b659SJoost Mulders ddi_prop_free(regs); 5992ca5b659SJoost Mulders 6002ca5b659SJoost Mulders /* 6012ca5b659SJoost Mulders * Assign type-named pointers to the register sets. 6022ca5b659SJoost Mulders */ 6032ca5b659SJoost Mulders for (n = 0; n < nsets; n++) { 6042ca5b659SJoost Mulders addr = vrp->regset[n].reg.pci_phys_hi & PCI_REG_ADDR_M; 6052ca5b659SJoost Mulders if (addr == PCI_ADDR_CONFIG && vrp->acc_cfg == NULL) 6062ca5b659SJoost Mulders vrp->acc_cfg = &vrp->regset[n]; 6072ca5b659SJoost Mulders else if (addr == PCI_ADDR_IO && vrp->acc_io == NULL) 6082ca5b659SJoost Mulders vrp->acc_io = &vrp->regset[n]; 6092ca5b659SJoost Mulders else if (addr == PCI_ADDR_MEM32 && vrp->acc_mem == NULL) 6102ca5b659SJoost Mulders vrp->acc_mem = &vrp->regset[n]; 6112ca5b659SJoost Mulders } 6122ca5b659SJoost Mulders 6132ca5b659SJoost Mulders /* 6142ca5b659SJoost Mulders * Assure there is one of each type. 6152ca5b659SJoost Mulders */ 6162ca5b659SJoost Mulders if (vrp->acc_cfg == NULL || 6172ca5b659SJoost Mulders vrp->acc_io == NULL || 6182ca5b659SJoost Mulders vrp->acc_mem == NULL) { 6192ca5b659SJoost Mulders for (n = 0; n < nsets; n++) 6202ca5b659SJoost Mulders ddi_regs_map_free(&vrp->regset[n].hdl); 6212ca5b659SJoost Mulders kmem_free(vrp->regset, nsets * sizeof (vr_acc_t)); 6222ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 6232ca5b659SJoost Mulders "Config-, I/O- and memory sets not available"); 6242ca5b659SJoost Mulders return (VR_FAILURE); 6252ca5b659SJoost Mulders } 6262ca5b659SJoost Mulders 6272ca5b659SJoost Mulders /* 6282ca5b659SJoost Mulders * Store vendor/device/revision. 6292ca5b659SJoost Mulders */ 6302ca5b659SJoost Mulders vrp->chip.vendor = VR_GET16(vrp->acc_cfg, PCI_CONF_VENID); 6312ca5b659SJoost Mulders vrp->chip.device = VR_GET16(vrp->acc_cfg, PCI_CONF_DEVID); 6322ca5b659SJoost Mulders vrp->chip.revision = VR_GET16(vrp->acc_cfg, PCI_CONF_REVID); 6332ca5b659SJoost Mulders 6342ca5b659SJoost Mulders /* 6352ca5b659SJoost Mulders * Copy the matching chip_info_t structure. 6362ca5b659SJoost Mulders */ 6372ca5b659SJoost Mulders elem = sizeof (vr_chip_info) / sizeof (chip_info_t); 6382ca5b659SJoost Mulders for (n = 0; n < elem; n++) { 6392ca5b659SJoost Mulders if (vrp->chip.revision >= vr_chip_info[n].revmin && 6402ca5b659SJoost Mulders vrp->chip.revision <= vr_chip_info[n].revmax) { 6412ca5b659SJoost Mulders bcopy((void*)&vr_chip_info[n], 6422ca5b659SJoost Mulders (void*)&vrp->chip.info, 6432ca5b659SJoost Mulders sizeof (chip_info_t)); 6442ca5b659SJoost Mulders break; 6452ca5b659SJoost Mulders } 6462ca5b659SJoost Mulders } 6472ca5b659SJoost Mulders 6482ca5b659SJoost Mulders /* 6492ca5b659SJoost Mulders * If we didn't find a chip_info_t for this card, copy the first 6502ca5b659SJoost Mulders * entry of the info structures. This is a generic Rhine whith no 6512ca5b659SJoost Mulders * bugs and no features. 6522ca5b659SJoost Mulders */ 6532ca5b659SJoost Mulders if (vrp->chip.info.name == NULL) { 6542ca5b659SJoost Mulders bcopy((void*)&vr_chip_info[0], 6552ca5b659SJoost Mulders (void*) &vrp->chip.info, 6562ca5b659SJoost Mulders sizeof (chip_info_t)); 6572ca5b659SJoost Mulders } 6582ca5b659SJoost Mulders 6592ca5b659SJoost Mulders /* 6602ca5b659SJoost Mulders * Tell what is found. 6612ca5b659SJoost Mulders */ 6622ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "pci%d,%d,%d: %s, revision 0x%0x", 6632ca5b659SJoost Mulders PCI_REG_BUS_G(vrp->acc_cfg->reg.pci_phys_hi), 6642ca5b659SJoost Mulders PCI_REG_DEV_G(vrp->acc_cfg->reg.pci_phys_hi), 6652ca5b659SJoost Mulders PCI_REG_FUNC_G(vrp->acc_cfg->reg.pci_phys_hi), 6662ca5b659SJoost Mulders vrp->chip.info.name, 6672ca5b659SJoost Mulders vrp->chip.revision); 6682ca5b659SJoost Mulders 6692ca5b659SJoost Mulders /* 6702ca5b659SJoost Mulders * Assure that the device is prepared for memory space accesses 6712ca5b659SJoost Mulders * This should be the default as the device advertises memory 6722ca5b659SJoost Mulders * access in it's BAR's. However, my VT6102 on a EPIA CL board doesn't 6732ca5b659SJoost Mulders * and thus we explicetely enable it. 6742ca5b659SJoost Mulders */ 6752ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_io, VR_CFGD, VR_CFGD_MMIOEN); 6762ca5b659SJoost Mulders 6772ca5b659SJoost Mulders /* 6782ca5b659SJoost Mulders * Setup a handle for regular usage, prefer memory space accesses. 6792ca5b659SJoost Mulders */ 6802ca5b659SJoost Mulders if (vrp->acc_mem != NULL && 6812ca5b659SJoost Mulders (vrp->chip.info.bugs & VR_BUG_NO_MEMIO) == 0) 6822ca5b659SJoost Mulders vrp->acc_reg = vrp->acc_mem; 6832ca5b659SJoost Mulders else 6842ca5b659SJoost Mulders vrp->acc_reg = vrp->acc_io; 6852ca5b659SJoost Mulders 6862ca5b659SJoost Mulders /* 6872ca5b659SJoost Mulders * Store the vendor's MAC address. 6882ca5b659SJoost Mulders */ 6892ca5b659SJoost Mulders for (n = 0; n < ETHERADDRL; n++) { 6902ca5b659SJoost Mulders vrp->vendor_ether_addr[n] = VR_GET8(vrp->acc_reg, 6912ca5b659SJoost Mulders VR_ETHERADDR + n); 6922ca5b659SJoost Mulders } 6932ca5b659SJoost Mulders return (VR_SUCCESS); 6942ca5b659SJoost Mulders } 6952ca5b659SJoost Mulders 6962ca5b659SJoost Mulders static void 6972ca5b659SJoost Mulders vr_bus_unconfig(vr_t *vrp) 6982ca5b659SJoost Mulders { 6992ca5b659SJoost Mulders uint_t n; 7002ca5b659SJoost Mulders 7012ca5b659SJoost Mulders /* 7022ca5b659SJoost Mulders * Free the register access handles. 7032ca5b659SJoost Mulders */ 7042ca5b659SJoost Mulders for (n = 0; n < vrp->nsets; n++) 7052ca5b659SJoost Mulders ddi_regs_map_free(&vrp->regset[n].hdl); 7062ca5b659SJoost Mulders kmem_free(vrp->regset, vrp->nsets * sizeof (vr_acc_t)); 7072ca5b659SJoost Mulders } 7082ca5b659SJoost Mulders 7092ca5b659SJoost Mulders /* 7102ca5b659SJoost Mulders * Initialize parameter structures. 7112ca5b659SJoost Mulders */ 7122ca5b659SJoost Mulders static void 7132ca5b659SJoost Mulders vr_param_init(vr_t *vrp) 7142ca5b659SJoost Mulders { 7152ca5b659SJoost Mulders /* 7162ca5b659SJoost Mulders * Initialize default link configuration parameters. 7172ca5b659SJoost Mulders */ 7182ca5b659SJoost Mulders vrp->param.an_en = VR_LINK_AUTONEG_ON; 7192ca5b659SJoost Mulders vrp->param.anadv_en = 1; /* Select 802.3 autonegotiation */ 7202ca5b659SJoost Mulders vrp->param.anadv_en |= MII_ABILITY_100BASE_T4; 7212ca5b659SJoost Mulders vrp->param.anadv_en |= MII_ABILITY_100BASE_TX_FD; 7222ca5b659SJoost Mulders vrp->param.anadv_en |= MII_ABILITY_100BASE_TX; 7232ca5b659SJoost Mulders vrp->param.anadv_en |= MII_ABILITY_10BASE_T_FD; 7242ca5b659SJoost Mulders vrp->param.anadv_en |= MII_ABILITY_10BASE_T; 7252ca5b659SJoost Mulders /* Not a PHY ability, but advertised on behalf of MAC */ 726bdb9230aSGarrett D'Amore vrp->param.anadv_en |= MII_ABILITY_PAUSE; 7272ca5b659SJoost Mulders vrp->param.mtu = ETHERMTU; 7282ca5b659SJoost Mulders 7292ca5b659SJoost Mulders /* 7302ca5b659SJoost Mulders * Store the PHY identity. 7312ca5b659SJoost Mulders */ 7322ca5b659SJoost Mulders vr_phy_read(vrp, MII_PHYIDH, &vrp->chip.mii.identh); 7332ca5b659SJoost Mulders vr_phy_read(vrp, MII_PHYIDL, &vrp->chip.mii.identl); 7342ca5b659SJoost Mulders 7352ca5b659SJoost Mulders /* 7362ca5b659SJoost Mulders * Clear incapabilities imposed by PHY in phymask. 7372ca5b659SJoost Mulders */ 7382ca5b659SJoost Mulders vrp->param.an_phymask = vrp->param.anadv_en; 7392ca5b659SJoost Mulders vr_phy_read(vrp, MII_STATUS, &vrp->chip.mii.status); 7402ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_10) == 0) 7412ca5b659SJoost Mulders vrp->param.an_phymask &= ~MII_ABILITY_10BASE_T; 7422ca5b659SJoost Mulders 7432ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_10_FD) == 0) 7442ca5b659SJoost Mulders vrp->param.an_phymask &= ~MII_ABILITY_10BASE_T_FD; 7452ca5b659SJoost Mulders 7462ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_100_BASEX) == 0) 7472ca5b659SJoost Mulders vrp->param.an_phymask &= ~MII_ABILITY_100BASE_TX; 7482ca5b659SJoost Mulders 7492ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_100_BASEX_FD) == 0) 7502ca5b659SJoost Mulders vrp->param.an_phymask &= ~MII_ABILITY_100BASE_TX_FD; 7512ca5b659SJoost Mulders 7522ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_100_BASE_T4) == 0) 7532ca5b659SJoost Mulders vrp->param.an_phymask &= ~MII_ABILITY_100BASE_T4; 7542ca5b659SJoost Mulders 7552ca5b659SJoost Mulders /* 7562ca5b659SJoost Mulders * Clear incapabilities imposed by MAC in macmask 7572ca5b659SJoost Mulders * Note that flowcontrol (FCS?) is never masked. All of our adapters 7582ca5b659SJoost Mulders * have the ability to honor incoming pause frames. Only the newer can 7592ca5b659SJoost Mulders * transmit pause frames. Since there's no asym flowcontrol in 100Mbit 7602ca5b659SJoost Mulders * Ethernet, we always advertise (symmetric) pause. 7612ca5b659SJoost Mulders */ 7622ca5b659SJoost Mulders vrp->param.an_macmask = vrp->param.anadv_en; 7632ca5b659SJoost Mulders 7642ca5b659SJoost Mulders /* 7652ca5b659SJoost Mulders * Advertised capabilities is enabled minus incapable. 7662ca5b659SJoost Mulders */ 7672ca5b659SJoost Mulders vrp->chip.mii.anadv = vrp->param.anadv_en & 7682ca5b659SJoost Mulders (vrp->param.an_phymask & vrp->param.an_macmask); 7692ca5b659SJoost Mulders 7702ca5b659SJoost Mulders /* 7712ca5b659SJoost Mulders * Ensure that autoneg of the PHY matches our default. 7722ca5b659SJoost Mulders */ 7732ca5b659SJoost Mulders if (vrp->param.an_en == VR_LINK_AUTONEG_ON) 7742ca5b659SJoost Mulders vrp->chip.mii.control = MII_CONTROL_ANE; 7752ca5b659SJoost Mulders else 7762ca5b659SJoost Mulders vrp->chip.mii.control = 7772ca5b659SJoost Mulders (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX); 7782ca5b659SJoost Mulders } 7792ca5b659SJoost Mulders 7802ca5b659SJoost Mulders /* 7812ca5b659SJoost Mulders * Setup the descriptor rings. 7822ca5b659SJoost Mulders */ 7832ca5b659SJoost Mulders static vr_result_t 7842ca5b659SJoost Mulders vr_rings_init(vr_t *vrp) 7852ca5b659SJoost Mulders { 7862ca5b659SJoost Mulders 7872ca5b659SJoost Mulders vrp->rx.ndesc = VR_RX_N_DESC; 7882ca5b659SJoost Mulders vrp->tx.ndesc = VR_TX_N_DESC; 7892ca5b659SJoost Mulders 7902ca5b659SJoost Mulders /* 7912ca5b659SJoost Mulders * Create a ring for receive. 7922ca5b659SJoost Mulders */ 7932ca5b659SJoost Mulders if (vr_alloc_ring(vrp, &vrp->rxring, vrp->rx.ndesc) != VR_SUCCESS) 7942ca5b659SJoost Mulders return (VR_FAILURE); 7952ca5b659SJoost Mulders 7962ca5b659SJoost Mulders /* 7972ca5b659SJoost Mulders * Create a ring for transmit. 7982ca5b659SJoost Mulders */ 7992ca5b659SJoost Mulders if (vr_alloc_ring(vrp, &vrp->txring, vrp->tx.ndesc) != VR_SUCCESS) { 8002ca5b659SJoost Mulders vr_free_ring(&vrp->rxring, vrp->rx.ndesc); 8012ca5b659SJoost Mulders return (VR_FAILURE); 8022ca5b659SJoost Mulders } 8032ca5b659SJoost Mulders 8042ca5b659SJoost Mulders vrp->rx.ring = vrp->rxring.desc; 8052ca5b659SJoost Mulders vrp->tx.ring = vrp->txring.desc; 8062ca5b659SJoost Mulders return (VR_SUCCESS); 8072ca5b659SJoost Mulders } 8082ca5b659SJoost Mulders 8092ca5b659SJoost Mulders static void 8102ca5b659SJoost Mulders vr_rings_fini(vr_t *vrp) 8112ca5b659SJoost Mulders { 8122ca5b659SJoost Mulders vr_free_ring(&vrp->rxring, vrp->rx.ndesc); 8132ca5b659SJoost Mulders vr_free_ring(&vrp->txring, vrp->tx.ndesc); 8142ca5b659SJoost Mulders } 8152ca5b659SJoost Mulders 8162ca5b659SJoost Mulders /* 8172ca5b659SJoost Mulders * Allocate a descriptor ring 8182ca5b659SJoost Mulders * The number of descriptor entries must fit in a single page so that the 8192ca5b659SJoost Mulders * whole ring fits in one consequtive space. 8202ca5b659SJoost Mulders * i386: 4K page / 16 byte descriptor = 256 entries 8212ca5b659SJoost Mulders * sparc: 8K page / 16 byte descriptor = 512 entries 8222ca5b659SJoost Mulders */ 8232ca5b659SJoost Mulders static vr_result_t 8242ca5b659SJoost Mulders vr_alloc_ring(vr_t *vrp, vr_ring_t *ring, size_t n) 8252ca5b659SJoost Mulders { 8262ca5b659SJoost Mulders ddi_dma_cookie_t desc_dma_cookie; 8272ca5b659SJoost Mulders uint_t desc_cookiecnt; 8282ca5b659SJoost Mulders int i, rc; 8292ca5b659SJoost Mulders size_t rbytes; 8302ca5b659SJoost Mulders 8312ca5b659SJoost Mulders /* 8322ca5b659SJoost Mulders * Allocate a DMA handle for the chip descriptors. 8332ca5b659SJoost Mulders */ 8342ca5b659SJoost Mulders rc = ddi_dma_alloc_handle(vrp->devinfo, 8352ca5b659SJoost Mulders &vr_dev_dma_attr, 8362ca5b659SJoost Mulders DDI_DMA_SLEEP, 8372ca5b659SJoost Mulders NULL, 8382ca5b659SJoost Mulders &ring->handle); 8392ca5b659SJoost Mulders 8402ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 8412ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 8422ca5b659SJoost Mulders "ddi_dma_alloc_handle in vr_alloc_ring failed."); 8432ca5b659SJoost Mulders return (VR_FAILURE); 8442ca5b659SJoost Mulders } 8452ca5b659SJoost Mulders 8462ca5b659SJoost Mulders /* 8472ca5b659SJoost Mulders * Allocate memory for the chip descriptors. 8482ca5b659SJoost Mulders */ 8492ca5b659SJoost Mulders rc = ddi_dma_mem_alloc(ring->handle, 8502ca5b659SJoost Mulders n * sizeof (vr_chip_desc_t), 8512ca5b659SJoost Mulders &vr_dev_dma_accattr, 8522ca5b659SJoost Mulders DDI_DMA_CONSISTENT, 8532ca5b659SJoost Mulders DDI_DMA_SLEEP, 8542ca5b659SJoost Mulders NULL, 8552ca5b659SJoost Mulders (caddr_t *)&ring->cdesc, 8562ca5b659SJoost Mulders &rbytes, 8572ca5b659SJoost Mulders &ring->acchdl); 8582ca5b659SJoost Mulders 8592ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 8602ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 8612ca5b659SJoost Mulders "ddi_dma_mem_alloc in vr_alloc_ring failed."); 8622ca5b659SJoost Mulders ddi_dma_free_handle(&ring->handle); 8632ca5b659SJoost Mulders return (VR_FAILURE); 8642ca5b659SJoost Mulders } 8652ca5b659SJoost Mulders 8662ca5b659SJoost Mulders /* 8672ca5b659SJoost Mulders * Map the descriptor memory. 8682ca5b659SJoost Mulders */ 8692ca5b659SJoost Mulders rc = ddi_dma_addr_bind_handle(ring->handle, 8702ca5b659SJoost Mulders NULL, 8712ca5b659SJoost Mulders (caddr_t)ring->cdesc, 8722ca5b659SJoost Mulders rbytes, 8732ca5b659SJoost Mulders DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 8742ca5b659SJoost Mulders DDI_DMA_SLEEP, 8752ca5b659SJoost Mulders NULL, 8762ca5b659SJoost Mulders &desc_dma_cookie, 8772ca5b659SJoost Mulders &desc_cookiecnt); 8782ca5b659SJoost Mulders 8792ca5b659SJoost Mulders if (rc != DDI_DMA_MAPPED || desc_cookiecnt > 1) { 8802ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 8812ca5b659SJoost Mulders "ddi_dma_addr_bind_handle in vr_alloc_ring failed: " 8822ca5b659SJoost Mulders "rc = %d, cookiecnt = %d", rc, desc_cookiecnt); 8832ca5b659SJoost Mulders ddi_dma_mem_free(&ring->acchdl); 8842ca5b659SJoost Mulders ddi_dma_free_handle(&ring->handle); 8852ca5b659SJoost Mulders return (VR_FAILURE); 8862ca5b659SJoost Mulders } 8872ca5b659SJoost Mulders ring->cdesc_paddr = desc_dma_cookie.dmac_address; 8882ca5b659SJoost Mulders 8892ca5b659SJoost Mulders /* 8902ca5b659SJoost Mulders * Allocate memory for the host descriptor ring. 8912ca5b659SJoost Mulders */ 8922ca5b659SJoost Mulders ring->desc = 8932ca5b659SJoost Mulders (vr_desc_t *)kmem_zalloc(n * sizeof (vr_desc_t), KM_SLEEP); 8942ca5b659SJoost Mulders 8952ca5b659SJoost Mulders /* 8962ca5b659SJoost Mulders * Interlink the descriptors and connect host- to chip descriptors. 8972ca5b659SJoost Mulders */ 8982ca5b659SJoost Mulders for (i = 0; i < n; i++) { 8992ca5b659SJoost Mulders /* 9002ca5b659SJoost Mulders * Connect the host descriptor to a chip descriptor. 9012ca5b659SJoost Mulders */ 9022ca5b659SJoost Mulders ring->desc[i].cdesc = &ring->cdesc[i]; 9032ca5b659SJoost Mulders 9042ca5b659SJoost Mulders /* 9052ca5b659SJoost Mulders * Store the DMA address and offset in the descriptor 9062ca5b659SJoost Mulders * Offset is for ddi_dma_sync() and paddr is for ddi_get/-put(). 9072ca5b659SJoost Mulders */ 9082ca5b659SJoost Mulders ring->desc[i].offset = i * sizeof (vr_chip_desc_t); 9092ca5b659SJoost Mulders ring->desc[i].paddr = ring->cdesc_paddr + ring->desc[i].offset; 9102ca5b659SJoost Mulders 9112ca5b659SJoost Mulders /* 9122ca5b659SJoost Mulders * Link the previous descriptor to this one. 9132ca5b659SJoost Mulders */ 9142ca5b659SJoost Mulders if (i > 0) { 9152ca5b659SJoost Mulders /* Host */ 9162ca5b659SJoost Mulders ring->desc[i-1].next = &ring->desc[i]; 9172ca5b659SJoost Mulders 9182ca5b659SJoost Mulders /* Chip */ 9192ca5b659SJoost Mulders ddi_put32(ring->acchdl, 9202ca5b659SJoost Mulders &ring->cdesc[i-1].next, 9212ca5b659SJoost Mulders ring->desc[i].paddr); 9222ca5b659SJoost Mulders } 9232ca5b659SJoost Mulders } 9242ca5b659SJoost Mulders 9252ca5b659SJoost Mulders /* 9262ca5b659SJoost Mulders * Make rings out of this list by pointing last to first. 9272ca5b659SJoost Mulders */ 9282ca5b659SJoost Mulders i = n - 1; 9292ca5b659SJoost Mulders ring->desc[i].next = &ring->desc[0]; 9302ca5b659SJoost Mulders ddi_put32(ring->acchdl, &ring->cdesc[i].next, ring->desc[0].paddr); 9312ca5b659SJoost Mulders return (VR_SUCCESS); 9322ca5b659SJoost Mulders } 9332ca5b659SJoost Mulders 9342ca5b659SJoost Mulders /* 9352ca5b659SJoost Mulders * Free the memory allocated for a ring. 9362ca5b659SJoost Mulders */ 9372ca5b659SJoost Mulders static void 9382ca5b659SJoost Mulders vr_free_ring(vr_ring_t *r, size_t n) 9392ca5b659SJoost Mulders { 9402ca5b659SJoost Mulders /* 9412ca5b659SJoost Mulders * Unmap and free the chip descriptors. 9422ca5b659SJoost Mulders */ 9432ca5b659SJoost Mulders (void) ddi_dma_unbind_handle(r->handle); 9442ca5b659SJoost Mulders ddi_dma_mem_free(&r->acchdl); 9452ca5b659SJoost Mulders ddi_dma_free_handle(&r->handle); 9462ca5b659SJoost Mulders 9472ca5b659SJoost Mulders /* 9482ca5b659SJoost Mulders * Free the memory for storing host descriptors 9492ca5b659SJoost Mulders */ 9502ca5b659SJoost Mulders kmem_free(r->desc, n * sizeof (vr_desc_t)); 9512ca5b659SJoost Mulders } 9522ca5b659SJoost Mulders 9532ca5b659SJoost Mulders /* 9542ca5b659SJoost Mulders * Initialize the receive ring. 9552ca5b659SJoost Mulders */ 9562ca5b659SJoost Mulders static vr_result_t 9572ca5b659SJoost Mulders vr_rxring_init(vr_t *vrp) 9582ca5b659SJoost Mulders { 9592ca5b659SJoost Mulders int i, rc; 9602ca5b659SJoost Mulders vr_desc_t *rp; 9612ca5b659SJoost Mulders 9622ca5b659SJoost Mulders /* 9632ca5b659SJoost Mulders * Set the read pointer at the start of the ring. 9642ca5b659SJoost Mulders */ 9652ca5b659SJoost Mulders vrp->rx.rp = &vrp->rx.ring[0]; 9662ca5b659SJoost Mulders 9672ca5b659SJoost Mulders /* 9682ca5b659SJoost Mulders * Assign a DMA buffer to each receive descriptor. 9692ca5b659SJoost Mulders */ 9702ca5b659SJoost Mulders for (i = 0; i < vrp->rx.ndesc; i++) { 9712ca5b659SJoost Mulders rp = &vrp->rx.ring[i]; 9722ca5b659SJoost Mulders rc = vr_alloc_dmabuf(vrp, 9732ca5b659SJoost Mulders &vrp->rx.ring[i].dmabuf, 9742ca5b659SJoost Mulders DDI_DMA_STREAMING | DDI_DMA_READ); 9752ca5b659SJoost Mulders 9762ca5b659SJoost Mulders if (rc != VR_SUCCESS) { 9772ca5b659SJoost Mulders while (--i >= 0) 9782ca5b659SJoost Mulders vr_free_dmabuf(&vrp->rx.ring[i].dmabuf); 9792ca5b659SJoost Mulders return (VR_FAILURE); 9802ca5b659SJoost Mulders } 9812ca5b659SJoost Mulders 9822ca5b659SJoost Mulders /* 9832ca5b659SJoost Mulders * Store the address of the dma buffer in the chip descriptor 9842ca5b659SJoost Mulders */ 9852ca5b659SJoost Mulders ddi_put32(vrp->rxring.acchdl, 9862ca5b659SJoost Mulders &rp->cdesc->data, 9872ca5b659SJoost Mulders rp->dmabuf.paddr); 9882ca5b659SJoost Mulders 9892ca5b659SJoost Mulders /* 9902ca5b659SJoost Mulders * Put the buffer length in the chip descriptor. Ensure that 9912ca5b659SJoost Mulders * length fits in the 11 bits of stat1 (2047/0x7FF) 9922ca5b659SJoost Mulders */ 9932ca5b659SJoost Mulders ddi_put32(vrp->rxring.acchdl, &rp->cdesc->stat1, 9942ca5b659SJoost Mulders MIN(VR_MAX_PKTSZ, rp->dmabuf.bufsz)); 9952ca5b659SJoost Mulders 9962ca5b659SJoost Mulders /* 9972ca5b659SJoost Mulders * Set descriptor ownership to the card 9982ca5b659SJoost Mulders */ 9992ca5b659SJoost Mulders ddi_put32(vrp->rxring.acchdl, &rp->cdesc->stat0, VR_RDES0_OWN); 10002ca5b659SJoost Mulders 10012ca5b659SJoost Mulders /* 10022ca5b659SJoost Mulders * Sync the descriptor with main memory 10032ca5b659SJoost Mulders */ 10042ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->rxring.handle, rp->offset, 10052ca5b659SJoost Mulders sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORDEV); 10062ca5b659SJoost Mulders } 10072ca5b659SJoost Mulders return (VR_SUCCESS); 10082ca5b659SJoost Mulders } 10092ca5b659SJoost Mulders 10102ca5b659SJoost Mulders /* 10112ca5b659SJoost Mulders * Free the DMA buffers assigned to the receive ring. 10122ca5b659SJoost Mulders */ 10132ca5b659SJoost Mulders static void 10142ca5b659SJoost Mulders vr_rxring_fini(vr_t *vrp) 10152ca5b659SJoost Mulders { 10162ca5b659SJoost Mulders int i; 10172ca5b659SJoost Mulders 10182ca5b659SJoost Mulders for (i = 0; i < vrp->rx.ndesc; i++) 10192ca5b659SJoost Mulders vr_free_dmabuf(&vrp->rx.ring[i].dmabuf); 10202ca5b659SJoost Mulders } 10212ca5b659SJoost Mulders 10222ca5b659SJoost Mulders static vr_result_t 10232ca5b659SJoost Mulders vr_txring_init(vr_t *vrp) 10242ca5b659SJoost Mulders { 10252ca5b659SJoost Mulders vr_desc_t *wp; 10262ca5b659SJoost Mulders int i, rc; 10272ca5b659SJoost Mulders 10282ca5b659SJoost Mulders /* 10292ca5b659SJoost Mulders * Set the write- and claim pointer. 10302ca5b659SJoost Mulders */ 10312ca5b659SJoost Mulders vrp->tx.wp = &vrp->tx.ring[0]; 10322ca5b659SJoost Mulders vrp->tx.cp = &vrp->tx.ring[0]; 10332ca5b659SJoost Mulders 10342ca5b659SJoost Mulders /* 10352ca5b659SJoost Mulders * (Re)set the TX bookkeeping. 10362ca5b659SJoost Mulders */ 10372ca5b659SJoost Mulders vrp->tx.stallticks = 0; 10382ca5b659SJoost Mulders vrp->tx.resched = 0; 10392ca5b659SJoost Mulders 10402ca5b659SJoost Mulders /* 10412ca5b659SJoost Mulders * Every transmit decreases nfree. Every reclaim increases nfree. 10422ca5b659SJoost Mulders */ 10432ca5b659SJoost Mulders vrp->tx.nfree = vrp->tx.ndesc; 10442ca5b659SJoost Mulders 10452ca5b659SJoost Mulders /* 10462ca5b659SJoost Mulders * Attach a DMA buffer to each transmit descriptor. 10472ca5b659SJoost Mulders */ 10482ca5b659SJoost Mulders for (i = 0; i < vrp->tx.ndesc; i++) { 10492ca5b659SJoost Mulders rc = vr_alloc_dmabuf(vrp, 10502ca5b659SJoost Mulders &vrp->tx.ring[i].dmabuf, 10512ca5b659SJoost Mulders DDI_DMA_STREAMING | DDI_DMA_WRITE); 10522ca5b659SJoost Mulders 10532ca5b659SJoost Mulders if (rc != VR_SUCCESS) { 10542ca5b659SJoost Mulders while (--i >= 0) 10552ca5b659SJoost Mulders vr_free_dmabuf(&vrp->tx.ring[i].dmabuf); 10562ca5b659SJoost Mulders return (VR_FAILURE); 10572ca5b659SJoost Mulders } 10582ca5b659SJoost Mulders } 10592ca5b659SJoost Mulders 10602ca5b659SJoost Mulders /* 10612ca5b659SJoost Mulders * Init & sync the TX descriptors so the device sees a valid ring. 10622ca5b659SJoost Mulders */ 10632ca5b659SJoost Mulders for (i = 0; i < vrp->tx.ndesc; i++) { 10642ca5b659SJoost Mulders wp = &vrp->tx.ring[i]; 10652ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat0, 0); 10662ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat1, 0); 10672ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->data, 10682ca5b659SJoost Mulders wp->dmabuf.paddr); 10692ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->txring.handle, wp->offset, 10702ca5b659SJoost Mulders sizeof (vr_chip_desc_t), 10712ca5b659SJoost Mulders DDI_DMA_SYNC_FORDEV); 10722ca5b659SJoost Mulders } 10732ca5b659SJoost Mulders return (VR_SUCCESS); 10742ca5b659SJoost Mulders } 10752ca5b659SJoost Mulders 10762ca5b659SJoost Mulders /* 10772ca5b659SJoost Mulders * Free the DMA buffers attached to the TX ring. 10782ca5b659SJoost Mulders */ 10792ca5b659SJoost Mulders static void 10802ca5b659SJoost Mulders vr_txring_fini(vr_t *vrp) 10812ca5b659SJoost Mulders { 10822ca5b659SJoost Mulders int i; 10832ca5b659SJoost Mulders 10842ca5b659SJoost Mulders /* 10852ca5b659SJoost Mulders * Free the DMA buffers attached to the TX ring 10862ca5b659SJoost Mulders */ 10872ca5b659SJoost Mulders for (i = 0; i < vrp->tx.ndesc; i++) 10882ca5b659SJoost Mulders vr_free_dmabuf(&vrp->tx.ring[i].dmabuf); 10892ca5b659SJoost Mulders } 10902ca5b659SJoost Mulders 10912ca5b659SJoost Mulders /* 10922ca5b659SJoost Mulders * Allocate a DMA buffer. 10932ca5b659SJoost Mulders */ 10942ca5b659SJoost Mulders static vr_result_t 10952ca5b659SJoost Mulders vr_alloc_dmabuf(vr_t *vrp, vr_data_dma_t *dmap, uint_t dmaflags) 10962ca5b659SJoost Mulders { 10972ca5b659SJoost Mulders ddi_dma_cookie_t dma_cookie; 10982ca5b659SJoost Mulders uint_t cookiecnt; 10992ca5b659SJoost Mulders int rc; 11002ca5b659SJoost Mulders 11012ca5b659SJoost Mulders /* 11022ca5b659SJoost Mulders * Allocate a DMA handle for the buffer 11032ca5b659SJoost Mulders */ 11042ca5b659SJoost Mulders rc = ddi_dma_alloc_handle(vrp->devinfo, 11052ca5b659SJoost Mulders &vr_data_dma_attr, 11062ca5b659SJoost Mulders DDI_DMA_DONTWAIT, NULL, 11072ca5b659SJoost Mulders &dmap->handle); 11082ca5b659SJoost Mulders 11092ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 11102ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 11112ca5b659SJoost Mulders "ddi_dma_alloc_handle failed in vr_alloc_dmabuf"); 11122ca5b659SJoost Mulders return (VR_FAILURE); 11132ca5b659SJoost Mulders } 11142ca5b659SJoost Mulders 11152ca5b659SJoost Mulders /* 11162ca5b659SJoost Mulders * Allocate the buffer 11172ca5b659SJoost Mulders * The allocated buffer is aligned on 2K boundary. This ensures that 11182ca5b659SJoost Mulders * a 1500 byte frame never cross a page boundary and thus that the DMA 11192ca5b659SJoost Mulders * mapping can be established in 1 fragment. 11202ca5b659SJoost Mulders */ 11212ca5b659SJoost Mulders rc = ddi_dma_mem_alloc(dmap->handle, 11222ca5b659SJoost Mulders VR_DMABUFSZ, 11232ca5b659SJoost Mulders &vr_data_dma_accattr, 11242ca5b659SJoost Mulders DDI_DMA_RDWR | DDI_DMA_STREAMING, 11252ca5b659SJoost Mulders DDI_DMA_DONTWAIT, NULL, 11262ca5b659SJoost Mulders &dmap->buf, 11272ca5b659SJoost Mulders &dmap->bufsz, 11282ca5b659SJoost Mulders &dmap->acchdl); 11292ca5b659SJoost Mulders 11302ca5b659SJoost Mulders if (rc != DDI_SUCCESS) { 11312ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 11322ca5b659SJoost Mulders "ddi_dma_mem_alloc failed in vr_alloc_dmabuf"); 11332ca5b659SJoost Mulders ddi_dma_free_handle(&dmap->handle); 11342ca5b659SJoost Mulders return (VR_FAILURE); 11352ca5b659SJoost Mulders } 11362ca5b659SJoost Mulders 11372ca5b659SJoost Mulders /* 11382ca5b659SJoost Mulders * Map the memory 11392ca5b659SJoost Mulders */ 11402ca5b659SJoost Mulders rc = ddi_dma_addr_bind_handle(dmap->handle, 11412ca5b659SJoost Mulders NULL, 11422ca5b659SJoost Mulders (caddr_t)dmap->buf, 11432ca5b659SJoost Mulders dmap->bufsz, 11442ca5b659SJoost Mulders dmaflags, 11452ca5b659SJoost Mulders DDI_DMA_DONTWAIT, 11462ca5b659SJoost Mulders NULL, 11472ca5b659SJoost Mulders &dma_cookie, 11482ca5b659SJoost Mulders &cookiecnt); 11492ca5b659SJoost Mulders 11502ca5b659SJoost Mulders /* 11512ca5b659SJoost Mulders * The cookiecount should never > 1 because we requested 2K alignment 11522ca5b659SJoost Mulders */ 11532ca5b659SJoost Mulders if (rc != DDI_DMA_MAPPED || cookiecnt > 1) { 11542ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 11552ca5b659SJoost Mulders "dma_addr_bind_handle failed in vr_alloc_dmabuf: " 11562ca5b659SJoost Mulders "rc = %d, cookiecnt = %d", rc, cookiecnt); 11572ca5b659SJoost Mulders ddi_dma_mem_free(&dmap->acchdl); 11582ca5b659SJoost Mulders ddi_dma_free_handle(&dmap->handle); 11592ca5b659SJoost Mulders return (VR_FAILURE); 11602ca5b659SJoost Mulders } 11612ca5b659SJoost Mulders dmap->paddr = dma_cookie.dmac_address; 11622ca5b659SJoost Mulders return (VR_SUCCESS); 11632ca5b659SJoost Mulders } 11642ca5b659SJoost Mulders 11652ca5b659SJoost Mulders /* 11662ca5b659SJoost Mulders * Destroy a DMA buffer. 11672ca5b659SJoost Mulders */ 11682ca5b659SJoost Mulders static void 11692ca5b659SJoost Mulders vr_free_dmabuf(vr_data_dma_t *dmap) 11702ca5b659SJoost Mulders { 11712ca5b659SJoost Mulders (void) ddi_dma_unbind_handle(dmap->handle); 11722ca5b659SJoost Mulders ddi_dma_mem_free(&dmap->acchdl); 11732ca5b659SJoost Mulders ddi_dma_free_handle(&dmap->handle); 11742ca5b659SJoost Mulders } 11752ca5b659SJoost Mulders 11762ca5b659SJoost Mulders /* 11772ca5b659SJoost Mulders * Interrupt service routine 11782ca5b659SJoost Mulders * When our vector is shared with another device, av_dispatch_autovect calls 11792ca5b659SJoost Mulders * all service routines for the vector until *none* of them return claimed 11802ca5b659SJoost Mulders * That means that, when sharing vectors, this routine is called at least 11812ca5b659SJoost Mulders * twice for each interrupt. 11822ca5b659SJoost Mulders */ 11832ca5b659SJoost Mulders uint_t 11842ca5b659SJoost Mulders vr_intr(caddr_t arg1, caddr_t arg2) 11852ca5b659SJoost Mulders { 11862ca5b659SJoost Mulders vr_t *vrp; 11872ca5b659SJoost Mulders uint16_t status; 11882ca5b659SJoost Mulders mblk_t *lp = NULL; 11892ca5b659SJoost Mulders uint32_t tx_resched; 11902ca5b659SJoost Mulders uint32_t link_change; 11912ca5b659SJoost Mulders 11922ca5b659SJoost Mulders tx_resched = 0; 11932ca5b659SJoost Mulders link_change = 0; 11942ca5b659SJoost Mulders vrp = (void *)arg1; 11952ca5b659SJoost Mulders _NOTE(ARGUNUSED(arg2)) 11962ca5b659SJoost Mulders 1197*5815e35bSjoostmnl@gmail.com mutex_enter(&vrp->intrlock); 1198*5815e35bSjoostmnl@gmail.com /* 1199*5815e35bSjoostmnl@gmail.com * If the driver is not in running state it is not our interrupt. 1200*5815e35bSjoostmnl@gmail.com * Shared interrupts can end up here without us being started. 1201*5815e35bSjoostmnl@gmail.com */ 1202*5815e35bSjoostmnl@gmail.com if (vrp->chip.state != CHIPSTATE_RUNNING) { 1203*5815e35bSjoostmnl@gmail.com mutex_exit(&vrp->intrlock); 1204*5815e35bSjoostmnl@gmail.com return (DDI_INTR_UNCLAIMED); 1205*5815e35bSjoostmnl@gmail.com } 1206*5815e35bSjoostmnl@gmail.com 12072ca5b659SJoost Mulders /* 12082ca5b659SJoost Mulders * Read the status register to see if the interrupt is from our device 12092ca5b659SJoost Mulders * This read also ensures that posted writes are brought to main memory. 12102ca5b659SJoost Mulders */ 12112ca5b659SJoost Mulders status = VR_GET16(vrp->acc_reg, VR_ISR0) & VR_ICR0_CFG; 12122ca5b659SJoost Mulders if (status == 0) { 12132ca5b659SJoost Mulders /* 12142ca5b659SJoost Mulders * Status contains no configured interrupts 12152ca5b659SJoost Mulders * The interrupt was not generated by our device. 12162ca5b659SJoost Mulders */ 12172ca5b659SJoost Mulders vrp->stats.intr_unclaimed++; 12182ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 12192ca5b659SJoost Mulders return (DDI_INTR_UNCLAIMED); 12202ca5b659SJoost Mulders } 12212ca5b659SJoost Mulders vrp->stats.intr_claimed++; 12222ca5b659SJoost Mulders 12232ca5b659SJoost Mulders /* 12242ca5b659SJoost Mulders * Acknowledge the event(s) that caused interruption. 12252ca5b659SJoost Mulders */ 12262ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_ISR0, status); 12272ca5b659SJoost Mulders 12282ca5b659SJoost Mulders /* 12292ca5b659SJoost Mulders * Receive completion. 12302ca5b659SJoost Mulders */ 12312ca5b659SJoost Mulders if ((status & (VR_ISR0_RX_DONE | VR_ISR_RX_ERR_BITS)) != 0) { 12322ca5b659SJoost Mulders /* 12332ca5b659SJoost Mulders * Received some packets. 12342ca5b659SJoost Mulders */ 12352ca5b659SJoost Mulders lp = vr_receive(vrp); 12362ca5b659SJoost Mulders 12372ca5b659SJoost Mulders /* 12382ca5b659SJoost Mulders * DMA stops after a conflict in the FIFO. 12392ca5b659SJoost Mulders */ 12402ca5b659SJoost Mulders if ((status & VR_ISR_RX_ERR_BITS) != 0) 12412ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO); 12422ca5b659SJoost Mulders status &= ~(VR_ISR0_RX_DONE | VR_ISR_RX_ERR_BITS); 12432ca5b659SJoost Mulders } 12442ca5b659SJoost Mulders 12452ca5b659SJoost Mulders /* 12462ca5b659SJoost Mulders * Transmit completion. 12472ca5b659SJoost Mulders */ 12482ca5b659SJoost Mulders if ((status & (VR_ISR0_TX_DONE | VR_ISR_TX_ERR_BITS)) != 0) { 12492ca5b659SJoost Mulders /* 12502ca5b659SJoost Mulders * Card done with transmitting some packets 12512ca5b659SJoost Mulders * TX_DONE is generated 3 times per ring but it appears 12522ca5b659SJoost Mulders * more often because it is also set when an RX_DONE 12532ca5b659SJoost Mulders * interrupt is generated. 12542ca5b659SJoost Mulders */ 12552ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 12562ca5b659SJoost Mulders vr_tx_reclaim(vrp); 12572ca5b659SJoost Mulders tx_resched = vrp->tx.resched; 12582ca5b659SJoost Mulders vrp->tx.resched = 0; 12592ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 12602ca5b659SJoost Mulders status &= ~(VR_ISR0_TX_DONE | VR_ISR_TX_ERR_BITS); 12612ca5b659SJoost Mulders } 12622ca5b659SJoost Mulders 12632ca5b659SJoost Mulders /* 12642ca5b659SJoost Mulders * Link status change. 12652ca5b659SJoost Mulders */ 12662ca5b659SJoost Mulders if ((status & VR_ICR0_LINKSTATUS) != 0) { 12672ca5b659SJoost Mulders /* 12682ca5b659SJoost Mulders * Get new link state and inform the mac layer. 12692ca5b659SJoost Mulders */ 12702ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 12712ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 12722ca5b659SJoost Mulders vr_link_state(vrp); 12732ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 12742ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 12752ca5b659SJoost Mulders status &= ~VR_ICR0_LINKSTATUS; 12762ca5b659SJoost Mulders vrp->stats.linkchanges++; 12772ca5b659SJoost Mulders link_change = 1; 12782ca5b659SJoost Mulders } 12792ca5b659SJoost Mulders 12802ca5b659SJoost Mulders /* 12812ca5b659SJoost Mulders * Bus error. 12822ca5b659SJoost Mulders */ 12832ca5b659SJoost Mulders if ((status & VR_ISR0_BUSERR) != 0) { 12842ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "bus error occured"); 12852ca5b659SJoost Mulders vrp->reset = 1; 12862ca5b659SJoost Mulders status &= ~VR_ISR0_BUSERR; 12872ca5b659SJoost Mulders } 12882ca5b659SJoost Mulders 12892ca5b659SJoost Mulders /* 12902ca5b659SJoost Mulders * We must have handled all things here. 12912ca5b659SJoost Mulders */ 12922ca5b659SJoost Mulders ASSERT(status == 0); 12932ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 12942ca5b659SJoost Mulders 12952ca5b659SJoost Mulders /* 12962ca5b659SJoost Mulders * Reset the device if requested 12972ca5b659SJoost Mulders * The request can come from the periodic tx check or from the interrupt 12982ca5b659SJoost Mulders * status. 12992ca5b659SJoost Mulders */ 13002ca5b659SJoost Mulders if (vrp->reset != 0) { 13012ca5b659SJoost Mulders vr_error(vrp); 13022ca5b659SJoost Mulders vrp->reset = 0; 13032ca5b659SJoost Mulders } 13042ca5b659SJoost Mulders 13052ca5b659SJoost Mulders /* 13062ca5b659SJoost Mulders * Pass up the list with received packets. 13072ca5b659SJoost Mulders */ 13082ca5b659SJoost Mulders if (lp != NULL) 13092ca5b659SJoost Mulders mac_rx(vrp->machdl, 0, lp); 13102ca5b659SJoost Mulders 13112ca5b659SJoost Mulders /* 13122ca5b659SJoost Mulders * Inform the upper layer on the linkstatus if there was a change. 13132ca5b659SJoost Mulders */ 13142ca5b659SJoost Mulders if (link_change != 0) 13152ca5b659SJoost Mulders mac_link_update(vrp->machdl, 13162ca5b659SJoost Mulders (link_state_t)vrp->chip.link.state); 13172ca5b659SJoost Mulders /* 13182ca5b659SJoost Mulders * Restart transmissions if we were waiting for tx descriptors. 13192ca5b659SJoost Mulders */ 13202ca5b659SJoost Mulders if (tx_resched == 1) 13212ca5b659SJoost Mulders mac_tx_update(vrp->machdl); 13222ca5b659SJoost Mulders 13232ca5b659SJoost Mulders /* 13242ca5b659SJoost Mulders * Read something from the card to ensure that all of our configuration 13252ca5b659SJoost Mulders * writes are delivered to the device before the interrupt is ended. 13262ca5b659SJoost Mulders */ 13272ca5b659SJoost Mulders (void) VR_GET8(vrp->acc_reg, VR_ETHERADDR); 13282ca5b659SJoost Mulders return (DDI_INTR_CLAIMED); 13292ca5b659SJoost Mulders } 13302ca5b659SJoost Mulders 13312ca5b659SJoost Mulders /* 13322ca5b659SJoost Mulders * Respond to an unforseen situation by resetting the card and our bookkeeping. 13332ca5b659SJoost Mulders */ 13342ca5b659SJoost Mulders static void 13352ca5b659SJoost Mulders vr_error(vr_t *vrp) 13362ca5b659SJoost Mulders { 13372ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "resetting MAC."); 13382ca5b659SJoost Mulders mutex_enter(&vrp->intrlock); 13392ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 13402ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 13412ca5b659SJoost Mulders (void) vr_stop(vrp); 13422ca5b659SJoost Mulders vr_reset(vrp); 13432ca5b659SJoost Mulders (void) vr_start(vrp); 13442ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 13452ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 13462ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 13472ca5b659SJoost Mulders vrp->stats.resets++; 13482ca5b659SJoost Mulders } 13492ca5b659SJoost Mulders 13502ca5b659SJoost Mulders /* 13512ca5b659SJoost Mulders * Collect received packets in a list. 13522ca5b659SJoost Mulders */ 13532ca5b659SJoost Mulders static mblk_t * 13542ca5b659SJoost Mulders vr_receive(vr_t *vrp) 13552ca5b659SJoost Mulders { 13562ca5b659SJoost Mulders mblk_t *lp, *mp, *np; 13572ca5b659SJoost Mulders vr_desc_t *rxp; 13582ca5b659SJoost Mulders vr_data_dma_t *dmap; 13592ca5b659SJoost Mulders uint32_t pklen; 13602ca5b659SJoost Mulders uint32_t rxstat0; 13612ca5b659SJoost Mulders uint32_t n; 13622ca5b659SJoost Mulders 13632ca5b659SJoost Mulders lp = NULL; 13642ca5b659SJoost Mulders n = 0; 13652ca5b659SJoost Mulders for (rxp = vrp->rx.rp; ; rxp = rxp->next, n++) { 13662ca5b659SJoost Mulders /* 13672ca5b659SJoost Mulders * Sync the descriptor before looking at it. 13682ca5b659SJoost Mulders */ 13692ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->rxring.handle, rxp->offset, 13702ca5b659SJoost Mulders sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORKERNEL); 13712ca5b659SJoost Mulders 13722ca5b659SJoost Mulders /* 13732ca5b659SJoost Mulders * Get the status from the descriptor. 13742ca5b659SJoost Mulders */ 13752ca5b659SJoost Mulders rxstat0 = ddi_get32(vrp->rxring.acchdl, &rxp->cdesc->stat0); 13762ca5b659SJoost Mulders 13772ca5b659SJoost Mulders /* 13782ca5b659SJoost Mulders * We're done if the descriptor is owned by the card. 13792ca5b659SJoost Mulders */ 13802ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_OWN) != 0) 13812ca5b659SJoost Mulders break; 13822ca5b659SJoost Mulders else if ((rxstat0 & VR_RDES0_RXOK) != 0) { 13832ca5b659SJoost Mulders /* 13842ca5b659SJoost Mulders * Received a good packet 13852ca5b659SJoost Mulders */ 13862ca5b659SJoost Mulders dmap = &rxp->dmabuf; 13872ca5b659SJoost Mulders pklen = (rxstat0 >> 16) - ETHERFCSL; 13882ca5b659SJoost Mulders 13892ca5b659SJoost Mulders /* 13902ca5b659SJoost Mulders * Sync the data. 13912ca5b659SJoost Mulders */ 13922ca5b659SJoost Mulders (void) ddi_dma_sync(dmap->handle, 0, 13932ca5b659SJoost Mulders pklen, DDI_DMA_SYNC_FORKERNEL); 13942ca5b659SJoost Mulders 13952ca5b659SJoost Mulders /* 13962ca5b659SJoost Mulders * Send a new copied message upstream. 13972ca5b659SJoost Mulders */ 13982ca5b659SJoost Mulders np = allocb(pklen, 0); 13992ca5b659SJoost Mulders if (np != NULL) { 14002ca5b659SJoost Mulders bcopy(dmap->buf, np->b_rptr, pklen); 14012ca5b659SJoost Mulders np->b_wptr = np->b_rptr + pklen; 14022ca5b659SJoost Mulders 14032ca5b659SJoost Mulders vrp->stats.mac_stat_ipackets++; 14042ca5b659SJoost Mulders vrp->stats.mac_stat_rbytes += pklen; 14052ca5b659SJoost Mulders 14062ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_BAR) != 0) 14072ca5b659SJoost Mulders vrp->stats.mac_stat_brdcstrcv++; 14082ca5b659SJoost Mulders else if ((rxstat0 & VR_RDES0_MAR) != 0) 14092ca5b659SJoost Mulders vrp->stats.mac_stat_multircv++; 14102ca5b659SJoost Mulders 14112ca5b659SJoost Mulders /* 14122ca5b659SJoost Mulders * Link this packet in the list. 14132ca5b659SJoost Mulders */ 14142ca5b659SJoost Mulders np->b_next = NULL; 14152ca5b659SJoost Mulders if (lp == NULL) 14162ca5b659SJoost Mulders lp = mp = np; 14172ca5b659SJoost Mulders else { 14182ca5b659SJoost Mulders mp->b_next = np; 14192ca5b659SJoost Mulders mp = np; 14202ca5b659SJoost Mulders } 14212ca5b659SJoost Mulders } else { 14222ca5b659SJoost Mulders vrp->stats.allocbfail++; 14232ca5b659SJoost Mulders vrp->stats.mac_stat_norcvbuf++; 14242ca5b659SJoost Mulders } 14252ca5b659SJoost Mulders 14262ca5b659SJoost Mulders } else { 14272ca5b659SJoost Mulders /* 14282ca5b659SJoost Mulders * Received with errors. 14292ca5b659SJoost Mulders */ 14302ca5b659SJoost Mulders vrp->stats.mac_stat_ierrors++; 14312ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_FAE) != 0) 14322ca5b659SJoost Mulders vrp->stats.ether_stat_align_errors++; 14332ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_CRCERR) != 0) 14342ca5b659SJoost Mulders vrp->stats.ether_stat_fcs_errors++; 14352ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_LONG) != 0) 14362ca5b659SJoost Mulders vrp->stats.ether_stat_toolong_errors++; 14372ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_RUNT) != 0) 14382ca5b659SJoost Mulders vrp->stats.ether_stat_tooshort_errors++; 14392ca5b659SJoost Mulders if ((rxstat0 & VR_RDES0_FOV) != 0) 14402ca5b659SJoost Mulders vrp->stats.mac_stat_overflows++; 14412ca5b659SJoost Mulders } 14422ca5b659SJoost Mulders 14432ca5b659SJoost Mulders /* 14442ca5b659SJoost Mulders * Reset descriptor ownership to the MAC. 14452ca5b659SJoost Mulders */ 14462ca5b659SJoost Mulders ddi_put32(vrp->rxring.acchdl, 14472ca5b659SJoost Mulders &rxp->cdesc->stat0, 14482ca5b659SJoost Mulders VR_RDES0_OWN); 14492ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->rxring.handle, 14502ca5b659SJoost Mulders rxp->offset, 14512ca5b659SJoost Mulders sizeof (vr_chip_desc_t), 14522ca5b659SJoost Mulders DDI_DMA_SYNC_FORDEV); 14532ca5b659SJoost Mulders } 14542ca5b659SJoost Mulders vrp->rx.rp = rxp; 14552ca5b659SJoost Mulders 14562ca5b659SJoost Mulders /* 14572ca5b659SJoost Mulders * If we do flowcontrol and if the card can transmit pause frames, 14582ca5b659SJoost Mulders * increment the "available receive descriptors" register. 14592ca5b659SJoost Mulders */ 14602ca5b659SJoost Mulders if (n > 0 && vrp->chip.link.flowctrl == VR_PAUSE_BIDIRECTIONAL) { 14612ca5b659SJoost Mulders /* 14622ca5b659SJoost Mulders * Whenever the card moves a fragment to host memory it 14632ca5b659SJoost Mulders * decrements the RXBUFCOUNT register. If the value in the 14642ca5b659SJoost Mulders * register reaches a low watermark, the card transmits a pause 14652ca5b659SJoost Mulders * frame. If the value in this register reaches a high 14662ca5b659SJoost Mulders * watermark, the card sends a "cancel pause" frame 14672ca5b659SJoost Mulders * 14682ca5b659SJoost Mulders * Non-zero values written to this byte register are added 14692ca5b659SJoost Mulders * by the chip to the register's contents, so we must write 14702ca5b659SJoost Mulders * the number of descriptors free'd. 14712ca5b659SJoost Mulders */ 14722ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_FCR0_RXBUFCOUNT, MIN(n, 0xFF)); 14732ca5b659SJoost Mulders } 14742ca5b659SJoost Mulders return (lp); 14752ca5b659SJoost Mulders } 14762ca5b659SJoost Mulders 14772ca5b659SJoost Mulders /* 14782ca5b659SJoost Mulders * Enqueue a list of packets for transmission 14792ca5b659SJoost Mulders * Return the packets not transmitted. 14802ca5b659SJoost Mulders */ 14812ca5b659SJoost Mulders mblk_t * 14822ca5b659SJoost Mulders vr_mac_tx_enqueue_list(void *p, mblk_t *mp) 14832ca5b659SJoost Mulders { 14842ca5b659SJoost Mulders vr_t *vrp; 14852ca5b659SJoost Mulders mblk_t *nextp; 14862ca5b659SJoost Mulders 14872ca5b659SJoost Mulders vrp = (vr_t *)p; 14882ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 14892ca5b659SJoost Mulders do { 14902ca5b659SJoost Mulders if (vrp->tx.nfree == 0) { 14912ca5b659SJoost Mulders vrp->stats.ether_stat_defer_xmts++; 14922ca5b659SJoost Mulders vrp->tx.resched = 1; 14932ca5b659SJoost Mulders break; 14942ca5b659SJoost Mulders } 14952ca5b659SJoost Mulders nextp = mp->b_next; 14962ca5b659SJoost Mulders mp->b_next = mp->b_prev = NULL; 14972ca5b659SJoost Mulders vr_tx_enqueue_msg(vrp, mp); 14982ca5b659SJoost Mulders mp = nextp; 14992ca5b659SJoost Mulders vrp->tx.nfree--; 15002ca5b659SJoost Mulders } while (mp != NULL); 15012ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 15022ca5b659SJoost Mulders 15032ca5b659SJoost Mulders /* 15042ca5b659SJoost Mulders * Tell the chip to poll the TX ring. 15052ca5b659SJoost Mulders */ 15062ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO); 15072ca5b659SJoost Mulders return (mp); 15082ca5b659SJoost Mulders } 15092ca5b659SJoost Mulders 15102ca5b659SJoost Mulders /* 15112ca5b659SJoost Mulders * Enqueue a message for transmission. 15122ca5b659SJoost Mulders */ 15132ca5b659SJoost Mulders static void 15142ca5b659SJoost Mulders vr_tx_enqueue_msg(vr_t *vrp, mblk_t *mp) 15152ca5b659SJoost Mulders { 15162ca5b659SJoost Mulders vr_desc_t *wp; 15172ca5b659SJoost Mulders vr_data_dma_t *dmap; 15182ca5b659SJoost Mulders uint32_t pklen; 15192ca5b659SJoost Mulders uint32_t nextp; 15202ca5b659SJoost Mulders int padlen; 15212ca5b659SJoost Mulders 15222ca5b659SJoost Mulders if ((uchar_t)mp->b_rptr[0] == 0xff && 15232ca5b659SJoost Mulders (uchar_t)mp->b_rptr[1] == 0xff && 15242ca5b659SJoost Mulders (uchar_t)mp->b_rptr[2] == 0xff && 15252ca5b659SJoost Mulders (uchar_t)mp->b_rptr[3] == 0xff && 15262ca5b659SJoost Mulders (uchar_t)mp->b_rptr[4] == 0xff && 15272ca5b659SJoost Mulders (uchar_t)mp->b_rptr[5] == 0xff) 15282ca5b659SJoost Mulders vrp->stats.mac_stat_brdcstxmt++; 15292ca5b659SJoost Mulders else if ((uchar_t)mp->b_rptr[0] == 1) 15302ca5b659SJoost Mulders vrp->stats.mac_stat_multixmt++; 15312ca5b659SJoost Mulders 15322ca5b659SJoost Mulders pklen = msgsize(mp); 15332ca5b659SJoost Mulders wp = vrp->tx.wp; 15342ca5b659SJoost Mulders dmap = &wp->dmabuf; 15352ca5b659SJoost Mulders 15362ca5b659SJoost Mulders /* 15372ca5b659SJoost Mulders * Copy the message into the pre-mapped buffer and free mp 15382ca5b659SJoost Mulders */ 15392ca5b659SJoost Mulders mcopymsg(mp, dmap->buf); 15402ca5b659SJoost Mulders 15412ca5b659SJoost Mulders /* 15422ca5b659SJoost Mulders * Clean padlen bytes of short packet. 15432ca5b659SJoost Mulders */ 15442ca5b659SJoost Mulders padlen = ETHERMIN - pklen; 15452ca5b659SJoost Mulders if (padlen > 0) { 15462ca5b659SJoost Mulders bzero(dmap->buf + pklen, padlen); 15472ca5b659SJoost Mulders pklen += padlen; 15482ca5b659SJoost Mulders } 15492ca5b659SJoost Mulders 15502ca5b659SJoost Mulders /* 15512ca5b659SJoost Mulders * Most of the statistics are updated on reclaim, after the actual 15522ca5b659SJoost Mulders * transmit. obytes is maintained here because the length is cleared 15532ca5b659SJoost Mulders * after transmission 15542ca5b659SJoost Mulders */ 15552ca5b659SJoost Mulders vrp->stats.mac_stat_obytes += pklen; 15562ca5b659SJoost Mulders 15572ca5b659SJoost Mulders /* 15582ca5b659SJoost Mulders * Sync the data so the device sees the new content too. 15592ca5b659SJoost Mulders */ 15602ca5b659SJoost Mulders (void) ddi_dma_sync(dmap->handle, 0, pklen, DDI_DMA_SYNC_FORDEV); 15612ca5b659SJoost Mulders 15622ca5b659SJoost Mulders /* 15632ca5b659SJoost Mulders * If we have reached the TX interrupt distance, enable a TX interrupt 15642ca5b659SJoost Mulders * for this packet. The Interrupt Control (IC) bit in the transmit 15652ca5b659SJoost Mulders * descriptor doesn't have any effect on the interrupt generation 15662ca5b659SJoost Mulders * despite the vague statements in the datasheet. Thus, we use the 15672ca5b659SJoost Mulders * more obscure interrupt suppress bit which is probably part of the 15682ca5b659SJoost Mulders * MAC's bookkeeping for TX interrupts and fragmented packets. 15692ca5b659SJoost Mulders */ 15702ca5b659SJoost Mulders vrp->tx.intr_distance++; 15712ca5b659SJoost Mulders nextp = ddi_get32(vrp->txring.acchdl, &wp->cdesc->next); 15722ca5b659SJoost Mulders if (vrp->tx.intr_distance >= VR_TX_MAX_INTR_DISTANCE) { 15732ca5b659SJoost Mulders /* 15742ca5b659SJoost Mulders * Don't suppress the interrupt for this packet. 15752ca5b659SJoost Mulders */ 15762ca5b659SJoost Mulders vrp->tx.intr_distance = 0; 15772ca5b659SJoost Mulders nextp &= (~VR_TDES3_SUPPRESS_INTR); 15782ca5b659SJoost Mulders } else { 15792ca5b659SJoost Mulders /* 15802ca5b659SJoost Mulders * Suppress the interrupt for this packet. 15812ca5b659SJoost Mulders */ 15822ca5b659SJoost Mulders nextp |= VR_TDES3_SUPPRESS_INTR; 15832ca5b659SJoost Mulders } 15842ca5b659SJoost Mulders 15852ca5b659SJoost Mulders /* 15862ca5b659SJoost Mulders * Write and sync the chip's descriptor 15872ca5b659SJoost Mulders */ 15882ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat1, 15892ca5b659SJoost Mulders pklen | (VR_TDES1_STP | VR_TDES1_EDP | VR_TDES1_CHN)); 15902ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->next, nextp); 15912ca5b659SJoost Mulders ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat0, VR_TDES0_OWN); 15922ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->txring.handle, wp->offset, 15932ca5b659SJoost Mulders sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORDEV); 15942ca5b659SJoost Mulders 15952ca5b659SJoost Mulders /* 15962ca5b659SJoost Mulders * The ticks counter is cleared by reclaim when it reclaimed some 15972ca5b659SJoost Mulders * descriptors and incremented by the periodic TX stall check. 15982ca5b659SJoost Mulders */ 15992ca5b659SJoost Mulders vrp->tx.stallticks = 1; 16002ca5b659SJoost Mulders vrp->tx.wp = wp->next; 16012ca5b659SJoost Mulders } 16022ca5b659SJoost Mulders 16032ca5b659SJoost Mulders /* 16042ca5b659SJoost Mulders * Free transmitted descriptors. 16052ca5b659SJoost Mulders */ 16062ca5b659SJoost Mulders static void 16072ca5b659SJoost Mulders vr_tx_reclaim(vr_t *vrp) 16082ca5b659SJoost Mulders { 16092ca5b659SJoost Mulders vr_desc_t *cp; 16102ca5b659SJoost Mulders uint32_t stat0, stat1, freed, dirty; 16112ca5b659SJoost Mulders 16122ca5b659SJoost Mulders ASSERT(mutex_owned(&vrp->tx.lock)); 16132ca5b659SJoost Mulders 16142ca5b659SJoost Mulders freed = 0; 16152ca5b659SJoost Mulders dirty = vrp->tx.ndesc - vrp->tx.nfree; 16162ca5b659SJoost Mulders for (cp = vrp->tx.cp; dirty > 0; cp = cp->next) { 16172ca5b659SJoost Mulders /* 16182ca5b659SJoost Mulders * Sync & get descriptor status. 16192ca5b659SJoost Mulders */ 16202ca5b659SJoost Mulders (void) ddi_dma_sync(vrp->txring.handle, cp->offset, 16212ca5b659SJoost Mulders sizeof (vr_chip_desc_t), 16222ca5b659SJoost Mulders DDI_DMA_SYNC_FORKERNEL); 16232ca5b659SJoost Mulders stat0 = ddi_get32(vrp->txring.acchdl, &cp->cdesc->stat0); 16242ca5b659SJoost Mulders 16252ca5b659SJoost Mulders if ((stat0 & VR_TDES0_OWN) != 0) 16262ca5b659SJoost Mulders break; 16272ca5b659SJoost Mulders 16282ca5b659SJoost Mulders /* 16292ca5b659SJoost Mulders * Do stats for the first descriptor in a chain. 16302ca5b659SJoost Mulders */ 16312ca5b659SJoost Mulders stat1 = ddi_get32(vrp->txring.acchdl, &cp->cdesc->stat1); 16322ca5b659SJoost Mulders if ((stat1 & VR_TDES1_STP) != 0) { 16332ca5b659SJoost Mulders if ((stat0 & VR_TDES0_TERR) != 0) { 16342ca5b659SJoost Mulders vrp->stats.ether_stat_macxmt_errors++; 16352ca5b659SJoost Mulders if ((stat0 & VR_TDES0_UDF) != 0) 16362ca5b659SJoost Mulders vrp->stats.mac_stat_underflows++; 16372ca5b659SJoost Mulders if ((stat0 & VR_TDES0_ABT) != 0) 16382ca5b659SJoost Mulders vrp-> stats.ether_stat_ex_collisions++; 16392ca5b659SJoost Mulders /* 16402ca5b659SJoost Mulders * Abort and FIFO underflow stop the MAC. 16412ca5b659SJoost Mulders * Packet queueing must be disabled with HD 16422ca5b659SJoost Mulders * links because otherwise the MAC is also lost 16432ca5b659SJoost Mulders * after a few of these events. 16442ca5b659SJoost Mulders */ 16452ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, 16462ca5b659SJoost Mulders VR_CTRL0_DMA_GO); 16472ca5b659SJoost Mulders } else 16482ca5b659SJoost Mulders vrp->stats.mac_stat_opackets++; 16492ca5b659SJoost Mulders 16502ca5b659SJoost Mulders if ((stat0 & VR_TDES0_COL) != 0) { 16512ca5b659SJoost Mulders if ((stat0 & VR_TDES0_NCR) == 1) { 16522ca5b659SJoost Mulders vrp->stats. 16532ca5b659SJoost Mulders ether_stat_first_collisions++; 16542ca5b659SJoost Mulders } else { 16552ca5b659SJoost Mulders vrp->stats. 16562ca5b659SJoost Mulders ether_stat_multi_collisions++; 16572ca5b659SJoost Mulders } 16582ca5b659SJoost Mulders vrp->stats.mac_stat_collisions += 16592ca5b659SJoost Mulders (stat0 & VR_TDES0_NCR); 16602ca5b659SJoost Mulders } 16612ca5b659SJoost Mulders 16622ca5b659SJoost Mulders if ((stat0 & VR_TDES0_CRS) != 0) 16632ca5b659SJoost Mulders vrp->stats.ether_stat_carrier_errors++; 16642ca5b659SJoost Mulders 16652ca5b659SJoost Mulders if ((stat0 & VR_TDES0_OWC) != 0) 16662ca5b659SJoost Mulders vrp->stats.ether_stat_tx_late_collisions++; 16672ca5b659SJoost Mulders } 16682ca5b659SJoost Mulders freed += 1; 16692ca5b659SJoost Mulders dirty -= 1; 16702ca5b659SJoost Mulders } 16712ca5b659SJoost Mulders vrp->tx.cp = cp; 16722ca5b659SJoost Mulders 16732ca5b659SJoost Mulders if (freed > 0) { 16742ca5b659SJoost Mulders vrp->tx.nfree += freed; 16752ca5b659SJoost Mulders vrp->tx.stallticks = 0; 16762ca5b659SJoost Mulders vrp->stats.txreclaims += 1; 16772ca5b659SJoost Mulders } else 16782ca5b659SJoost Mulders vrp->stats.txreclaim0 += 1; 16792ca5b659SJoost Mulders } 16802ca5b659SJoost Mulders 16812ca5b659SJoost Mulders /* 16822ca5b659SJoost Mulders * Check TX health every 2 seconds. 16832ca5b659SJoost Mulders */ 16842ca5b659SJoost Mulders static void 16852ca5b659SJoost Mulders vr_periodic(void *p) 16862ca5b659SJoost Mulders { 16872ca5b659SJoost Mulders vr_t *vrp; 16882ca5b659SJoost Mulders 16892ca5b659SJoost Mulders vrp = (vr_t *)p; 16902ca5b659SJoost Mulders if (vrp->chip.state == CHIPSTATE_RUNNING && 16912ca5b659SJoost Mulders vrp->chip.link.state == VR_LINK_STATE_UP && vrp->reset == 0) { 16922ca5b659SJoost Mulders if (mutex_tryenter(&vrp->intrlock) != 0) { 16932ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 16942ca5b659SJoost Mulders if (vrp->tx.resched == 1) { 16952ca5b659SJoost Mulders if (vrp->tx.stallticks >= VR_MAXTXCHECKS) { 16962ca5b659SJoost Mulders /* 16972ca5b659SJoost Mulders * No succesful reclaim in the last n 16982ca5b659SJoost Mulders * intervals. Reset the MAC. 16992ca5b659SJoost Mulders */ 17002ca5b659SJoost Mulders vrp->reset = 1; 17012ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 17022ca5b659SJoost Mulders "TX stalled, resetting MAC"); 17032ca5b659SJoost Mulders vrp->stats.txstalls++; 17042ca5b659SJoost Mulders } else { 17052ca5b659SJoost Mulders /* 17062ca5b659SJoost Mulders * Increase until we find that we've 17072ca5b659SJoost Mulders * waited long enough. 17082ca5b659SJoost Mulders */ 17092ca5b659SJoost Mulders vrp->tx.stallticks += 1; 17102ca5b659SJoost Mulders } 17112ca5b659SJoost Mulders } 17122ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 17132ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 17142ca5b659SJoost Mulders vrp->stats.txchecks++; 17152ca5b659SJoost Mulders } 17162ca5b659SJoost Mulders } 17172ca5b659SJoost Mulders vrp->stats.cyclics++; 17182ca5b659SJoost Mulders } 17192ca5b659SJoost Mulders 17202ca5b659SJoost Mulders /* 17212ca5b659SJoost Mulders * Bring the device to our desired initial state. 17222ca5b659SJoost Mulders */ 17232ca5b659SJoost Mulders static void 17242ca5b659SJoost Mulders vr_reset(vr_t *vrp) 17252ca5b659SJoost Mulders { 17262ca5b659SJoost Mulders uint32_t time; 17272ca5b659SJoost Mulders 17282ca5b659SJoost Mulders /* 17292ca5b659SJoost Mulders * Reset the MAC 17302ca5b659SJoost Mulders * If we don't wait long enough for the forced reset to complete, 17312ca5b659SJoost Mulders * MAC looses sync with PHY. Result link up, no link change interrupt 17322ca5b659SJoost Mulders * and no data transfer. 17332ca5b659SJoost Mulders */ 17342ca5b659SJoost Mulders time = 0; 17352ca5b659SJoost Mulders VR_PUT8(vrp->acc_io, VR_CTRL1, VR_CTRL1_RESET); 17362ca5b659SJoost Mulders do { 17372ca5b659SJoost Mulders drv_usecwait(100); 17382ca5b659SJoost Mulders time += 100; 17392ca5b659SJoost Mulders if (time >= 100000) { 17402ca5b659SJoost Mulders VR_PUT8(vrp->acc_io, VR_MISC1, VR_MISC1_RESET); 17412ca5b659SJoost Mulders delay(drv_usectohz(200000)); 17422ca5b659SJoost Mulders } 17432ca5b659SJoost Mulders } while ((VR_GET8(vrp->acc_io, VR_CTRL1) & VR_CTRL1_RESET) != 0); 17442ca5b659SJoost Mulders delay(drv_usectohz(10000)); 17452ca5b659SJoost Mulders 17462ca5b659SJoost Mulders /* 17472ca5b659SJoost Mulders * Load the PROM contents into the MAC again. 17482ca5b659SJoost Mulders */ 17492ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_io, VR_PROMCTL, VR_PROMCTL_RELOAD); 17502ca5b659SJoost Mulders delay(drv_usectohz(100000)); 17512ca5b659SJoost Mulders 17522ca5b659SJoost Mulders /* 17532ca5b659SJoost Mulders * Tell the MAC via IO space that we like to use memory space for 17542ca5b659SJoost Mulders * accessing registers. 17552ca5b659SJoost Mulders */ 17562ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_io, VR_CFGD, VR_CFGD_MMIOEN); 17572ca5b659SJoost Mulders } 17582ca5b659SJoost Mulders 17592ca5b659SJoost Mulders /* 17602ca5b659SJoost Mulders * Prepare and enable the card (MAC + PHY + PCI). 17612ca5b659SJoost Mulders */ 17622ca5b659SJoost Mulders static int 17632ca5b659SJoost Mulders vr_start(vr_t *vrp) 17642ca5b659SJoost Mulders { 17652ca5b659SJoost Mulders uint8_t pci_latency, pci_mode; 17662ca5b659SJoost Mulders 17672ca5b659SJoost Mulders ASSERT(mutex_owned(&vrp->oplock)); 17682ca5b659SJoost Mulders 17692ca5b659SJoost Mulders /* 17702ca5b659SJoost Mulders * Allocate DMA buffers for RX. 17712ca5b659SJoost Mulders */ 17722ca5b659SJoost Mulders if (vr_rxring_init(vrp) != VR_SUCCESS) { 17732ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "vr_rxring_init() failed"); 17742ca5b659SJoost Mulders return (ENOMEM); 17752ca5b659SJoost Mulders } 17762ca5b659SJoost Mulders 17772ca5b659SJoost Mulders /* 17782ca5b659SJoost Mulders * Allocate DMA buffers for TX. 17792ca5b659SJoost Mulders */ 17802ca5b659SJoost Mulders if (vr_txring_init(vrp) != VR_SUCCESS) { 17812ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "vr_txring_init() failed"); 17822ca5b659SJoost Mulders vr_rxring_fini(vrp); 17832ca5b659SJoost Mulders return (ENOMEM); 17842ca5b659SJoost Mulders } 17852ca5b659SJoost Mulders 17862ca5b659SJoost Mulders /* 17872ca5b659SJoost Mulders * Changes of the chip specific registers as done in VIA's fet driver 17882ca5b659SJoost Mulders * These bits are not in the datasheet and controlled by vr_chip_info. 17892ca5b659SJoost Mulders */ 17902ca5b659SJoost Mulders pci_mode = VR_GET8(vrp->acc_reg, VR_MODE2); 17912ca5b659SJoost Mulders if ((vrp->chip.info.bugs & VR_BUG_NEEDMODE10T) != 0) 17922ca5b659SJoost Mulders pci_mode |= VR_MODE2_MODE10T; 17932ca5b659SJoost Mulders 17942ca5b659SJoost Mulders if ((vrp->chip.info.bugs & VR_BUG_NEEDMODE2PCEROPT) != 0) 17952ca5b659SJoost Mulders pci_mode |= VR_MODE2_PCEROPT; 17962ca5b659SJoost Mulders 17972ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_MRDLNMULTIPLE) != 0) 17982ca5b659SJoost Mulders pci_mode |= VR_MODE2_MRDPL; 17992ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MODE2, pci_mode); 18002ca5b659SJoost Mulders 18012ca5b659SJoost Mulders pci_mode = VR_GET8(vrp->acc_reg, VR_MODE3); 18022ca5b659SJoost Mulders if ((vrp->chip.info.bugs & VR_BUG_NEEDMIION) != 0) 18032ca5b659SJoost Mulders pci_mode |= VR_MODE3_MIION; 18042ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MODE3, pci_mode); 18052ca5b659SJoost Mulders 18062ca5b659SJoost Mulders /* 18072ca5b659SJoost Mulders * RX: Accept broadcast packets. 18082ca5b659SJoost Mulders */ 18092ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTBROAD); 18102ca5b659SJoost Mulders 18112ca5b659SJoost Mulders /* 18122ca5b659SJoost Mulders * RX: Start DMA when there are 256 bytes in the FIFO. 18132ca5b659SJoost Mulders */ 18142ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_FIFO_THRESHOLD_BITS, 18152ca5b659SJoost Mulders VR_RXCFG_FIFO_THRESHOLD_256); 18162ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_BCR0, VR_BCR0_RX_FIFO_THRESHOLD_BITS, 18172ca5b659SJoost Mulders VR_BCR0_RX_FIFO_THRESHOLD_256); 18182ca5b659SJoost Mulders 18192ca5b659SJoost Mulders /* 18202ca5b659SJoost Mulders * TX: Start transmit when there are 256 bytes in the FIFO. 18212ca5b659SJoost Mulders */ 18222ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_TXCFG, VR_TXCFG_FIFO_THRESHOLD_BITS, 18232ca5b659SJoost Mulders VR_TXCFG_FIFO_THRESHOLD_256); 18242ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_BCR1, VR_BCR1_TX_FIFO_THRESHOLD_BITS, 18252ca5b659SJoost Mulders VR_BCR1_TX_FIFO_THRESHOLD_256); 18262ca5b659SJoost Mulders 18272ca5b659SJoost Mulders /* 18282ca5b659SJoost Mulders * Burst transfers up to 256 bytes. 18292ca5b659SJoost Mulders */ 18302ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_BCR0, VR_BCR0_DMABITS, VR_BCR0_DMA256); 18312ca5b659SJoost Mulders 18322ca5b659SJoost Mulders /* 18332ca5b659SJoost Mulders * Disable TX autopolling as it is bad for RX performance 18342ca5b659SJoost Mulders * I assume this is because the RX process finds the bus often occupied 18352ca5b659SJoost Mulders * by the polling process. 18362ca5b659SJoost Mulders */ 18372ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_NOAUTOPOLL); 18382ca5b659SJoost Mulders 18392ca5b659SJoost Mulders /* 18402ca5b659SJoost Mulders * Honor the PCI latency timer if it is reasonable. 18412ca5b659SJoost Mulders */ 18422ca5b659SJoost Mulders pci_latency = VR_GET8(vrp->acc_cfg, PCI_CONF_LATENCY_TIMER); 18432ca5b659SJoost Mulders if (pci_latency != 0 && pci_latency != 0xFF) 18442ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_LATENCYTIMER); 18452ca5b659SJoost Mulders else 18462ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_LATENCYTIMER); 18472ca5b659SJoost Mulders 18482ca5b659SJoost Mulders /* 18492ca5b659SJoost Mulders * Ensure that VLAN filtering is off, because this strips the tag. 18502ca5b659SJoost Mulders */ 18512ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_VLANTAGGING) != 0) { 18522ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_BCR1, VR_BCR1_VLANFILTER); 18532ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_TXCFG, VR_TXCFG_8021PQ_EN); 18542ca5b659SJoost Mulders } 18552ca5b659SJoost Mulders 18562ca5b659SJoost Mulders /* 18572ca5b659SJoost Mulders * Clear the CAM filter. 18582ca5b659SJoost Mulders */ 18592ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_CAMSUPPORT) != 0) { 18602ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_ENABLE); 18612ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_CAM_MASK, 0); 18622ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE); 18632ca5b659SJoost Mulders 18642ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 18652ca5b659SJoost Mulders VR_CAM_CTRL_ENABLE|VR_CAM_CTRL_SELECT_VLAN); 18662ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_VCAM0, 0); 18672ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_VCAM1, 0); 18682ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_WRITE); 18692ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_CAM_MASK, 1); 18702ca5b659SJoost Mulders drv_usecwait(2); 18712ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE); 18722ca5b659SJoost Mulders } 18732ca5b659SJoost Mulders 18742ca5b659SJoost Mulders /* 18752ca5b659SJoost Mulders * Give the start addresses of the descriptor rings to the DMA 18762ca5b659SJoost Mulders * controller on the MAC. 18772ca5b659SJoost Mulders */ 18782ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_RXADDR, vrp->rx.rp->paddr); 18792ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_TXADDR, vrp->tx.wp->paddr); 18802ca5b659SJoost Mulders 18812ca5b659SJoost Mulders /* 18822ca5b659SJoost Mulders * We don't use the additionally invented interrupt ICR1 register, 18832ca5b659SJoost Mulders * so make sure these are disabled. 18842ca5b659SJoost Mulders */ 18852ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_ISR1, 0xFF); 18862ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_ICR1, 0); 18872ca5b659SJoost Mulders 18882ca5b659SJoost Mulders /* 18892ca5b659SJoost Mulders * Enable interrupts. 18902ca5b659SJoost Mulders */ 18912ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_ISR0, 0xFFFF); 18922ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_ICR0, VR_ICR0_CFG); 18932ca5b659SJoost Mulders 18942ca5b659SJoost Mulders /* 18952ca5b659SJoost Mulders * Enable the DMA controller. 18962ca5b659SJoost Mulders */ 18972ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO); 18982ca5b659SJoost Mulders 18992ca5b659SJoost Mulders /* 19002ca5b659SJoost Mulders * Configure the link. Rely on the link change interrupt for getting 19012ca5b659SJoost Mulders * the link state into the driver. 19022ca5b659SJoost Mulders */ 19032ca5b659SJoost Mulders vr_link_init(vrp); 19042ca5b659SJoost Mulders 19052ca5b659SJoost Mulders /* 19062ca5b659SJoost Mulders * Set the software view on the state to 'running'. 19072ca5b659SJoost Mulders */ 19082ca5b659SJoost Mulders vrp->chip.state = CHIPSTATE_RUNNING; 19092ca5b659SJoost Mulders return (0); 19102ca5b659SJoost Mulders } 19112ca5b659SJoost Mulders 19122ca5b659SJoost Mulders /* 19132ca5b659SJoost Mulders * Stop DMA and interrupts. 19142ca5b659SJoost Mulders */ 19152ca5b659SJoost Mulders static int 19162ca5b659SJoost Mulders vr_stop(vr_t *vrp) 19172ca5b659SJoost Mulders { 19182ca5b659SJoost Mulders ASSERT(mutex_owned(&vrp->oplock)); 19192ca5b659SJoost Mulders 19202ca5b659SJoost Mulders /* 19212ca5b659SJoost Mulders * Stop interrupts. 19222ca5b659SJoost Mulders */ 19232ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_ICR0, 0); 19242ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_ICR1, 0); 19252ca5b659SJoost Mulders 19262ca5b659SJoost Mulders /* 19272ca5b659SJoost Mulders * Stop DMA. 19282ca5b659SJoost Mulders */ 19292ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_STOP); 19302ca5b659SJoost Mulders 19312ca5b659SJoost Mulders /* 19322ca5b659SJoost Mulders * Set the software view on the state to stopped. 19332ca5b659SJoost Mulders */ 19342ca5b659SJoost Mulders vrp->chip.state = CHIPSTATE_STOPPED; 19352ca5b659SJoost Mulders 19362ca5b659SJoost Mulders /* 19372ca5b659SJoost Mulders * Remove DMA buffers from the rings. 19382ca5b659SJoost Mulders */ 19392ca5b659SJoost Mulders vr_rxring_fini(vrp); 19402ca5b659SJoost Mulders vr_txring_fini(vrp); 19412ca5b659SJoost Mulders return (0); 19422ca5b659SJoost Mulders } 19432ca5b659SJoost Mulders 19442ca5b659SJoost Mulders int 19452ca5b659SJoost Mulders vr_mac_start(void *p) 19462ca5b659SJoost Mulders { 19472ca5b659SJoost Mulders vr_t *vrp; 19482ca5b659SJoost Mulders int rc; 19492ca5b659SJoost Mulders 19502ca5b659SJoost Mulders vrp = (vr_t *)p; 19512ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 19522ca5b659SJoost Mulders 19532ca5b659SJoost Mulders /* 19542ca5b659SJoost Mulders * Reset the card. 19552ca5b659SJoost Mulders */ 19562ca5b659SJoost Mulders vr_reset(vrp); 19572ca5b659SJoost Mulders 19582ca5b659SJoost Mulders /* 19592ca5b659SJoost Mulders * Prepare and enable the card. 19602ca5b659SJoost Mulders */ 19612ca5b659SJoost Mulders rc = vr_start(vrp); 19622ca5b659SJoost Mulders 19632ca5b659SJoost Mulders /* 19642ca5b659SJoost Mulders * Configure a cyclic function to keep the card & driver from diverting. 19652ca5b659SJoost Mulders */ 19662ca5b659SJoost Mulders vrp->periodic_id = 19672ca5b659SJoost Mulders ddi_periodic_add(vr_periodic, vrp, VR_CHECK_INTERVAL, DDI_IPL_0); 19682ca5b659SJoost Mulders 19692ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 19702ca5b659SJoost Mulders return (rc); 19712ca5b659SJoost Mulders } 19722ca5b659SJoost Mulders 19732ca5b659SJoost Mulders void 19742ca5b659SJoost Mulders vr_mac_stop(void *p) 19752ca5b659SJoost Mulders { 19762ca5b659SJoost Mulders vr_t *vrp = p; 19772ca5b659SJoost Mulders 19782ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 19792ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 19802ca5b659SJoost Mulders 19812ca5b659SJoost Mulders /* 19822ca5b659SJoost Mulders * Stop the device. 19832ca5b659SJoost Mulders */ 19842ca5b659SJoost Mulders (void) vr_stop(vrp); 19852ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 19862ca5b659SJoost Mulders 19872ca5b659SJoost Mulders /* 19882ca5b659SJoost Mulders * Remove the cyclic from the system. 19892ca5b659SJoost Mulders */ 19902ca5b659SJoost Mulders ddi_periodic_delete(vrp->periodic_id); 19912ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 19922ca5b659SJoost Mulders } 19932ca5b659SJoost Mulders 19942ca5b659SJoost Mulders /* 19952ca5b659SJoost Mulders * Add or remove a multicast address to/from the filter 19962ca5b659SJoost Mulders * 19972ca5b659SJoost Mulders * From the 21143 manual: 19982ca5b659SJoost Mulders * The 21143 can store 512 bits serving as hash bucket heads, and one physical 19992ca5b659SJoost Mulders * 48-bit Ethernet address. Incoming frames with multicast destination 20002ca5b659SJoost Mulders * addresses are subjected to imperfect filtering. Frames with physical 20012ca5b659SJoost Mulders * destination addresses are checked against the single physical address. 20022ca5b659SJoost Mulders * For any incoming frame with a multicast destination address, the 21143 20032ca5b659SJoost Mulders * applies the standard Ethernet cyclic redundancy check (CRC) function to the 20042ca5b659SJoost Mulders * first 6 bytes containing the destination address, then it uses the most 20052ca5b659SJoost Mulders * significant 9 bits of the result as a bit index into the table. If the 20062ca5b659SJoost Mulders * indexed bit is set, the frame is accepted. If the bit is cleared, the frame 20072ca5b659SJoost Mulders * is rejected. This filtering mode is called imperfect because multicast 20082ca5b659SJoost Mulders * frames not addressed to this station may slip through, but it still 20092ca5b659SJoost Mulders * decreases the number of frames that the host can receive. 20102ca5b659SJoost Mulders * I assume the above is also the way the VIA chips work. There's not a single 20112ca5b659SJoost Mulders * word about the multicast filter in the datasheet. 20122ca5b659SJoost Mulders * 20132ca5b659SJoost Mulders * Another word on the CAM filter on VT6105M controllers: 20142ca5b659SJoost Mulders * The VT6105M has content addressable memory which can be used for perfect 20152ca5b659SJoost Mulders * filtering of 32 multicast addresses and a few VLAN id's 20162ca5b659SJoost Mulders * 20172ca5b659SJoost Mulders * I think it works like this: When the controller receives a multicast 20182ca5b659SJoost Mulders * address, it looks up the address using CAM. When it is found, it takes the 20192ca5b659SJoost Mulders * matching cell address (index) and compares this to the bit position in the 20202ca5b659SJoost Mulders * cam mask. If the bit is set, the packet is passed up. If CAM lookup does not 20212ca5b659SJoost Mulders * result in a match, the packet is filtered using the hash based filter, 20222ca5b659SJoost Mulders * if that matches, the packet is passed up and dropped otherwise 20232ca5b659SJoost Mulders * Also, there's not a single word in the datasheet on how this cam is supposed 20242ca5b659SJoost Mulders * to work ... 20252ca5b659SJoost Mulders */ 20262ca5b659SJoost Mulders int 20272ca5b659SJoost Mulders vr_mac_set_multicast(void *p, boolean_t add, const uint8_t *mca) 20282ca5b659SJoost Mulders { 20292ca5b659SJoost Mulders vr_t *vrp; 20302ca5b659SJoost Mulders uint32_t crc_index; 20312ca5b659SJoost Mulders int32_t cam_index; 20322ca5b659SJoost Mulders uint32_t cam_mask; 20332ca5b659SJoost Mulders boolean_t use_hash_filter; 20342ca5b659SJoost Mulders ether_addr_t taddr; 20352ca5b659SJoost Mulders uint32_t a; 20362ca5b659SJoost Mulders 20372ca5b659SJoost Mulders vrp = (vr_t *)p; 20382ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 20392ca5b659SJoost Mulders mutex_enter(&vrp->intrlock); 20402ca5b659SJoost Mulders use_hash_filter = B_FALSE; 20412ca5b659SJoost Mulders 20422ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_CAMSUPPORT) != 0) { 20432ca5b659SJoost Mulders /* 20442ca5b659SJoost Mulders * Program the perfect filter. 20452ca5b659SJoost Mulders */ 20462ca5b659SJoost Mulders cam_mask = VR_GET32(vrp->acc_reg, VR_CAM_MASK); 20472ca5b659SJoost Mulders if (add == B_TRUE) { 20482ca5b659SJoost Mulders /* 20492ca5b659SJoost Mulders * Get index of first empty slot. 20502ca5b659SJoost Mulders */ 20512ca5b659SJoost Mulders bzero(&taddr, sizeof (taddr)); 20522ca5b659SJoost Mulders cam_index = vr_cam_index(vrp, taddr); 20532ca5b659SJoost Mulders if (cam_index != -1) { 20542ca5b659SJoost Mulders /* 20552ca5b659SJoost Mulders * Add address at cam_index. 20562ca5b659SJoost Mulders */ 20572ca5b659SJoost Mulders cam_mask |= (1 << cam_index); 20582ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 20592ca5b659SJoost Mulders VR_CAM_CTRL_ENABLE); 20602ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_ADDR, cam_index); 20612ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_CAM_MASK, cam_mask); 20622ca5b659SJoost Mulders for (a = 0; a < ETHERADDRL; a++) { 20632ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, 20642ca5b659SJoost Mulders VR_MCAM0 + a, mca[a]); 20652ca5b659SJoost Mulders } 20662ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 20672ca5b659SJoost Mulders VR_CAM_CTRL_WRITE); 20682ca5b659SJoost Mulders drv_usecwait(2); 20692ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 20702ca5b659SJoost Mulders VR_CAM_CTRL_DONE); 20712ca5b659SJoost Mulders } else { 20722ca5b659SJoost Mulders /* 20732ca5b659SJoost Mulders * No free CAM slots available 20742ca5b659SJoost Mulders * Add mca to the imperfect filter. 20752ca5b659SJoost Mulders */ 20762ca5b659SJoost Mulders use_hash_filter = B_TRUE; 20772ca5b659SJoost Mulders } 20782ca5b659SJoost Mulders } else { 20792ca5b659SJoost Mulders /* 20802ca5b659SJoost Mulders * Find the index of the entry to remove 20812ca5b659SJoost Mulders * If the entry was not found (-1), the addition was 20822ca5b659SJoost Mulders * probably done when the table was full. 20832ca5b659SJoost Mulders */ 20842ca5b659SJoost Mulders cam_index = vr_cam_index(vrp, mca); 20852ca5b659SJoost Mulders if (cam_index != -1) { 20862ca5b659SJoost Mulders /* 20872ca5b659SJoost Mulders * Disable the corresponding mask bit. 20882ca5b659SJoost Mulders */ 20892ca5b659SJoost Mulders cam_mask &= ~(1 << cam_index); 20902ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 20912ca5b659SJoost Mulders VR_CAM_CTRL_ENABLE); 20922ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_CAM_MASK, cam_mask); 20932ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, 20942ca5b659SJoost Mulders VR_CAM_CTRL_DONE); 20952ca5b659SJoost Mulders } else { 20962ca5b659SJoost Mulders /* 20972ca5b659SJoost Mulders * The entry to be removed was not found 20982ca5b659SJoost Mulders * The likely cause is that the CAM was full 20992ca5b659SJoost Mulders * during addition. The entry is added to the 21002ca5b659SJoost Mulders * hash filter in that case and needs to be 21012ca5b659SJoost Mulders * removed there too. 21022ca5b659SJoost Mulders */ 21032ca5b659SJoost Mulders use_hash_filter = B_TRUE; 21042ca5b659SJoost Mulders } 21052ca5b659SJoost Mulders } 21062ca5b659SJoost Mulders } else { 21072ca5b659SJoost Mulders /* 21082ca5b659SJoost Mulders * No CAM in the MAC, thus we need the hash filter. 21092ca5b659SJoost Mulders */ 21102ca5b659SJoost Mulders use_hash_filter = B_TRUE; 21112ca5b659SJoost Mulders } 21122ca5b659SJoost Mulders 21132ca5b659SJoost Mulders if (use_hash_filter == B_TRUE) { 21142ca5b659SJoost Mulders /* 21152ca5b659SJoost Mulders * Get the CRC-32 of the multicast address 21162ca5b659SJoost Mulders * The card uses the "MSB first" direction when calculating the 21172ca5b659SJoost Mulders * the CRC. This is odd because ethernet is "LSB first" 21182ca5b659SJoost Mulders * We have to use that "big endian" approach as well. 21192ca5b659SJoost Mulders */ 21202ca5b659SJoost Mulders crc_index = ether_crc_be(mca) >> (32 - 6); 21212ca5b659SJoost Mulders if (add == B_TRUE) { 21222ca5b659SJoost Mulders /* 21232ca5b659SJoost Mulders * Turn bit[crc_index] on. 21242ca5b659SJoost Mulders */ 21252ca5b659SJoost Mulders if (crc_index < 32) 21262ca5b659SJoost Mulders vrp->mhash0 |= (1 << crc_index); 21272ca5b659SJoost Mulders else 21282ca5b659SJoost Mulders vrp->mhash1 |= (1 << (crc_index - 32)); 21292ca5b659SJoost Mulders } else { 21302ca5b659SJoost Mulders /* 21312ca5b659SJoost Mulders * Turn bit[crc_index] off. 21322ca5b659SJoost Mulders */ 21332ca5b659SJoost Mulders if (crc_index < 32) 21342ca5b659SJoost Mulders vrp->mhash0 &= ~(0 << crc_index); 21352ca5b659SJoost Mulders else 21362ca5b659SJoost Mulders vrp->mhash1 &= ~(0 << (crc_index - 32)); 21372ca5b659SJoost Mulders } 21382ca5b659SJoost Mulders 21392ca5b659SJoost Mulders /* 21402ca5b659SJoost Mulders * When not promiscuous write the filter now. When promiscuous, 21412ca5b659SJoost Mulders * the filter is open and will be written when promiscuous ends. 21422ca5b659SJoost Mulders */ 21432ca5b659SJoost Mulders if (vrp->promisc == B_FALSE) { 21442ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR0, vrp->mhash0); 21452ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR1, vrp->mhash1); 21462ca5b659SJoost Mulders } 21472ca5b659SJoost Mulders } 21482ca5b659SJoost Mulders 21492ca5b659SJoost Mulders /* 21502ca5b659SJoost Mulders * Enable/disable multicast receivements based on mcount. 21512ca5b659SJoost Mulders */ 21522ca5b659SJoost Mulders if (add == B_TRUE) 21532ca5b659SJoost Mulders vrp->mcount++; 21542ca5b659SJoost Mulders else if (vrp->mcount != 0) 21552ca5b659SJoost Mulders vrp->mcount --; 21562ca5b659SJoost Mulders if (vrp->mcount != 0) 21572ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTMULTI); 21582ca5b659SJoost Mulders else 21592ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTMULTI); 21602ca5b659SJoost Mulders 21612ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 21622ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 21632ca5b659SJoost Mulders return (0); 21642ca5b659SJoost Mulders } 21652ca5b659SJoost Mulders 21662ca5b659SJoost Mulders /* 21672ca5b659SJoost Mulders * Calculate the CRC32 for 6 bytes of multicast address in MSB(it) first order. 21682ca5b659SJoost Mulders * The MSB first order is a bit odd because Ethernet standard is LSB first 21692ca5b659SJoost Mulders */ 21702ca5b659SJoost Mulders static uint32_t 21712ca5b659SJoost Mulders ether_crc_be(const uint8_t *data) 21722ca5b659SJoost Mulders { 21732ca5b659SJoost Mulders uint32_t crc = (uint32_t)0xFFFFFFFFU; 21742ca5b659SJoost Mulders uint32_t carry; 21752ca5b659SJoost Mulders uint32_t bit; 21762ca5b659SJoost Mulders uint32_t length; 21772ca5b659SJoost Mulders uint8_t c; 21782ca5b659SJoost Mulders 21792ca5b659SJoost Mulders for (length = 0; length < ETHERADDRL; length++) { 21802ca5b659SJoost Mulders c = data[length]; 21812ca5b659SJoost Mulders for (bit = 0; bit < 8; bit++) { 21822ca5b659SJoost Mulders carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); 21832ca5b659SJoost Mulders crc <<= 1; 21842ca5b659SJoost Mulders c >>= 1; 21852ca5b659SJoost Mulders if (carry) 21862ca5b659SJoost Mulders crc = (crc ^ 0x04C11DB6) | carry; 21872ca5b659SJoost Mulders } 21882ca5b659SJoost Mulders } 21892ca5b659SJoost Mulders return (crc); 21902ca5b659SJoost Mulders } 21912ca5b659SJoost Mulders 21922ca5b659SJoost Mulders 21932ca5b659SJoost Mulders /* 21942ca5b659SJoost Mulders * Return the CAM index (base 0) of maddr or -1 if maddr is not found 21952ca5b659SJoost Mulders * If maddr is 0, return the index of an empty slot in CAM or -1 when no free 21962ca5b659SJoost Mulders * slots available. 21972ca5b659SJoost Mulders */ 21982ca5b659SJoost Mulders static int32_t 21992ca5b659SJoost Mulders vr_cam_index(vr_t *vrp, const uint8_t *maddr) 22002ca5b659SJoost Mulders { 22012ca5b659SJoost Mulders ether_addr_t taddr; 22022ca5b659SJoost Mulders int32_t index; 22032ca5b659SJoost Mulders uint32_t mask; 22042ca5b659SJoost Mulders uint32_t a; 22052ca5b659SJoost Mulders 22062ca5b659SJoost Mulders bzero(&taddr, sizeof (taddr)); 22072ca5b659SJoost Mulders 22082ca5b659SJoost Mulders /* 22092ca5b659SJoost Mulders * Read the CAM mask from the controller. 22102ca5b659SJoost Mulders */ 22112ca5b659SJoost Mulders mask = VR_GET32(vrp->acc_reg, VR_CAM_MASK); 22122ca5b659SJoost Mulders 22132ca5b659SJoost Mulders /* 22142ca5b659SJoost Mulders * If maddr is 0, return the first unused slot or -1 for no unused. 22152ca5b659SJoost Mulders */ 22162ca5b659SJoost Mulders if (bcmp(maddr, taddr, ETHERADDRL) == 0) { 22172ca5b659SJoost Mulders /* 22182ca5b659SJoost Mulders * Look for the first unused position in mask. 22192ca5b659SJoost Mulders */ 22202ca5b659SJoost Mulders for (index = 0; index < VR_CAM_SZ; index++) { 22212ca5b659SJoost Mulders if (((mask >> index) & 1) == 0) 22222ca5b659SJoost Mulders return (index); 22232ca5b659SJoost Mulders } 22242ca5b659SJoost Mulders return (-1); 22252ca5b659SJoost Mulders } else { 22262ca5b659SJoost Mulders /* 22272ca5b659SJoost Mulders * Look for maddr in CAM. 22282ca5b659SJoost Mulders */ 22292ca5b659SJoost Mulders for (index = 0; index < VR_CAM_SZ; index++) { 22302ca5b659SJoost Mulders /* Look at enabled entries only */ 22312ca5b659SJoost Mulders if (((mask >> index) & 1) == 0) 22322ca5b659SJoost Mulders continue; 22332ca5b659SJoost Mulders 22342ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_ENABLE); 22352ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_ADDR, index); 22362ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_READ); 22372ca5b659SJoost Mulders drv_usecwait(2); 22382ca5b659SJoost Mulders for (a = 0; a < ETHERADDRL; a++) 22392ca5b659SJoost Mulders taddr[a] = VR_GET8(vrp->acc_reg, VR_MCAM0 + a); 22402ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE); 22412ca5b659SJoost Mulders if (bcmp(maddr, taddr, ETHERADDRL) == 0) 22422ca5b659SJoost Mulders return (index); 22432ca5b659SJoost Mulders } 22442ca5b659SJoost Mulders } 22452ca5b659SJoost Mulders return (-1); 22462ca5b659SJoost Mulders } 22472ca5b659SJoost Mulders 22482ca5b659SJoost Mulders /* 22492ca5b659SJoost Mulders * Set promiscuous mode on or off. 22502ca5b659SJoost Mulders */ 22512ca5b659SJoost Mulders int 22522ca5b659SJoost Mulders vr_mac_set_promisc(void *p, boolean_t promiscflag) 22532ca5b659SJoost Mulders { 22542ca5b659SJoost Mulders vr_t *vrp; 22552ca5b659SJoost Mulders uint8_t rxcfg; 22562ca5b659SJoost Mulders 22572ca5b659SJoost Mulders vrp = (vr_t *)p; 22582ca5b659SJoost Mulders 22592ca5b659SJoost Mulders mutex_enter(&vrp->intrlock); 22602ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 22612ca5b659SJoost Mulders mutex_enter(&vrp->tx.lock); 22622ca5b659SJoost Mulders 22632ca5b659SJoost Mulders /* 22642ca5b659SJoost Mulders * Get current receive configuration. 22652ca5b659SJoost Mulders */ 22662ca5b659SJoost Mulders rxcfg = VR_GET8(vrp->acc_reg, VR_RXCFG); 22672ca5b659SJoost Mulders vrp->promisc = promiscflag; 22682ca5b659SJoost Mulders 22692ca5b659SJoost Mulders if (promiscflag == B_TRUE) { 22702ca5b659SJoost Mulders /* 22712ca5b659SJoost Mulders * Enable promiscuous mode and open the multicast filter. 22722ca5b659SJoost Mulders */ 22732ca5b659SJoost Mulders rxcfg |= (VR_RXCFG_PROMISC | VR_RXCFG_ACCEPTMULTI); 22742ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR0, 0xffffffff); 22752ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR1, 0xffffffff); 22762ca5b659SJoost Mulders } else { 22772ca5b659SJoost Mulders /* 22782ca5b659SJoost Mulders * Restore the multicast filter and disable promiscuous mode. 22792ca5b659SJoost Mulders */ 22802ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR0, vrp->mhash0); 22812ca5b659SJoost Mulders VR_PUT32(vrp->acc_reg, VR_MAR1, vrp->mhash1); 22822ca5b659SJoost Mulders rxcfg &= ~VR_RXCFG_PROMISC; 22832ca5b659SJoost Mulders if (vrp->mcount != 0) 22842ca5b659SJoost Mulders rxcfg |= VR_RXCFG_ACCEPTMULTI; 22852ca5b659SJoost Mulders } 22862ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_RXCFG, rxcfg); 22872ca5b659SJoost Mulders mutex_exit(&vrp->tx.lock); 22882ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 22892ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 22902ca5b659SJoost Mulders return (0); 22912ca5b659SJoost Mulders } 22922ca5b659SJoost Mulders 22932ca5b659SJoost Mulders int 22942ca5b659SJoost Mulders vr_mac_getstat(void *arg, uint_t stat, uint64_t *val) 22952ca5b659SJoost Mulders { 22962ca5b659SJoost Mulders vr_t *vrp; 22972ca5b659SJoost Mulders uint64_t v; 22982ca5b659SJoost Mulders 22992ca5b659SJoost Mulders vrp = (void *) arg; 23002ca5b659SJoost Mulders 23012ca5b659SJoost Mulders switch (stat) { 23022ca5b659SJoost Mulders default: 23032ca5b659SJoost Mulders return (ENOTSUP); 23042ca5b659SJoost Mulders 23052ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_100T4: 23062ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_T4) != 0; 23072ca5b659SJoost Mulders break; 23082ca5b659SJoost Mulders 23092ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_100FDX: 23102ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_TX_FD) != 0; 23112ca5b659SJoost Mulders break; 23122ca5b659SJoost Mulders 23132ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_100HDX: 23142ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_TX) != 0; 23152ca5b659SJoost Mulders break; 23162ca5b659SJoost Mulders 23172ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_10FDX: 23182ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_ABILITY_10BASE_T_FD) != 0; 23192ca5b659SJoost Mulders break; 23202ca5b659SJoost Mulders 23212ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_10HDX: 23222ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_ABILITY_10BASE_T) != 0; 23232ca5b659SJoost Mulders break; 23242ca5b659SJoost Mulders 23252ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_ASMPAUSE: 23262ca5b659SJoost Mulders v = 0; 23272ca5b659SJoost Mulders break; 23282ca5b659SJoost Mulders 23292ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_AUTONEG: 23302ca5b659SJoost Mulders v = (vrp->chip.mii.control & MII_CONTROL_ANE) != 0; 23312ca5b659SJoost Mulders break; 23322ca5b659SJoost Mulders 23332ca5b659SJoost Mulders case ETHER_STAT_ADV_CAP_PAUSE: 2334bdb9230aSGarrett D'Amore v = (vrp->chip.mii.anadv & MII_ABILITY_PAUSE) != 0; 23352ca5b659SJoost Mulders break; 23362ca5b659SJoost Mulders 23372ca5b659SJoost Mulders case ETHER_STAT_ADV_REMFAULT: 23382ca5b659SJoost Mulders v = (vrp->chip.mii.anadv & MII_AN_ADVERT_REMFAULT) != 0; 23392ca5b659SJoost Mulders break; 23402ca5b659SJoost Mulders 23412ca5b659SJoost Mulders case ETHER_STAT_ALIGN_ERRORS: 23422ca5b659SJoost Mulders v = vrp->stats.ether_stat_align_errors; 23432ca5b659SJoost Mulders break; 23442ca5b659SJoost Mulders 23452ca5b659SJoost Mulders case ETHER_STAT_CAP_100T4: 23462ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_100_BASE_T4) != 0; 23472ca5b659SJoost Mulders break; 23482ca5b659SJoost Mulders 23492ca5b659SJoost Mulders case ETHER_STAT_CAP_100FDX: 23502ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_100_BASEX_FD) != 0; 23512ca5b659SJoost Mulders break; 23522ca5b659SJoost Mulders 23532ca5b659SJoost Mulders case ETHER_STAT_CAP_100HDX: 23542ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_100_BASEX) != 0; 23552ca5b659SJoost Mulders break; 23562ca5b659SJoost Mulders 23572ca5b659SJoost Mulders case ETHER_STAT_CAP_10FDX: 23582ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_10_FD) != 0; 23592ca5b659SJoost Mulders break; 23602ca5b659SJoost Mulders 23612ca5b659SJoost Mulders case ETHER_STAT_CAP_10HDX: 23622ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_10) != 0; 23632ca5b659SJoost Mulders break; 23642ca5b659SJoost Mulders 23652ca5b659SJoost Mulders case ETHER_STAT_CAP_ASMPAUSE: 23662ca5b659SJoost Mulders v = 0; 23672ca5b659SJoost Mulders break; 23682ca5b659SJoost Mulders 23692ca5b659SJoost Mulders case ETHER_STAT_CAP_AUTONEG: 23702ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_CANAUTONEG) != 0; 23712ca5b659SJoost Mulders break; 23722ca5b659SJoost Mulders 23732ca5b659SJoost Mulders case ETHER_STAT_CAP_PAUSE: 23742ca5b659SJoost Mulders v = 1; 23752ca5b659SJoost Mulders break; 23762ca5b659SJoost Mulders 23772ca5b659SJoost Mulders case ETHER_STAT_CAP_REMFAULT: 23782ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0; 23792ca5b659SJoost Mulders break; 23802ca5b659SJoost Mulders 23812ca5b659SJoost Mulders case ETHER_STAT_CARRIER_ERRORS: 23822ca5b659SJoost Mulders /* 23832ca5b659SJoost Mulders * Number of times carrier was lost or never detected on a 23842ca5b659SJoost Mulders * transmission attempt. 23852ca5b659SJoost Mulders */ 23862ca5b659SJoost Mulders v = vrp->stats.ether_stat_carrier_errors; 23872ca5b659SJoost Mulders break; 23882ca5b659SJoost Mulders 23892ca5b659SJoost Mulders case ETHER_STAT_JABBER_ERRORS: 23902ca5b659SJoost Mulders return (ENOTSUP); 23912ca5b659SJoost Mulders 23922ca5b659SJoost Mulders case ETHER_STAT_DEFER_XMTS: 23932ca5b659SJoost Mulders /* 23942ca5b659SJoost Mulders * Packets without collisions where first transmit attempt was 23952ca5b659SJoost Mulders * delayed because the medium was busy. 23962ca5b659SJoost Mulders */ 23972ca5b659SJoost Mulders v = vrp->stats.ether_stat_defer_xmts; 23982ca5b659SJoost Mulders break; 23992ca5b659SJoost Mulders 24002ca5b659SJoost Mulders case ETHER_STAT_EX_COLLISIONS: 24012ca5b659SJoost Mulders /* 24022ca5b659SJoost Mulders * Frames where excess collisions occurred on transmit, causing 24032ca5b659SJoost Mulders * transmit failure. 24042ca5b659SJoost Mulders */ 24052ca5b659SJoost Mulders v = vrp->stats.ether_stat_ex_collisions; 24062ca5b659SJoost Mulders break; 24072ca5b659SJoost Mulders 24082ca5b659SJoost Mulders case ETHER_STAT_FCS_ERRORS: 24092ca5b659SJoost Mulders /* 24102ca5b659SJoost Mulders * Packets received with CRC errors. 24112ca5b659SJoost Mulders */ 24122ca5b659SJoost Mulders v = vrp->stats.ether_stat_fcs_errors; 24132ca5b659SJoost Mulders break; 24142ca5b659SJoost Mulders 24152ca5b659SJoost Mulders case ETHER_STAT_FIRST_COLLISIONS: 24162ca5b659SJoost Mulders /* 24172ca5b659SJoost Mulders * Packets successfully transmitted with exactly one collision. 24182ca5b659SJoost Mulders */ 24192ca5b659SJoost Mulders v = vrp->stats.ether_stat_first_collisions; 24202ca5b659SJoost Mulders break; 24212ca5b659SJoost Mulders 24222ca5b659SJoost Mulders case ETHER_STAT_LINK_ASMPAUSE: 24232ca5b659SJoost Mulders v = 0; 24242ca5b659SJoost Mulders break; 24252ca5b659SJoost Mulders 24262ca5b659SJoost Mulders case ETHER_STAT_LINK_AUTONEG: 24272ca5b659SJoost Mulders v = (vrp->chip.mii.control & MII_CONTROL_ANE) != 0 && 24282ca5b659SJoost Mulders (vrp->chip.mii.status & MII_STATUS_ANDONE) != 0; 24292ca5b659SJoost Mulders break; 24302ca5b659SJoost Mulders 24312ca5b659SJoost Mulders case ETHER_STAT_LINK_DUPLEX: 24322ca5b659SJoost Mulders v = vrp->chip.link.duplex; 24332ca5b659SJoost Mulders break; 24342ca5b659SJoost Mulders 24352ca5b659SJoost Mulders case ETHER_STAT_LINK_PAUSE: 24362ca5b659SJoost Mulders v = vrp->chip.link.flowctrl; 24372ca5b659SJoost Mulders break; 24382ca5b659SJoost Mulders 24392ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_100T4: 24402ca5b659SJoost Mulders v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_T4) != 0; 24412ca5b659SJoost Mulders break; 24422ca5b659SJoost Mulders 24432ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_1000FDX: 24442ca5b659SJoost Mulders v = 0; 24452ca5b659SJoost Mulders break; 24462ca5b659SJoost Mulders 24472ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_1000HDX: 24482ca5b659SJoost Mulders v = 0; 24492ca5b659SJoost Mulders break; 24502ca5b659SJoost Mulders 24512ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_100FDX: 24522ca5b659SJoost Mulders v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_TX_FD) != 0; 24532ca5b659SJoost Mulders break; 24542ca5b659SJoost Mulders 24552ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_100HDX: 24562ca5b659SJoost Mulders v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_TX) != 0; 24572ca5b659SJoost Mulders break; 24582ca5b659SJoost Mulders 24592ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_10FDX: 24602ca5b659SJoost Mulders v = (vrp->chip.mii.lpable & MII_ABILITY_10BASE_T_FD) != 0; 24612ca5b659SJoost Mulders break; 24622ca5b659SJoost Mulders 24632ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_10HDX: 24642ca5b659SJoost Mulders v = (vrp->chip.mii.lpable & MII_ABILITY_10BASE_T) != 0; 24652ca5b659SJoost Mulders break; 24662ca5b659SJoost Mulders 24672ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_ASMPAUSE: 24682ca5b659SJoost Mulders v = 0; 24692ca5b659SJoost Mulders break; 24702ca5b659SJoost Mulders 24712ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_AUTONEG: 24722ca5b659SJoost Mulders v = (vrp->chip.mii.anexp & MII_AN_EXP_LPCANAN) != 0; 24732ca5b659SJoost Mulders break; 24742ca5b659SJoost Mulders 24752ca5b659SJoost Mulders case ETHER_STAT_LP_CAP_PAUSE: 2476bdb9230aSGarrett D'Amore v = (vrp->chip.mii.lpable & MII_ABILITY_PAUSE) != 0; 24772ca5b659SJoost Mulders break; 24782ca5b659SJoost Mulders 24792ca5b659SJoost Mulders case ETHER_STAT_LP_REMFAULT: 24802ca5b659SJoost Mulders v = (vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0; 24812ca5b659SJoost Mulders break; 24822ca5b659SJoost Mulders 24832ca5b659SJoost Mulders case ETHER_STAT_MACRCV_ERRORS: 24842ca5b659SJoost Mulders /* 24852ca5b659SJoost Mulders * Packets received with MAC errors, except align_errors, 24862ca5b659SJoost Mulders * fcs_errors, and toolong_errors. 24872ca5b659SJoost Mulders */ 24882ca5b659SJoost Mulders v = vrp->stats.ether_stat_macrcv_errors; 24892ca5b659SJoost Mulders break; 24902ca5b659SJoost Mulders 24912ca5b659SJoost Mulders case ETHER_STAT_MACXMT_ERRORS: 24922ca5b659SJoost Mulders /* 24932ca5b659SJoost Mulders * Packets encountering transmit MAC failures, except carrier 24942ca5b659SJoost Mulders * and collision failures. 24952ca5b659SJoost Mulders */ 24962ca5b659SJoost Mulders v = vrp->stats.ether_stat_macxmt_errors; 24972ca5b659SJoost Mulders break; 24982ca5b659SJoost Mulders 24992ca5b659SJoost Mulders case ETHER_STAT_MULTI_COLLISIONS: 25002ca5b659SJoost Mulders /* 25012ca5b659SJoost Mulders * Packets successfully transmitted with multiple collisions. 25022ca5b659SJoost Mulders */ 25032ca5b659SJoost Mulders v = vrp->stats.ether_stat_multi_collisions; 25042ca5b659SJoost Mulders break; 25052ca5b659SJoost Mulders 25062ca5b659SJoost Mulders case ETHER_STAT_SQE_ERRORS: 25072ca5b659SJoost Mulders /* 25082ca5b659SJoost Mulders * Number of times signal quality error was reported 25092ca5b659SJoost Mulders * This one is reported by the PHY. 25102ca5b659SJoost Mulders */ 25112ca5b659SJoost Mulders return (ENOTSUP); 25122ca5b659SJoost Mulders 25132ca5b659SJoost Mulders case ETHER_STAT_TOOLONG_ERRORS: 25142ca5b659SJoost Mulders /* 25152ca5b659SJoost Mulders * Packets received larger than the maximum permitted length. 25162ca5b659SJoost Mulders */ 25172ca5b659SJoost Mulders v = vrp->stats.ether_stat_toolong_errors; 25182ca5b659SJoost Mulders break; 25192ca5b659SJoost Mulders 25202ca5b659SJoost Mulders case ETHER_STAT_TOOSHORT_ERRORS: 25212ca5b659SJoost Mulders v = vrp->stats.ether_stat_tooshort_errors; 25222ca5b659SJoost Mulders break; 25232ca5b659SJoost Mulders 25242ca5b659SJoost Mulders case ETHER_STAT_TX_LATE_COLLISIONS: 25252ca5b659SJoost Mulders /* 25262ca5b659SJoost Mulders * Number of times a transmit collision occurred late 25272ca5b659SJoost Mulders * (after 512 bit times). 25282ca5b659SJoost Mulders */ 25292ca5b659SJoost Mulders v = vrp->stats.ether_stat_tx_late_collisions; 25302ca5b659SJoost Mulders break; 25312ca5b659SJoost Mulders 25322ca5b659SJoost Mulders case ETHER_STAT_XCVR_ADDR: 25332ca5b659SJoost Mulders /* 25342ca5b659SJoost Mulders * MII address in the 0 to 31 range of the physical layer 25352ca5b659SJoost Mulders * device in use for a given Ethernet device. 25362ca5b659SJoost Mulders */ 25372ca5b659SJoost Mulders v = vrp->chip.phyaddr; 25382ca5b659SJoost Mulders break; 25392ca5b659SJoost Mulders 25402ca5b659SJoost Mulders case ETHER_STAT_XCVR_ID: 25412ca5b659SJoost Mulders /* 25422ca5b659SJoost Mulders * MII transceiver manufacturer and device ID. 25432ca5b659SJoost Mulders */ 25442ca5b659SJoost Mulders v = (vrp->chip.mii.identh << 16) | vrp->chip.mii.identl; 25452ca5b659SJoost Mulders break; 25462ca5b659SJoost Mulders 25472ca5b659SJoost Mulders case ETHER_STAT_XCVR_INUSE: 25482ca5b659SJoost Mulders v = vrp->chip.link.mau; 25492ca5b659SJoost Mulders break; 25502ca5b659SJoost Mulders 25512ca5b659SJoost Mulders case MAC_STAT_BRDCSTRCV: 25522ca5b659SJoost Mulders v = vrp->stats.mac_stat_brdcstrcv; 25532ca5b659SJoost Mulders break; 25542ca5b659SJoost Mulders 25552ca5b659SJoost Mulders case MAC_STAT_BRDCSTXMT: 25562ca5b659SJoost Mulders v = vrp->stats.mac_stat_brdcstxmt; 25572ca5b659SJoost Mulders break; 25582ca5b659SJoost Mulders 25592ca5b659SJoost Mulders case MAC_STAT_MULTIXMT: 25602ca5b659SJoost Mulders v = vrp->stats.mac_stat_multixmt; 25612ca5b659SJoost Mulders break; 25622ca5b659SJoost Mulders 25632ca5b659SJoost Mulders case MAC_STAT_COLLISIONS: 25642ca5b659SJoost Mulders v = vrp->stats.mac_stat_collisions; 25652ca5b659SJoost Mulders break; 25662ca5b659SJoost Mulders 25672ca5b659SJoost Mulders case MAC_STAT_IERRORS: 25682ca5b659SJoost Mulders v = vrp->stats.mac_stat_ierrors; 25692ca5b659SJoost Mulders break; 25702ca5b659SJoost Mulders 25712ca5b659SJoost Mulders case MAC_STAT_IFSPEED: 25722ca5b659SJoost Mulders if (vrp->chip.link.speed == VR_LINK_SPEED_100MBS) 25732ca5b659SJoost Mulders v = 100 * 1000 * 1000; 25742ca5b659SJoost Mulders else if (vrp->chip.link.speed == VR_LINK_SPEED_10MBS) 25752ca5b659SJoost Mulders v = 10 * 1000 * 1000; 25762ca5b659SJoost Mulders else 25772ca5b659SJoost Mulders v = 0; 25782ca5b659SJoost Mulders break; 25792ca5b659SJoost Mulders 25802ca5b659SJoost Mulders case MAC_STAT_IPACKETS: 25812ca5b659SJoost Mulders v = vrp->stats.mac_stat_ipackets; 25822ca5b659SJoost Mulders break; 25832ca5b659SJoost Mulders 25842ca5b659SJoost Mulders case MAC_STAT_MULTIRCV: 25852ca5b659SJoost Mulders v = vrp->stats.mac_stat_multircv; 25862ca5b659SJoost Mulders break; 25872ca5b659SJoost Mulders 25882ca5b659SJoost Mulders case MAC_STAT_NORCVBUF: 25892ca5b659SJoost Mulders vrp->stats.mac_stat_norcvbuf += 25902ca5b659SJoost Mulders VR_GET16(vrp->acc_reg, VR_TALLY_MPA); 25912ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_TALLY_MPA, 0); 25922ca5b659SJoost Mulders v = vrp->stats.mac_stat_norcvbuf; 25932ca5b659SJoost Mulders break; 25942ca5b659SJoost Mulders 25952ca5b659SJoost Mulders case MAC_STAT_NOXMTBUF: 25962ca5b659SJoost Mulders v = vrp->stats.mac_stat_noxmtbuf; 25972ca5b659SJoost Mulders break; 25982ca5b659SJoost Mulders 25992ca5b659SJoost Mulders case MAC_STAT_OBYTES: 26002ca5b659SJoost Mulders v = vrp->stats.mac_stat_obytes; 26012ca5b659SJoost Mulders break; 26022ca5b659SJoost Mulders 26032ca5b659SJoost Mulders case MAC_STAT_OERRORS: 26042ca5b659SJoost Mulders v = vrp->stats.ether_stat_macxmt_errors + 26052ca5b659SJoost Mulders vrp->stats.mac_stat_underflows + 26062ca5b659SJoost Mulders vrp->stats.ether_stat_align_errors + 26072ca5b659SJoost Mulders vrp->stats.ether_stat_carrier_errors + 26082ca5b659SJoost Mulders vrp->stats.ether_stat_fcs_errors; 26092ca5b659SJoost Mulders break; 26102ca5b659SJoost Mulders 26112ca5b659SJoost Mulders case MAC_STAT_OPACKETS: 26122ca5b659SJoost Mulders v = vrp->stats.mac_stat_opackets; 26132ca5b659SJoost Mulders break; 26142ca5b659SJoost Mulders 26152ca5b659SJoost Mulders case MAC_STAT_RBYTES: 26162ca5b659SJoost Mulders v = vrp->stats.mac_stat_rbytes; 26172ca5b659SJoost Mulders break; 26182ca5b659SJoost Mulders 26192ca5b659SJoost Mulders case MAC_STAT_UNKNOWNS: 26202ca5b659SJoost Mulders /* 26212ca5b659SJoost Mulders * Isn't this something for the MAC layer to maintain? 26222ca5b659SJoost Mulders */ 26232ca5b659SJoost Mulders return (ENOTSUP); 26242ca5b659SJoost Mulders 26252ca5b659SJoost Mulders case MAC_STAT_UNDERFLOWS: 26262ca5b659SJoost Mulders v = vrp->stats.mac_stat_underflows; 26272ca5b659SJoost Mulders break; 26282ca5b659SJoost Mulders 26292ca5b659SJoost Mulders case MAC_STAT_OVERFLOWS: 26302ca5b659SJoost Mulders v = vrp->stats.mac_stat_overflows; 26312ca5b659SJoost Mulders break; 26322ca5b659SJoost Mulders } 26332ca5b659SJoost Mulders *val = v; 26342ca5b659SJoost Mulders return (0); 26352ca5b659SJoost Mulders } 26362ca5b659SJoost Mulders 26372ca5b659SJoost Mulders int 26382ca5b659SJoost Mulders vr_mac_set_ether_addr(void *p, const uint8_t *ea) 26392ca5b659SJoost Mulders { 26402ca5b659SJoost Mulders vr_t *vrp; 26412ca5b659SJoost Mulders int i; 26422ca5b659SJoost Mulders 26432ca5b659SJoost Mulders vrp = (vr_t *)p; 26442ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 26452ca5b659SJoost Mulders mutex_enter(&vrp->intrlock); 26462ca5b659SJoost Mulders 26472ca5b659SJoost Mulders /* 26482ca5b659SJoost Mulders * Set a new station address. 26492ca5b659SJoost Mulders */ 26502ca5b659SJoost Mulders for (i = 0; i < ETHERADDRL; i++) 26512ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_ETHERADDR + i, ea[i]); 26522ca5b659SJoost Mulders 26532ca5b659SJoost Mulders mutex_exit(&vrp->intrlock); 26542ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 26552ca5b659SJoost Mulders return (0); 26562ca5b659SJoost Mulders } 26572ca5b659SJoost Mulders 26582ca5b659SJoost Mulders /* 26592ca5b659SJoost Mulders * Configure the ethernet link according to param and chip.mii. 26602ca5b659SJoost Mulders */ 26612ca5b659SJoost Mulders static void 26622ca5b659SJoost Mulders vr_link_init(vr_t *vrp) 26632ca5b659SJoost Mulders { 26642ca5b659SJoost Mulders ASSERT(mutex_owned(&vrp->oplock)); 26652ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_ANE) != 0) { 26662ca5b659SJoost Mulders /* 26672ca5b659SJoost Mulders * If we do autoneg, ensure restart autoneg is ON. 26682ca5b659SJoost Mulders */ 26692ca5b659SJoost Mulders vrp->chip.mii.control |= MII_CONTROL_RSAN; 26702ca5b659SJoost Mulders 26712ca5b659SJoost Mulders /* 26722ca5b659SJoost Mulders * The advertisements are prepared by param_init. 26732ca5b659SJoost Mulders */ 26742ca5b659SJoost Mulders vr_phy_write(vrp, MII_AN_ADVERT, vrp->chip.mii.anadv); 26752ca5b659SJoost Mulders } else { 26762ca5b659SJoost Mulders /* 26772ca5b659SJoost Mulders * If we don't autoneg, we need speed, duplex and flowcontrol 26782ca5b659SJoost Mulders * to configure the link. However, dladm doesn't allow changes 26792ca5b659SJoost Mulders * to speed and duplex (readonly). The way this is solved 26802ca5b659SJoost Mulders * (ahem) is to select the highest enabled combination 26812ca5b659SJoost Mulders * Speed and duplex should be r/w when autoneg is off. 26822ca5b659SJoost Mulders */ 26832ca5b659SJoost Mulders if ((vrp->param.anadv_en & 26842ca5b659SJoost Mulders MII_ABILITY_100BASE_TX_FD) != 0) { 26852ca5b659SJoost Mulders vrp->chip.mii.control |= MII_CONTROL_100MB; 26862ca5b659SJoost Mulders vrp->chip.mii.control |= MII_CONTROL_FDUPLEX; 26872ca5b659SJoost Mulders } else if ((vrp->param.anadv_en & 26882ca5b659SJoost Mulders MII_ABILITY_100BASE_TX) != 0) { 26892ca5b659SJoost Mulders vrp->chip.mii.control |= MII_CONTROL_100MB; 26902ca5b659SJoost Mulders vrp->chip.mii.control &= ~MII_CONTROL_FDUPLEX; 26912ca5b659SJoost Mulders } else if ((vrp->param.anadv_en & 26922ca5b659SJoost Mulders MII_ABILITY_10BASE_T_FD) != 0) { 26932ca5b659SJoost Mulders vrp->chip.mii.control |= MII_CONTROL_FDUPLEX; 26942ca5b659SJoost Mulders vrp->chip.mii.control &= ~MII_CONTROL_100MB; 26952ca5b659SJoost Mulders } else { 26962ca5b659SJoost Mulders vrp->chip.mii.control &= ~MII_CONTROL_100MB; 26972ca5b659SJoost Mulders vrp->chip.mii.control &= ~MII_CONTROL_FDUPLEX; 26982ca5b659SJoost Mulders } 26992ca5b659SJoost Mulders } 27002ca5b659SJoost Mulders /* 27012ca5b659SJoost Mulders * Write the control register. 27022ca5b659SJoost Mulders */ 27032ca5b659SJoost Mulders vr_phy_write(vrp, MII_CONTROL, vrp->chip.mii.control); 27042ca5b659SJoost Mulders 27052ca5b659SJoost Mulders /* 27062ca5b659SJoost Mulders * With autoneg off we cannot rely on the link_change interrupt for 27072ca5b659SJoost Mulders * for getting the status into the driver. 27082ca5b659SJoost Mulders */ 27092ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_ANE) == 0) { 27102ca5b659SJoost Mulders vr_link_state(vrp); 27112ca5b659SJoost Mulders mac_link_update(vrp->machdl, 27122ca5b659SJoost Mulders (link_state_t)vrp->chip.link.state); 27132ca5b659SJoost Mulders } 27142ca5b659SJoost Mulders } 27152ca5b659SJoost Mulders 27162ca5b659SJoost Mulders /* 27172ca5b659SJoost Mulders * Get link state in the driver and configure the MAC accordingly. 27182ca5b659SJoost Mulders */ 27192ca5b659SJoost Mulders static void 27202ca5b659SJoost Mulders vr_link_state(vr_t *vrp) 27212ca5b659SJoost Mulders { 27222ca5b659SJoost Mulders uint16_t mask; 27232ca5b659SJoost Mulders 27242ca5b659SJoost Mulders ASSERT(mutex_owned(&vrp->oplock)); 27252ca5b659SJoost Mulders 27262ca5b659SJoost Mulders vr_phy_read(vrp, MII_STATUS, &vrp->chip.mii.status); 27272ca5b659SJoost Mulders vr_phy_read(vrp, MII_CONTROL, &vrp->chip.mii.control); 27282ca5b659SJoost Mulders vr_phy_read(vrp, MII_AN_ADVERT, &vrp->chip.mii.anadv); 27292ca5b659SJoost Mulders vr_phy_read(vrp, MII_AN_LPABLE, &vrp->chip.mii.lpable); 27302ca5b659SJoost Mulders vr_phy_read(vrp, MII_AN_EXPANSION, &vrp->chip.mii.anexp); 27312ca5b659SJoost Mulders 27322ca5b659SJoost Mulders /* 27332ca5b659SJoost Mulders * If we did autongeg, deduce the link type/speed by selecting the 27342ca5b659SJoost Mulders * highest common denominator. 27352ca5b659SJoost Mulders */ 27362ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_ANE) != 0) { 27372ca5b659SJoost Mulders mask = vrp->chip.mii.anadv & vrp->chip.mii.lpable; 27382ca5b659SJoost Mulders if ((mask & MII_ABILITY_100BASE_TX_FD) != 0) { 27392ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_100MBS; 27402ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL; 27412ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_100X; 27422ca5b659SJoost Mulders } else if ((mask & MII_ABILITY_100BASE_T4) != 0) { 27432ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_100MBS; 27442ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF; 27452ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_100T4; 27462ca5b659SJoost Mulders } else if ((mask & MII_ABILITY_100BASE_TX) != 0) { 27472ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_100MBS; 27482ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF; 27492ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_100X; 27502ca5b659SJoost Mulders } else if ((mask & MII_ABILITY_10BASE_T_FD) != 0) { 27512ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_10MBS; 27522ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL; 27532ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_10; 27542ca5b659SJoost Mulders } else if ((mask & MII_ABILITY_10BASE_T) != 0) { 27552ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_10MBS; 27562ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF; 27572ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_10; 27582ca5b659SJoost Mulders } else { 27592ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_UNKNOWN; 27602ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_UNKNOWN; 27612ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_UNKNOWN; 27622ca5b659SJoost Mulders } 27632ca5b659SJoost Mulders 27642ca5b659SJoost Mulders /* 27652ca5b659SJoost Mulders * Did we negotiate pause? 27662ca5b659SJoost Mulders */ 2767bdb9230aSGarrett D'Amore if ((mask & MII_ABILITY_PAUSE) != 0 && 27682ca5b659SJoost Mulders vrp->chip.link.duplex == VR_LINK_DUPLEX_FULL) 27692ca5b659SJoost Mulders vrp->chip.link.flowctrl = VR_PAUSE_BIDIRECTIONAL; 27702ca5b659SJoost Mulders else 27712ca5b659SJoost Mulders vrp->chip.link.flowctrl = VR_PAUSE_NONE; 27722ca5b659SJoost Mulders 27732ca5b659SJoost Mulders /* 27742ca5b659SJoost Mulders * Did either one detect a AN fault? 27752ca5b659SJoost Mulders */ 27762ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0) 27772ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 27782ca5b659SJoost Mulders "AN remote fault reported by LP."); 27792ca5b659SJoost Mulders 27802ca5b659SJoost Mulders if ((vrp->chip.mii.lpable & MII_AN_ADVERT_REMFAULT) != 0) 27812ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "AN remote fault caused for LP."); 27822ca5b659SJoost Mulders } else { 27832ca5b659SJoost Mulders /* 27842ca5b659SJoost Mulders * We didn't autoneg 27852ca5b659SJoost Mulders * The link type is defined by the control register. 27862ca5b659SJoost Mulders */ 27872ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_100MB) != 0) { 27882ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_100MBS; 27892ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_100X; 27902ca5b659SJoost Mulders } else { 27912ca5b659SJoost Mulders vrp->chip.link.speed = VR_LINK_SPEED_10MBS; 27922ca5b659SJoost Mulders vrp->chip.link.mau = VR_MAU_10; 27932ca5b659SJoost Mulders } 27942ca5b659SJoost Mulders 27952ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_FDUPLEX) != 0) 27962ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL; 27972ca5b659SJoost Mulders else { 27982ca5b659SJoost Mulders vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF; 27992ca5b659SJoost Mulders /* 28002ca5b659SJoost Mulders * No pause on HDX links. 28012ca5b659SJoost Mulders */ 28022ca5b659SJoost Mulders vrp->chip.link.flowctrl = VR_PAUSE_NONE; 28032ca5b659SJoost Mulders } 28042ca5b659SJoost Mulders } 28052ca5b659SJoost Mulders 28062ca5b659SJoost Mulders /* 28072ca5b659SJoost Mulders * Set the duplex mode on the MAC according to that of the PHY. 28082ca5b659SJoost Mulders */ 28092ca5b659SJoost Mulders if (vrp->chip.link.duplex == VR_LINK_DUPLEX_FULL) { 28102ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_MACFULLDUPLEX); 28112ca5b659SJoost Mulders /* 28122ca5b659SJoost Mulders * Enable packet queueing on FDX links. 28132ca5b659SJoost Mulders */ 28142ca5b659SJoost Mulders if ((vrp->chip.info.bugs & VR_BUG_NO_TXQUEUEING) == 0) 28152ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_QPKTDIS); 28162ca5b659SJoost Mulders } else { 28172ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_MACFULLDUPLEX); 28182ca5b659SJoost Mulders /* 28192ca5b659SJoost Mulders * Disable packet queueing on HDX links. With queueing enabled, 28202ca5b659SJoost Mulders * this MAC get's lost after a TX abort (too many colisions). 28212ca5b659SJoost Mulders */ 28222ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_QPKTDIS); 28232ca5b659SJoost Mulders } 28242ca5b659SJoost Mulders 28252ca5b659SJoost Mulders /* 28262ca5b659SJoost Mulders * Set pause options on the MAC. 28272ca5b659SJoost Mulders */ 28282ca5b659SJoost Mulders if (vrp->chip.link.flowctrl == VR_PAUSE_BIDIRECTIONAL) { 28292ca5b659SJoost Mulders /* 28302ca5b659SJoost Mulders * All of our MAC's can receive pause frames. 28312ca5b659SJoost Mulders */ 28322ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_MISC0, VR_MISC0_FDXRFEN); 28332ca5b659SJoost Mulders 28342ca5b659SJoost Mulders /* 28352ca5b659SJoost Mulders * VT6105 and above can transmit pause frames. 28362ca5b659SJoost Mulders */ 28372ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_TX_PAUSE_CAP) != 0) { 28382ca5b659SJoost Mulders /* 28392ca5b659SJoost Mulders * Set the number of available receive descriptors 28402ca5b659SJoost Mulders * Non-zero values written to this register are added 28412ca5b659SJoost Mulders * to the register's contents. Careful: Writing zero 28422ca5b659SJoost Mulders * clears the register and thus causes a (long) pause 28432ca5b659SJoost Mulders * request. 28442ca5b659SJoost Mulders */ 28452ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_FCR0_RXBUFCOUNT, 28462ca5b659SJoost Mulders MIN(vrp->rx.ndesc, 0xFF) - 28472ca5b659SJoost Mulders VR_GET8(vrp->acc_reg, 28482ca5b659SJoost Mulders VR_FCR0_RXBUFCOUNT)); 28492ca5b659SJoost Mulders 28502ca5b659SJoost Mulders /* 28512ca5b659SJoost Mulders * Request pause when we have 4 descs left. 28522ca5b659SJoost Mulders */ 28532ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_FCR1, 28542ca5b659SJoost Mulders VR_FCR1_PAUSEONBITS, VR_FCR1_PAUSEON_04); 28552ca5b659SJoost Mulders 28562ca5b659SJoost Mulders /* 28572ca5b659SJoost Mulders * Cancel the pause when there are 24 descriptors again. 28582ca5b659SJoost Mulders */ 28592ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_FCR1, 28602ca5b659SJoost Mulders VR_FCR1_PAUSEOFFBITS, VR_FCR1_PAUSEOFF_24); 28612ca5b659SJoost Mulders 28622ca5b659SJoost Mulders /* 28632ca5b659SJoost Mulders * Request a pause of FFFF bit-times. This long pause 28642ca5b659SJoost Mulders * is cancelled when the high watermark is reached. 28652ca5b659SJoost Mulders */ 28662ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_FCR2_PAUSE, 0xFFFF); 28672ca5b659SJoost Mulders 28682ca5b659SJoost Mulders /* 28692ca5b659SJoost Mulders * Enable flow control on the MAC. 28702ca5b659SJoost Mulders */ 28712ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_MISC0, VR_MISC0_FDXTFEN); 28722ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_FCR1, VR_FCR1_FD_RX_EN | 28732ca5b659SJoost Mulders VR_FCR1_FD_TX_EN | VR_FCR1_XONXOFF_EN); 28742ca5b659SJoost Mulders } 28752ca5b659SJoost Mulders } else { 28762ca5b659SJoost Mulders /* 28772ca5b659SJoost Mulders * Turn flow control OFF. 28782ca5b659SJoost Mulders */ 28792ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, 28802ca5b659SJoost Mulders VR_MISC0, VR_MISC0_FDXRFEN | VR_MISC0_FDXTFEN); 28812ca5b659SJoost Mulders if ((vrp->chip.info.features & VR_FEATURE_TX_PAUSE_CAP) != 0) { 28822ca5b659SJoost Mulders VR_CLRBIT8(vrp->acc_reg, VR_FCR1, 28832ca5b659SJoost Mulders VR_FCR1_FD_RX_EN | VR_FCR1_FD_TX_EN | 28842ca5b659SJoost Mulders VR_FCR1_XONXOFF_EN); 28852ca5b659SJoost Mulders } 28862ca5b659SJoost Mulders } 28872ca5b659SJoost Mulders 28882ca5b659SJoost Mulders /* 28892ca5b659SJoost Mulders * Set link state. 28902ca5b659SJoost Mulders */ 28912ca5b659SJoost Mulders if ((vrp->chip.mii.status & MII_STATUS_LINKUP) != 0) 28922ca5b659SJoost Mulders vrp->chip.link.state = VR_LINK_STATE_UP; 28932ca5b659SJoost Mulders else 28942ca5b659SJoost Mulders vrp->chip.link.state = VR_LINK_STATE_DOWN; 28952ca5b659SJoost Mulders } 28962ca5b659SJoost Mulders 28972ca5b659SJoost Mulders /* 28982ca5b659SJoost Mulders * The PHY is automatically polled by the MAC once per 1024 MD clock cycles 28992ca5b659SJoost Mulders * MD is clocked once per 960ns so polling happens about every 1M ns, some 29002ca5b659SJoost Mulders * 1000 times per second 29012ca5b659SJoost Mulders * This polling process is required for the functionality of the link change 29022ca5b659SJoost Mulders * interrupt. Polling process must be disabled in order to access PHY registers 29032ca5b659SJoost Mulders * using MDIO 29042ca5b659SJoost Mulders * 29052ca5b659SJoost Mulders * Turn off PHY polling so that the PHY registers can be accessed. 29062ca5b659SJoost Mulders */ 29072ca5b659SJoost Mulders static void 29082ca5b659SJoost Mulders vr_phy_autopoll_disable(vr_t *vrp) 29092ca5b659SJoost Mulders { 29102ca5b659SJoost Mulders uint32_t time; 29112ca5b659SJoost Mulders uint8_t miicmd, miiaddr; 29122ca5b659SJoost Mulders 29132ca5b659SJoost Mulders /* 29142ca5b659SJoost Mulders * Special procedure to stop the autopolling. 29152ca5b659SJoost Mulders */ 29162ca5b659SJoost Mulders if ((vrp->chip.info.bugs & VR_BUG_MIIPOLLSTOP) != 0) { 29172ca5b659SJoost Mulders /* 29182ca5b659SJoost Mulders * If polling is enabled. 29192ca5b659SJoost Mulders */ 29202ca5b659SJoost Mulders miicmd = VR_GET8(vrp->acc_reg, VR_MIICMD); 29212ca5b659SJoost Mulders if ((miicmd & VR_MIICMD_MD_AUTO) != 0) { 29222ca5b659SJoost Mulders /* 29232ca5b659SJoost Mulders * Wait for the end of a cycle (mdone set). 29242ca5b659SJoost Mulders */ 29252ca5b659SJoost Mulders time = 0; 29262ca5b659SJoost Mulders do { 29272ca5b659SJoost Mulders drv_usecwait(10); 29282ca5b659SJoost Mulders if (time >= VR_MMI_WAITMAX) { 29292ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 29302ca5b659SJoost Mulders "Timeout in " 29312ca5b659SJoost Mulders "disable MII polling"); 29322ca5b659SJoost Mulders break; 29332ca5b659SJoost Mulders } 29342ca5b659SJoost Mulders time += VR_MMI_WAITINCR; 29352ca5b659SJoost Mulders miiaddr = VR_GET8(vrp->acc_reg, VR_MIIADDR); 29362ca5b659SJoost Mulders } while ((miiaddr & VR_MIIADDR_MDONE) == 0); 29372ca5b659SJoost Mulders } 29382ca5b659SJoost Mulders /* 29392ca5b659SJoost Mulders * Once paused, we can disable autopolling. 29402ca5b659SJoost Mulders */ 29412ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MIICMD, 0); 29422ca5b659SJoost Mulders } else { 29432ca5b659SJoost Mulders /* 29442ca5b659SJoost Mulders * Turn off MII polling. 29452ca5b659SJoost Mulders */ 29462ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MIICMD, 0); 29472ca5b659SJoost Mulders 29482ca5b659SJoost Mulders /* 29492ca5b659SJoost Mulders * Wait for MIDLE in MII address register. 29502ca5b659SJoost Mulders */ 29512ca5b659SJoost Mulders time = 0; 29522ca5b659SJoost Mulders do { 29532ca5b659SJoost Mulders drv_usecwait(VR_MMI_WAITINCR); 29542ca5b659SJoost Mulders if (time >= VR_MMI_WAITMAX) { 29552ca5b659SJoost Mulders vr_log(vrp, CE_WARN, 29562ca5b659SJoost Mulders "Timeout in disable MII polling"); 29572ca5b659SJoost Mulders break; 29582ca5b659SJoost Mulders } 29592ca5b659SJoost Mulders time += VR_MMI_WAITINCR; 29602ca5b659SJoost Mulders miiaddr = VR_GET8(vrp->acc_reg, VR_MIIADDR); 29612ca5b659SJoost Mulders } while ((miiaddr & VR_MIIADDR_MIDLE) == 0); 29622ca5b659SJoost Mulders } 29632ca5b659SJoost Mulders } 29642ca5b659SJoost Mulders 29652ca5b659SJoost Mulders /* 29662ca5b659SJoost Mulders * Turn on PHY polling. PHY's registers cannot be accessed. 29672ca5b659SJoost Mulders */ 29682ca5b659SJoost Mulders static void 29692ca5b659SJoost Mulders vr_phy_autopoll_enable(vr_t *vrp) 29702ca5b659SJoost Mulders { 29712ca5b659SJoost Mulders uint32_t time; 29722ca5b659SJoost Mulders 29732ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MIICMD, 0); 29742ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MIIADDR, MII_STATUS|VR_MIIADDR_MAUTO); 29752ca5b659SJoost Mulders VR_PUT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_AUTO); 29762ca5b659SJoost Mulders 29772ca5b659SJoost Mulders /* 29782ca5b659SJoost Mulders * Wait for the polling process to finish. 29792ca5b659SJoost Mulders */ 29802ca5b659SJoost Mulders time = 0; 29812ca5b659SJoost Mulders do { 29822ca5b659SJoost Mulders drv_usecwait(VR_MMI_WAITINCR); 29832ca5b659SJoost Mulders if (time >= VR_MMI_WAITMAX) { 29842ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "Timeout in enable MII polling"); 29852ca5b659SJoost Mulders break; 29862ca5b659SJoost Mulders } 29872ca5b659SJoost Mulders time += VR_MMI_WAITINCR; 29882ca5b659SJoost Mulders } while ((VR_GET8(vrp->acc_reg, VR_MIIADDR) & VR_MIIADDR_MDONE) == 0); 29892ca5b659SJoost Mulders 29902ca5b659SJoost Mulders /* 29912ca5b659SJoost Mulders * Initiate a polling. 29922ca5b659SJoost Mulders */ 29932ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_MAUTO); 29942ca5b659SJoost Mulders } 29952ca5b659SJoost Mulders 29962ca5b659SJoost Mulders /* 29972ca5b659SJoost Mulders * Read a register from the PHY using MDIO. 29982ca5b659SJoost Mulders */ 29992ca5b659SJoost Mulders static void 30002ca5b659SJoost Mulders vr_phy_read(vr_t *vrp, int offset, uint16_t *value) 30012ca5b659SJoost Mulders { 30022ca5b659SJoost Mulders uint32_t time; 30032ca5b659SJoost Mulders 30042ca5b659SJoost Mulders vr_phy_autopoll_disable(vrp); 30052ca5b659SJoost Mulders 30062ca5b659SJoost Mulders /* 30072ca5b659SJoost Mulders * Write the register number to the lower 5 bits of the MII address 30082ca5b659SJoost Mulders * register. 30092ca5b659SJoost Mulders */ 30102ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_BITS, offset); 30112ca5b659SJoost Mulders 30122ca5b659SJoost Mulders /* 30132ca5b659SJoost Mulders * Write a READ command to the MII control register 30142ca5b659SJoost Mulders * This bit will be cleared when the read is finished. 30152ca5b659SJoost Mulders */ 30162ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_READ); 30172ca5b659SJoost Mulders 30182ca5b659SJoost Mulders /* 30192ca5b659SJoost Mulders * Wait until the read is done. 30202ca5b659SJoost Mulders */ 30212ca5b659SJoost Mulders time = 0; 30222ca5b659SJoost Mulders do { 30232ca5b659SJoost Mulders drv_usecwait(VR_MMI_WAITINCR); 30242ca5b659SJoost Mulders if (time >= VR_MMI_WAITMAX) { 30252ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "Timeout in MII read command"); 30262ca5b659SJoost Mulders break; 30272ca5b659SJoost Mulders } 30282ca5b659SJoost Mulders time += VR_MMI_WAITINCR; 30292ca5b659SJoost Mulders } while ((VR_GET8(vrp->acc_reg, VR_MIICMD) & VR_MIICMD_MD_READ) != 0); 30302ca5b659SJoost Mulders 30312ca5b659SJoost Mulders *value = VR_GET16(vrp->acc_reg, VR_MIIDATA); 30322ca5b659SJoost Mulders vr_phy_autopoll_enable(vrp); 30332ca5b659SJoost Mulders } 30342ca5b659SJoost Mulders 30352ca5b659SJoost Mulders /* 30362ca5b659SJoost Mulders * Write to a PHY's register. 30372ca5b659SJoost Mulders */ 30382ca5b659SJoost Mulders static void 30392ca5b659SJoost Mulders vr_phy_write(vr_t *vrp, int offset, uint16_t value) 30402ca5b659SJoost Mulders { 30412ca5b659SJoost Mulders uint32_t time; 30422ca5b659SJoost Mulders 30432ca5b659SJoost Mulders vr_phy_autopoll_disable(vrp); 30442ca5b659SJoost Mulders 30452ca5b659SJoost Mulders /* 30462ca5b659SJoost Mulders * Write the register number to the MII address register. 30472ca5b659SJoost Mulders */ 30482ca5b659SJoost Mulders VR_SETBITS8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_BITS, offset); 30492ca5b659SJoost Mulders 30502ca5b659SJoost Mulders /* 30512ca5b659SJoost Mulders * Write the value to the data register. 30522ca5b659SJoost Mulders */ 30532ca5b659SJoost Mulders VR_PUT16(vrp->acc_reg, VR_MIIDATA, value); 30542ca5b659SJoost Mulders 30552ca5b659SJoost Mulders /* 30562ca5b659SJoost Mulders * Issue the WRITE command to the command register. 30572ca5b659SJoost Mulders * This bit will be cleared when the write is finished. 30582ca5b659SJoost Mulders */ 30592ca5b659SJoost Mulders VR_SETBIT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_WRITE); 30602ca5b659SJoost Mulders 30612ca5b659SJoost Mulders time = 0; 30622ca5b659SJoost Mulders do { 30632ca5b659SJoost Mulders drv_usecwait(VR_MMI_WAITINCR); 30642ca5b659SJoost Mulders if (time >= VR_MMI_WAITMAX) { 30652ca5b659SJoost Mulders vr_log(vrp, CE_NOTE, "Timeout in MII write command"); 30662ca5b659SJoost Mulders break; 30672ca5b659SJoost Mulders } 30682ca5b659SJoost Mulders time += VR_MMI_WAITINCR; 30692ca5b659SJoost Mulders } while ((VR_GET8(vrp->acc_reg, VR_MIICMD) & VR_MIICMD_MD_WRITE) != 0); 30702ca5b659SJoost Mulders vr_phy_autopoll_enable(vrp); 30712ca5b659SJoost Mulders } 30722ca5b659SJoost Mulders 30732ca5b659SJoost Mulders /* 30742ca5b659SJoost Mulders * Initialize and install some private kstats. 30752ca5b659SJoost Mulders */ 30762ca5b659SJoost Mulders typedef struct { 30772ca5b659SJoost Mulders char *name; 30782ca5b659SJoost Mulders uchar_t type; 30792ca5b659SJoost Mulders } vr_kstat_t; 30802ca5b659SJoost Mulders 30812ca5b659SJoost Mulders static const vr_kstat_t vr_driver_stats [] = { 30822ca5b659SJoost Mulders {"allocbfail", KSTAT_DATA_INT32}, 30832ca5b659SJoost Mulders {"intr_claimed", KSTAT_DATA_INT64}, 30842ca5b659SJoost Mulders {"intr_unclaimed", KSTAT_DATA_INT64}, 30852ca5b659SJoost Mulders {"linkchanges", KSTAT_DATA_INT64}, 30862ca5b659SJoost Mulders {"txnfree", KSTAT_DATA_INT32}, 30872ca5b659SJoost Mulders {"txstalls", KSTAT_DATA_INT32}, 30882ca5b659SJoost Mulders {"resets", KSTAT_DATA_INT32}, 30892ca5b659SJoost Mulders {"txreclaims", KSTAT_DATA_INT64}, 30902ca5b659SJoost Mulders {"txreclaim0", KSTAT_DATA_INT64}, 30912ca5b659SJoost Mulders {"cyclics", KSTAT_DATA_INT64}, 30922ca5b659SJoost Mulders {"txchecks", KSTAT_DATA_INT64}, 30932ca5b659SJoost Mulders }; 30942ca5b659SJoost Mulders 30952ca5b659SJoost Mulders static void 30962ca5b659SJoost Mulders vr_kstats_init(vr_t *vrp) 30972ca5b659SJoost Mulders { 30982ca5b659SJoost Mulders kstat_t *ksp; 30992ca5b659SJoost Mulders struct kstat_named *knp; 31002ca5b659SJoost Mulders int i; 31012ca5b659SJoost Mulders int nstats; 31022ca5b659SJoost Mulders 31032ca5b659SJoost Mulders nstats = sizeof (vr_driver_stats) / sizeof (vr_kstat_t); 31042ca5b659SJoost Mulders 31052ca5b659SJoost Mulders ksp = kstat_create(MODULENAME, ddi_get_instance(vrp->devinfo), 31062ca5b659SJoost Mulders "driver", "net", KSTAT_TYPE_NAMED, nstats, 0); 31072ca5b659SJoost Mulders 31082ca5b659SJoost Mulders if (ksp == NULL) 31092ca5b659SJoost Mulders vr_log(vrp, CE_WARN, "kstat_create failed"); 31102ca5b659SJoost Mulders 31112ca5b659SJoost Mulders ksp->ks_update = vr_update_kstats; 31122ca5b659SJoost Mulders ksp->ks_private = (void*) vrp; 31132ca5b659SJoost Mulders knp = ksp->ks_data; 31142ca5b659SJoost Mulders 31152ca5b659SJoost Mulders for (i = 0; i < nstats; i++, knp++) { 31162ca5b659SJoost Mulders kstat_named_init(knp, vr_driver_stats[i].name, 31172ca5b659SJoost Mulders vr_driver_stats[i].type); 31182ca5b659SJoost Mulders } 31192ca5b659SJoost Mulders kstat_install(ksp); 31202ca5b659SJoost Mulders vrp->ksp = ksp; 31212ca5b659SJoost Mulders } 31222ca5b659SJoost Mulders 31232ca5b659SJoost Mulders static int 31242ca5b659SJoost Mulders vr_update_kstats(kstat_t *ksp, int access) 31252ca5b659SJoost Mulders { 31262ca5b659SJoost Mulders vr_t *vrp; 31272ca5b659SJoost Mulders struct kstat_named *knp; 31282ca5b659SJoost Mulders 31292ca5b659SJoost Mulders vrp = (vr_t *)ksp->ks_private; 31302ca5b659SJoost Mulders knp = ksp->ks_data; 31312ca5b659SJoost Mulders 31322ca5b659SJoost Mulders if (access != KSTAT_READ) 31332ca5b659SJoost Mulders return (EACCES); 31342ca5b659SJoost Mulders 31352ca5b659SJoost Mulders (knp++)->value.ui32 = vrp->stats.allocbfail; 31362ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.intr_claimed; 31372ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.intr_unclaimed; 31382ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.linkchanges; 31392ca5b659SJoost Mulders (knp++)->value.ui32 = vrp->tx.nfree; 31402ca5b659SJoost Mulders (knp++)->value.ui32 = vrp->stats.txstalls; 31412ca5b659SJoost Mulders (knp++)->value.ui32 = vrp->stats.resets; 31422ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.txreclaims; 31432ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.txreclaim0; 31442ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.cyclics; 31452ca5b659SJoost Mulders (knp++)->value.ui64 = vrp->stats.txchecks; 31462ca5b659SJoost Mulders return (0); 31472ca5b659SJoost Mulders } 31482ca5b659SJoost Mulders 31492ca5b659SJoost Mulders /* 31502ca5b659SJoost Mulders * Remove 'private' kstats. 31512ca5b659SJoost Mulders */ 31522ca5b659SJoost Mulders static void 31532ca5b659SJoost Mulders vr_remove_kstats(vr_t *vrp) 31542ca5b659SJoost Mulders { 31552ca5b659SJoost Mulders if (vrp->ksp != NULL) 31562ca5b659SJoost Mulders kstat_delete(vrp->ksp); 31572ca5b659SJoost Mulders } 31582ca5b659SJoost Mulders 31592ca5b659SJoost Mulders /* 31602ca5b659SJoost Mulders * Get a property of the device/driver 31612ca5b659SJoost Mulders * Remarks: 31622ca5b659SJoost Mulders * - pr_val is always an integer of size pr_valsize 31632ca5b659SJoost Mulders * - ENABLED (EN) is what is configured via dladm 31642ca5b659SJoost Mulders * - ADVERTISED (ADV) is ENABLED minus constraints, like PHY/MAC capabilities 31652ca5b659SJoost Mulders * - DEFAULT are driver- and hardware defaults (DEFAULT is implemented as a 31662ca5b659SJoost Mulders * flag in pr_flags instead of MAC_PROP_DEFAULT_) 31672ca5b659SJoost Mulders * - perm is the permission printed on ndd -get /.. \? 31682ca5b659SJoost Mulders */ 31692ca5b659SJoost Mulders int 31702ca5b659SJoost Mulders vr_mac_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 31710dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 31722ca5b659SJoost Mulders { 31732ca5b659SJoost Mulders vr_t *vrp; 31742ca5b659SJoost Mulders uint32_t err; 31752ca5b659SJoost Mulders uint64_t val; 31762ca5b659SJoost Mulders 31772ca5b659SJoost Mulders /* Since we have no private properties */ 31782ca5b659SJoost Mulders _NOTE(ARGUNUSED(pr_name)) 31792ca5b659SJoost Mulders 31802ca5b659SJoost Mulders err = 0; 31812ca5b659SJoost Mulders vrp = (vr_t *)arg; 31822ca5b659SJoost Mulders switch (pr_num) { 31832ca5b659SJoost Mulders case MAC_PROP_ADV_1000FDX_CAP: 31842ca5b659SJoost Mulders case MAC_PROP_ADV_1000HDX_CAP: 31850dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP: 31862ca5b659SJoost Mulders case MAC_PROP_EN_1000HDX_CAP: 31872ca5b659SJoost Mulders val = 0; 31882ca5b659SJoost Mulders break; 31892ca5b659SJoost Mulders 31902ca5b659SJoost Mulders case MAC_PROP_ADV_100FDX_CAP: 31912ca5b659SJoost Mulders val = (vrp->chip.mii.anadv & 31922ca5b659SJoost Mulders MII_ABILITY_100BASE_TX_FD) != 0; 31932ca5b659SJoost Mulders break; 31942ca5b659SJoost Mulders 31952ca5b659SJoost Mulders case MAC_PROP_ADV_100HDX_CAP: 31962ca5b659SJoost Mulders val = (vrp->chip.mii.anadv & 31972ca5b659SJoost Mulders MII_ABILITY_100BASE_TX) != 0; 31982ca5b659SJoost Mulders break; 31992ca5b659SJoost Mulders 32002ca5b659SJoost Mulders case MAC_PROP_ADV_100T4_CAP: 32012ca5b659SJoost Mulders val = (vrp->chip.mii.anadv & 32022ca5b659SJoost Mulders MII_ABILITY_100BASE_T4) != 0; 32032ca5b659SJoost Mulders break; 32042ca5b659SJoost Mulders 32052ca5b659SJoost Mulders case MAC_PROP_ADV_10FDX_CAP: 32062ca5b659SJoost Mulders val = (vrp->chip.mii.anadv & 32072ca5b659SJoost Mulders MII_ABILITY_10BASE_T_FD) != 0; 32082ca5b659SJoost Mulders break; 32092ca5b659SJoost Mulders 32102ca5b659SJoost Mulders case MAC_PROP_ADV_10HDX_CAP: 32112ca5b659SJoost Mulders val = (vrp->chip.mii.anadv & 32122ca5b659SJoost Mulders MII_ABILITY_10BASE_T) != 0; 32132ca5b659SJoost Mulders break; 32142ca5b659SJoost Mulders 32152ca5b659SJoost Mulders case MAC_PROP_AUTONEG: 32162ca5b659SJoost Mulders val = (vrp->chip.mii.control & 32172ca5b659SJoost Mulders MII_CONTROL_ANE) != 0; 32182ca5b659SJoost Mulders break; 32192ca5b659SJoost Mulders 32202ca5b659SJoost Mulders case MAC_PROP_DUPLEX: 32212ca5b659SJoost Mulders val = vrp->chip.link.duplex; 32222ca5b659SJoost Mulders break; 32232ca5b659SJoost Mulders 32242ca5b659SJoost Mulders case MAC_PROP_EN_100FDX_CAP: 32252ca5b659SJoost Mulders val = (vrp->param.anadv_en & 32262ca5b659SJoost Mulders MII_ABILITY_100BASE_TX_FD) != 0; 32272ca5b659SJoost Mulders break; 32282ca5b659SJoost Mulders 32292ca5b659SJoost Mulders case MAC_PROP_EN_100HDX_CAP: 32302ca5b659SJoost Mulders val = (vrp->param.anadv_en & 32312ca5b659SJoost Mulders MII_ABILITY_100BASE_TX) != 0; 32322ca5b659SJoost Mulders break; 32332ca5b659SJoost Mulders 32342ca5b659SJoost Mulders case MAC_PROP_EN_100T4_CAP: 32352ca5b659SJoost Mulders val = (vrp->param.anadv_en & 32362ca5b659SJoost Mulders MII_ABILITY_100BASE_T4) != 0; 32372ca5b659SJoost Mulders break; 32382ca5b659SJoost Mulders 32392ca5b659SJoost Mulders case MAC_PROP_EN_10FDX_CAP: 32402ca5b659SJoost Mulders val = (vrp->param.anadv_en & 32412ca5b659SJoost Mulders MII_ABILITY_10BASE_T_FD) != 0; 32422ca5b659SJoost Mulders break; 32432ca5b659SJoost Mulders 32442ca5b659SJoost Mulders case MAC_PROP_EN_10HDX_CAP: 32452ca5b659SJoost Mulders val = (vrp->param.anadv_en & 32462ca5b659SJoost Mulders MII_ABILITY_10BASE_T) != 0; 32472ca5b659SJoost Mulders break; 32482ca5b659SJoost Mulders 32492ca5b659SJoost Mulders case MAC_PROP_EN_AUTONEG: 32502ca5b659SJoost Mulders val = vrp->param.an_en == VR_LINK_AUTONEG_ON; 32512ca5b659SJoost Mulders break; 32522ca5b659SJoost Mulders 32532ca5b659SJoost Mulders case MAC_PROP_FLOWCTRL: 32542ca5b659SJoost Mulders val = vrp->chip.link.flowctrl; 32552ca5b659SJoost Mulders break; 32562ca5b659SJoost Mulders 32572ca5b659SJoost Mulders case MAC_PROP_MTU: 32582ca5b659SJoost Mulders val = vrp->param.mtu; 32592ca5b659SJoost Mulders break; 32602ca5b659SJoost Mulders 32612ca5b659SJoost Mulders case MAC_PROP_SPEED: 32622ca5b659SJoost Mulders if (vrp->chip.link.speed == 32632ca5b659SJoost Mulders VR_LINK_SPEED_100MBS) 32642ca5b659SJoost Mulders val = 100 * 1000 * 1000; 32652ca5b659SJoost Mulders else if (vrp->chip.link.speed == 32662ca5b659SJoost Mulders VR_LINK_SPEED_10MBS) 32672ca5b659SJoost Mulders val = 10 * 1000 * 1000; 32682ca5b659SJoost Mulders else 32692ca5b659SJoost Mulders val = 0; 32702ca5b659SJoost Mulders break; 32712ca5b659SJoost Mulders 32722ca5b659SJoost Mulders case MAC_PROP_STATUS: 32732ca5b659SJoost Mulders val = vrp->chip.link.state; 32742ca5b659SJoost Mulders break; 32752ca5b659SJoost Mulders 32762ca5b659SJoost Mulders default: 32772ca5b659SJoost Mulders err = ENOTSUP; 32782ca5b659SJoost Mulders break; 32792ca5b659SJoost Mulders } 32800dc2366fSVenugopal Iyer 32812ca5b659SJoost Mulders if (err == 0 && pr_num != MAC_PROP_PRIVATE) { 32822ca5b659SJoost Mulders if (pr_valsize == sizeof (uint64_t)) 32832ca5b659SJoost Mulders *(uint64_t *)pr_val = val; 32842ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint32_t)) 32852ca5b659SJoost Mulders *(uint32_t *)pr_val = val; 32862ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint16_t)) 32872ca5b659SJoost Mulders *(uint16_t *)pr_val = val; 32882ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint8_t)) 32892ca5b659SJoost Mulders *(uint8_t *)pr_val = val; 32902ca5b659SJoost Mulders else 32912ca5b659SJoost Mulders err = EINVAL; 32922ca5b659SJoost Mulders } 32932ca5b659SJoost Mulders return (err); 32942ca5b659SJoost Mulders } 32952ca5b659SJoost Mulders 32960dc2366fSVenugopal Iyer void 32970dc2366fSVenugopal Iyer vr_mac_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 32980dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 32990dc2366fSVenugopal Iyer { 33000dc2366fSVenugopal Iyer vr_t *vrp = (vr_t *)arg; 33010dc2366fSVenugopal Iyer uint8_t val, perm; 33020dc2366fSVenugopal Iyer 33030dc2366fSVenugopal Iyer /* Since we have no private properties */ 33040dc2366fSVenugopal Iyer _NOTE(ARGUNUSED(pr_name)) 33050dc2366fSVenugopal Iyer 33060dc2366fSVenugopal Iyer switch (pr_num) { 33070dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP: 33080dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP: 33090dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP: 33100dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP: 33110dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP: 33120dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP: 33130dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP: 33140dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP: 33150dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP: 33160dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 33170dc2366fSVenugopal Iyer return; 33180dc2366fSVenugopal Iyer 33190dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP: 33200dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33210dc2366fSVenugopal Iyer MII_STATUS_100_BASEX_FD) != 0; 33220dc2366fSVenugopal Iyer break; 33230dc2366fSVenugopal Iyer 33240dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP: 33250dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33260dc2366fSVenugopal Iyer MII_STATUS_100_BASEX) != 0; 33270dc2366fSVenugopal Iyer break; 33280dc2366fSVenugopal Iyer 33290dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP: 33300dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33310dc2366fSVenugopal Iyer MII_STATUS_100_BASE_T4) != 0; 33320dc2366fSVenugopal Iyer break; 33330dc2366fSVenugopal Iyer 33340dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP: 33350dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33360dc2366fSVenugopal Iyer MII_STATUS_10_FD) != 0; 33370dc2366fSVenugopal Iyer break; 33380dc2366fSVenugopal Iyer 33390dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP: 33400dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33410dc2366fSVenugopal Iyer MII_STATUS_10) != 0; 33420dc2366fSVenugopal Iyer break; 33430dc2366fSVenugopal Iyer 33440dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG: 33450dc2366fSVenugopal Iyer case MAC_PROP_EN_AUTONEG: 33460dc2366fSVenugopal Iyer val = (vrp->chip.mii.status & 33470dc2366fSVenugopal Iyer MII_STATUS_CANAUTONEG) != 0; 33480dc2366fSVenugopal Iyer break; 33490dc2366fSVenugopal Iyer 33500dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: 33510dc2366fSVenugopal Iyer mac_prop_info_set_default_link_flowctrl(prh, 33520dc2366fSVenugopal Iyer LINK_FLOWCTRL_BI); 33530dc2366fSVenugopal Iyer return; 33540dc2366fSVenugopal Iyer 33550dc2366fSVenugopal Iyer case MAC_PROP_MTU: 33560dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, 33570dc2366fSVenugopal Iyer ETHERMTU, ETHERMTU); 33580dc2366fSVenugopal Iyer return; 33590dc2366fSVenugopal Iyer 33600dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX: 33610dc2366fSVenugopal Iyer /* 33620dc2366fSVenugopal Iyer * Writability depends on autoneg. 33630dc2366fSVenugopal Iyer */ 33640dc2366fSVenugopal Iyer perm = ((vrp->chip.mii.control & 33650dc2366fSVenugopal Iyer MII_CONTROL_ANE) == 0) ? MAC_PROP_PERM_RW : 33660dc2366fSVenugopal Iyer MAC_PROP_PERM_READ; 33670dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, perm); 33680dc2366fSVenugopal Iyer 33690dc2366fSVenugopal Iyer if (perm == MAC_PROP_PERM_RW) { 33700dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 33710dc2366fSVenugopal Iyer VR_LINK_DUPLEX_FULL); 33720dc2366fSVenugopal Iyer } 33730dc2366fSVenugopal Iyer return; 33740dc2366fSVenugopal Iyer 33750dc2366fSVenugopal Iyer case MAC_PROP_SPEED: 33760dc2366fSVenugopal Iyer perm = ((vrp->chip.mii.control & 33770dc2366fSVenugopal Iyer MII_CONTROL_ANE) == 0) ? 33780dc2366fSVenugopal Iyer MAC_PROP_PERM_RW : MAC_PROP_PERM_READ; 33790dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, perm); 33800dc2366fSVenugopal Iyer 33810dc2366fSVenugopal Iyer if (perm == MAC_PROP_PERM_RW) { 33820dc2366fSVenugopal Iyer mac_prop_info_set_default_uint64(prh, 33830dc2366fSVenugopal Iyer 100 * 1000 * 1000); 33840dc2366fSVenugopal Iyer } 33850dc2366fSVenugopal Iyer return; 33860dc2366fSVenugopal Iyer 33870dc2366fSVenugopal Iyer case MAC_PROP_STATUS: 33880dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 33890dc2366fSVenugopal Iyer return; 33900dc2366fSVenugopal Iyer 33910dc2366fSVenugopal Iyer default: 33920dc2366fSVenugopal Iyer return; 33930dc2366fSVenugopal Iyer } 33940dc2366fSVenugopal Iyer 33950dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, val); 33960dc2366fSVenugopal Iyer } 33970dc2366fSVenugopal Iyer 33982ca5b659SJoost Mulders /* 33992ca5b659SJoost Mulders * Set a property of the device. 34002ca5b659SJoost Mulders */ 34012ca5b659SJoost Mulders int 34022ca5b659SJoost Mulders vr_mac_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 34032ca5b659SJoost Mulders uint_t pr_valsize, const void *pr_val) 34042ca5b659SJoost Mulders { 34052ca5b659SJoost Mulders vr_t *vrp; 34062ca5b659SJoost Mulders uint32_t err; 34072ca5b659SJoost Mulders uint64_t val; 34082ca5b659SJoost Mulders 34092ca5b659SJoost Mulders /* Since we have no private properties */ 34102ca5b659SJoost Mulders _NOTE(ARGUNUSED(pr_name)) 34112ca5b659SJoost Mulders 34122ca5b659SJoost Mulders err = 0; 34132ca5b659SJoost Mulders vrp = (vr_t *)arg; 34142ca5b659SJoost Mulders mutex_enter(&vrp->oplock); 34152ca5b659SJoost Mulders 34162ca5b659SJoost Mulders /* 34172ca5b659SJoost Mulders * The current set of public property values are passed as integers 34182ca5b659SJoost Mulders * Private properties are passed as strings in pr_val length pr_valsize. 34192ca5b659SJoost Mulders */ 34202ca5b659SJoost Mulders if (pr_num != MAC_PROP_PRIVATE) { 34212ca5b659SJoost Mulders if (pr_valsize == sizeof (uint64_t)) 34222ca5b659SJoost Mulders val = *(uint64_t *)pr_val; 34232ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint32_t)) 34242ca5b659SJoost Mulders val = *(uint32_t *)pr_val; 34252ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint16_t)) 34262ca5b659SJoost Mulders val = *(uint32_t *)pr_val; 34272ca5b659SJoost Mulders else if (pr_valsize == sizeof (uint8_t)) 34282ca5b659SJoost Mulders val = *(uint8_t *)pr_val; 34292ca5b659SJoost Mulders else { 34302ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 34312ca5b659SJoost Mulders return (EINVAL); 34322ca5b659SJoost Mulders } 34332ca5b659SJoost Mulders } 34342ca5b659SJoost Mulders 34352ca5b659SJoost Mulders switch (pr_num) { 34362ca5b659SJoost Mulders case MAC_PROP_DUPLEX: 34372ca5b659SJoost Mulders if ((vrp->chip.mii.control & MII_CONTROL_ANE) == 0) { 34382ca5b659SJoost Mulders if (val == LINK_DUPLEX_FULL) 34392ca5b659SJoost Mulders vrp->chip.mii.control |= 34402ca5b659SJoost Mulders MII_CONTROL_FDUPLEX; 34412ca5b659SJoost Mulders else if (val == LINK_DUPLEX_HALF) 34422ca5b659SJoost Mulders vrp->chip.mii.control &= 34432ca5b659SJoost Mulders ~MII_CONTROL_FDUPLEX; 34442ca5b659SJoost Mulders else 34452ca5b659SJoost Mulders err = EINVAL; 34462ca5b659SJoost Mulders } else 34472ca5b659SJoost Mulders err = EINVAL; 34482ca5b659SJoost Mulders break; 34492ca5b659SJoost Mulders 34502ca5b659SJoost Mulders case MAC_PROP_EN_100FDX_CAP: 34512ca5b659SJoost Mulders if (val == 0) 34522ca5b659SJoost Mulders vrp->param.anadv_en &= 34532ca5b659SJoost Mulders ~MII_ABILITY_100BASE_TX_FD; 34542ca5b659SJoost Mulders else 34552ca5b659SJoost Mulders vrp->param.anadv_en |= 34562ca5b659SJoost Mulders MII_ABILITY_100BASE_TX_FD; 34572ca5b659SJoost Mulders break; 34582ca5b659SJoost Mulders 34592ca5b659SJoost Mulders case MAC_PROP_EN_100HDX_CAP: 34602ca5b659SJoost Mulders if (val == 0) 34612ca5b659SJoost Mulders vrp->param.anadv_en &= 34622ca5b659SJoost Mulders ~MII_ABILITY_100BASE_TX; 34632ca5b659SJoost Mulders else 34642ca5b659SJoost Mulders vrp->param.anadv_en |= 34652ca5b659SJoost Mulders MII_ABILITY_100BASE_TX; 34662ca5b659SJoost Mulders break; 34672ca5b659SJoost Mulders 34682ca5b659SJoost Mulders case MAC_PROP_EN_100T4_CAP: 34692ca5b659SJoost Mulders if (val == 0) 34702ca5b659SJoost Mulders vrp->param.anadv_en &= 34712ca5b659SJoost Mulders ~MII_ABILITY_100BASE_T4; 34722ca5b659SJoost Mulders else 34732ca5b659SJoost Mulders vrp->param.anadv_en |= 34742ca5b659SJoost Mulders MII_ABILITY_100BASE_T4; 34752ca5b659SJoost Mulders break; 34762ca5b659SJoost Mulders 34772ca5b659SJoost Mulders case MAC_PROP_EN_10FDX_CAP: 34782ca5b659SJoost Mulders if (val == 0) 34792ca5b659SJoost Mulders vrp->param.anadv_en &= 34802ca5b659SJoost Mulders ~MII_ABILITY_10BASE_T_FD; 34812ca5b659SJoost Mulders else 34822ca5b659SJoost Mulders vrp->param.anadv_en |= 34832ca5b659SJoost Mulders MII_ABILITY_10BASE_T_FD; 34842ca5b659SJoost Mulders break; 34852ca5b659SJoost Mulders 34862ca5b659SJoost Mulders case MAC_PROP_EN_10HDX_CAP: 34872ca5b659SJoost Mulders if (val == 0) 34882ca5b659SJoost Mulders vrp->param.anadv_en &= 34892ca5b659SJoost Mulders ~MII_ABILITY_10BASE_T; 34902ca5b659SJoost Mulders else 34912ca5b659SJoost Mulders vrp->param.anadv_en |= 34922ca5b659SJoost Mulders MII_ABILITY_10BASE_T; 34932ca5b659SJoost Mulders break; 34942ca5b659SJoost Mulders 34952ca5b659SJoost Mulders case MAC_PROP_AUTONEG: 34962ca5b659SJoost Mulders case MAC_PROP_EN_AUTONEG: 34972ca5b659SJoost Mulders if (val == 0) { 34982ca5b659SJoost Mulders vrp->param.an_en = VR_LINK_AUTONEG_OFF; 34992ca5b659SJoost Mulders vrp->chip.mii.control &= ~MII_CONTROL_ANE; 35002ca5b659SJoost Mulders } else { 35012ca5b659SJoost Mulders vrp->param.an_en = VR_LINK_AUTONEG_ON; 35022ca5b659SJoost Mulders if ((vrp->chip.mii.status & 35032ca5b659SJoost Mulders MII_STATUS_CANAUTONEG) != 0) 35042ca5b659SJoost Mulders vrp->chip.mii.control |= 35052ca5b659SJoost Mulders MII_CONTROL_ANE; 35062ca5b659SJoost Mulders else 35072ca5b659SJoost Mulders err = EINVAL; 35082ca5b659SJoost Mulders } 35092ca5b659SJoost Mulders break; 35102ca5b659SJoost Mulders 35112ca5b659SJoost Mulders case MAC_PROP_FLOWCTRL: 35122ca5b659SJoost Mulders if (val == LINK_FLOWCTRL_NONE) 3513bdb9230aSGarrett D'Amore vrp->param.anadv_en &= ~MII_ABILITY_PAUSE; 35142ca5b659SJoost Mulders else if (val == LINK_FLOWCTRL_BI) 3515bdb9230aSGarrett D'Amore vrp->param.anadv_en |= MII_ABILITY_PAUSE; 35162ca5b659SJoost Mulders else 35172ca5b659SJoost Mulders err = EINVAL; 35182ca5b659SJoost Mulders break; 35192ca5b659SJoost Mulders 35202ca5b659SJoost Mulders case MAC_PROP_MTU: 35212ca5b659SJoost Mulders if (val >= ETHERMIN && val <= ETHERMTU) 35222ca5b659SJoost Mulders vrp->param.mtu = (uint32_t)val; 35232ca5b659SJoost Mulders else 35242ca5b659SJoost Mulders err = EINVAL; 35252ca5b659SJoost Mulders break; 35262ca5b659SJoost Mulders 35272ca5b659SJoost Mulders case MAC_PROP_SPEED: 35282ca5b659SJoost Mulders if (val == 10 * 1000 * 1000) 35292ca5b659SJoost Mulders vrp->chip.link.speed = 35302ca5b659SJoost Mulders VR_LINK_SPEED_10MBS; 35312ca5b659SJoost Mulders else if (val == 100 * 1000 * 1000) 35322ca5b659SJoost Mulders vrp->chip.link.speed = 35332ca5b659SJoost Mulders VR_LINK_SPEED_100MBS; 35342ca5b659SJoost Mulders else 35352ca5b659SJoost Mulders err = EINVAL; 35362ca5b659SJoost Mulders break; 35372ca5b659SJoost Mulders 35382ca5b659SJoost Mulders default: 35392ca5b659SJoost Mulders err = ENOTSUP; 35402ca5b659SJoost Mulders break; 35412ca5b659SJoost Mulders } 35422ca5b659SJoost Mulders if (err == 0 && pr_num != MAC_PROP_PRIVATE) { 35432ca5b659SJoost Mulders vrp->chip.mii.anadv = vrp->param.anadv_en & 35442ca5b659SJoost Mulders (vrp->param.an_phymask & vrp->param.an_macmask); 35452ca5b659SJoost Mulders vr_link_init(vrp); 35462ca5b659SJoost Mulders } 35472ca5b659SJoost Mulders mutex_exit(&vrp->oplock); 35482ca5b659SJoost Mulders return (err); 35492ca5b659SJoost Mulders } 35502ca5b659SJoost Mulders 35512ca5b659SJoost Mulders 35522ca5b659SJoost Mulders /* 35532ca5b659SJoost Mulders * Logging and debug functions. 35542ca5b659SJoost Mulders */ 35552ca5b659SJoost Mulders static struct { 35562ca5b659SJoost Mulders kmutex_t mutex[1]; 35572ca5b659SJoost Mulders const char *ifname; 35582ca5b659SJoost Mulders const char *fmt; 35592ca5b659SJoost Mulders int level; 35602ca5b659SJoost Mulders } prtdata; 35612ca5b659SJoost Mulders 35622ca5b659SJoost Mulders static void 35632ca5b659SJoost Mulders vr_vprt(const char *fmt, va_list args) 35642ca5b659SJoost Mulders { 35652ca5b659SJoost Mulders char buf[512]; 35662ca5b659SJoost Mulders 35672ca5b659SJoost Mulders ASSERT(mutex_owned(prtdata.mutex)); 35682ca5b659SJoost Mulders (void) vsnprintf(buf, sizeof (buf), fmt, args); 35692ca5b659SJoost Mulders cmn_err(prtdata.level, prtdata.fmt, prtdata.ifname, buf); 35702ca5b659SJoost Mulders } 35712ca5b659SJoost Mulders 35722ca5b659SJoost Mulders static void 35732ca5b659SJoost Mulders vr_log(vr_t *vrp, int level, const char *fmt, ...) 35742ca5b659SJoost Mulders { 35752ca5b659SJoost Mulders va_list args; 35762ca5b659SJoost Mulders 35772ca5b659SJoost Mulders mutex_enter(prtdata.mutex); 35782ca5b659SJoost Mulders prtdata.ifname = vrp->ifname; 35792ca5b659SJoost Mulders prtdata.fmt = "!%s: %s"; 35802ca5b659SJoost Mulders prtdata.level = level; 35812ca5b659SJoost Mulders 35822ca5b659SJoost Mulders va_start(args, fmt); 35832ca5b659SJoost Mulders vr_vprt(fmt, args); 35842ca5b659SJoost Mulders va_end(args); 35852ca5b659SJoost Mulders 35862ca5b659SJoost Mulders mutex_exit(prtdata.mutex); 35872ca5b659SJoost Mulders } 35882ca5b659SJoost Mulders 35892ca5b659SJoost Mulders #if defined(DEBUG) 35902ca5b659SJoost Mulders static void 35912ca5b659SJoost Mulders vr_prt(const char *fmt, ...) 35922ca5b659SJoost Mulders { 35932ca5b659SJoost Mulders va_list args; 35942ca5b659SJoost Mulders 35952ca5b659SJoost Mulders ASSERT(mutex_owned(prtdata.mutex)); 35962ca5b659SJoost Mulders 35972ca5b659SJoost Mulders va_start(args, fmt); 35982ca5b659SJoost Mulders vr_vprt(fmt, args); 35992ca5b659SJoost Mulders va_end(args); 36002ca5b659SJoost Mulders 36012ca5b659SJoost Mulders mutex_exit(prtdata.mutex); 36022ca5b659SJoost Mulders } 36032ca5b659SJoost Mulders 36042ca5b659SJoost Mulders void 36052ca5b659SJoost Mulders (*vr_debug())(const char *fmt, ...) 36062ca5b659SJoost Mulders { 36072ca5b659SJoost Mulders mutex_enter(prtdata.mutex); 36082ca5b659SJoost Mulders prtdata.ifname = MODULENAME; 36092ca5b659SJoost Mulders prtdata.fmt = "^%s: %s\n"; 36102ca5b659SJoost Mulders prtdata.level = CE_CONT; 36112ca5b659SJoost Mulders 36122ca5b659SJoost Mulders return (vr_prt); 36132ca5b659SJoost Mulders } 36142ca5b659SJoost Mulders #endif /* DEBUG */ 36152ca5b659SJoost Mulders 36162ca5b659SJoost Mulders DDI_DEFINE_STREAM_OPS(vr_dev_ops, nulldev, nulldev, vr_attach, vr_detach, 36172ca5b659SJoost Mulders nodev, NULL, D_MP, NULL, vr_quiesce); 36182ca5b659SJoost Mulders 36192ca5b659SJoost Mulders static struct modldrv vr_modldrv = { 36202ca5b659SJoost Mulders &mod_driverops, /* Type of module. This one is a driver */ 36212ca5b659SJoost Mulders vr_ident, /* short description */ 36222ca5b659SJoost Mulders &vr_dev_ops /* driver specific ops */ 36232ca5b659SJoost Mulders }; 36242ca5b659SJoost Mulders 36252ca5b659SJoost Mulders static struct modlinkage modlinkage = { 36262ca5b659SJoost Mulders MODREV_1, (void *)&vr_modldrv, NULL 36272ca5b659SJoost Mulders }; 36282ca5b659SJoost Mulders 36292ca5b659SJoost Mulders int 36302ca5b659SJoost Mulders _info(struct modinfo *modinfop) 36312ca5b659SJoost Mulders { 36322ca5b659SJoost Mulders return (mod_info(&modlinkage, modinfop)); 36332ca5b659SJoost Mulders } 36342ca5b659SJoost Mulders 36352ca5b659SJoost Mulders int 36362ca5b659SJoost Mulders _init(void) 36372ca5b659SJoost Mulders { 36382ca5b659SJoost Mulders int status; 36392ca5b659SJoost Mulders 36402ca5b659SJoost Mulders mac_init_ops(&vr_dev_ops, MODULENAME); 36412ca5b659SJoost Mulders status = mod_install(&modlinkage); 36422ca5b659SJoost Mulders if (status == DDI_SUCCESS) 36432ca5b659SJoost Mulders mutex_init(prtdata.mutex, NULL, MUTEX_DRIVER, NULL); 36442ca5b659SJoost Mulders else 36452ca5b659SJoost Mulders mac_fini_ops(&vr_dev_ops); 36462ca5b659SJoost Mulders return (status); 36472ca5b659SJoost Mulders } 36482ca5b659SJoost Mulders 36492ca5b659SJoost Mulders int 36502ca5b659SJoost Mulders _fini(void) 36512ca5b659SJoost Mulders { 36522ca5b659SJoost Mulders int status; 36532ca5b659SJoost Mulders 36542ca5b659SJoost Mulders status = mod_remove(&modlinkage); 36552ca5b659SJoost Mulders if (status == 0) { 36562ca5b659SJoost Mulders mac_fini_ops(&vr_dev_ops); 36572ca5b659SJoost Mulders mutex_destroy(prtdata.mutex); 36582ca5b659SJoost Mulders } 36592ca5b659SJoost Mulders return (status); 36602ca5b659SJoost Mulders } 3661