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
vr_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)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
vr_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)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
vr_quiesce(dev_info_t * dev_info)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
vr_add_intr(vr_t * vrp)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
vr_remove_intr(vr_t * vrp)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
vr_resume(dev_info_t * devinfo)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
vr_suspend(dev_info_t * devinfo)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
vr_bus_config(vr_t * vrp)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
vr_bus_unconfig(vr_t * vrp)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
vr_param_init(vr_t * vrp)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
vr_rings_init(vr_t * vrp)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
vr_rings_fini(vr_t * vrp)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
vr_alloc_ring(vr_t * vrp,vr_ring_t * ring,size_t n)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
vr_free_ring(vr_ring_t * r,size_t n)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
vr_rxring_init(vr_t * vrp)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
vr_rxring_fini(vr_t * vrp)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
vr_txring_init(vr_t * vrp)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
vr_txring_fini(vr_t * vrp)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
vr_alloc_dmabuf(vr_t * vrp,vr_data_dma_t * dmap,uint_t dmaflags)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
vr_free_dmabuf(vr_data_dma_t * dmap)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
vr_intr(caddr_t arg1,caddr_t arg2)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
vr_error(vr_t * vrp)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 *
vr_receive(vr_t * vrp)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 *
vr_mac_tx_enqueue_list(void * p,mblk_t * mp)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
vr_tx_enqueue_msg(vr_t * vrp,mblk_t * mp)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
vr_tx_reclaim(vr_t * vrp)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
vr_periodic(void * p)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
vr_reset(vr_t * vrp)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
vr_start(vr_t * vrp)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
vr_stop(vr_t * vrp)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
vr_mac_start(void * p)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
vr_mac_stop(void * p)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
vr_mac_set_multicast(void * p,boolean_t add,const uint8_t * mca)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
ether_crc_be(const uint8_t * data)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
vr_cam_index(vr_t * vrp,const uint8_t * maddr)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
vr_mac_set_promisc(void * p,boolean_t promiscflag)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
vr_mac_getstat(void * arg,uint_t stat,uint64_t * val)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
vr_mac_set_ether_addr(void * p,const uint8_t * ea)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
vr_link_init(vr_t * vrp)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
vr_link_state(vr_t * vrp)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
vr_phy_autopoll_disable(vr_t * vrp)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
vr_phy_autopoll_enable(vr_t * vrp)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
vr_phy_read(vr_t * vrp,int offset,uint16_t * value)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
vr_phy_write(vr_t * vrp,int offset,uint16_t value)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
vr_kstats_init(vr_t * vrp)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
vr_update_kstats(kstat_t * ksp,int access)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
vr_remove_kstats(vr_t * vrp)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
vr_mac_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)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
vr_mac_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)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
vr_mac_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)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
vr_vprt(const char * fmt,va_list args)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
vr_log(vr_t * vrp,int level,const char * fmt,...)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
vr_prt(const char * fmt,...)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
vr_debug()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
_info(struct modinfo * modinfop)36302ca5b659SJoost Mulders _info(struct modinfo *modinfop)
36312ca5b659SJoost Mulders {
36322ca5b659SJoost Mulders return (mod_info(&modlinkage, modinfop));
36332ca5b659SJoost Mulders }
36342ca5b659SJoost Mulders
36352ca5b659SJoost Mulders int
_init(void)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
_fini(void)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