19540SJoost.Mulders@Sun.COM /*
29540SJoost.Mulders@Sun.COM * CDDL HEADER START
39540SJoost.Mulders@Sun.COM *
49540SJoost.Mulders@Sun.COM * The contents of this file are subject to the terms of the
59540SJoost.Mulders@Sun.COM * Common Development and Distribution License (the "License").
69540SJoost.Mulders@Sun.COM * You may not use this file except in compliance with the License.
79540SJoost.Mulders@Sun.COM *
89540SJoost.Mulders@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99540SJoost.Mulders@Sun.COM * or http://www.opensolaris.org/os/licensing.
109540SJoost.Mulders@Sun.COM * See the License for the specific language governing permissions
119540SJoost.Mulders@Sun.COM * and limitations under the License.
129540SJoost.Mulders@Sun.COM *
139540SJoost.Mulders@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149540SJoost.Mulders@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159540SJoost.Mulders@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169540SJoost.Mulders@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179540SJoost.Mulders@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189540SJoost.Mulders@Sun.COM *
199540SJoost.Mulders@Sun.COM * CDDL HEADER END
209540SJoost.Mulders@Sun.COM */
219540SJoost.Mulders@Sun.COM
229540SJoost.Mulders@Sun.COM /*
2311878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
249540SJoost.Mulders@Sun.COM * Use is subject to license terms.
259540SJoost.Mulders@Sun.COM */
269540SJoost.Mulders@Sun.COM
279540SJoost.Mulders@Sun.COM #include <sys/types.h>
289540SJoost.Mulders@Sun.COM #include <sys/stream.h>
299540SJoost.Mulders@Sun.COM #include <sys/strsun.h>
309540SJoost.Mulders@Sun.COM #include <sys/stat.h>
319540SJoost.Mulders@Sun.COM #include <sys/pci.h>
329540SJoost.Mulders@Sun.COM #include <sys/modctl.h>
339540SJoost.Mulders@Sun.COM #include <sys/kstat.h>
349540SJoost.Mulders@Sun.COM #include <sys/ethernet.h>
359540SJoost.Mulders@Sun.COM #include <sys/devops.h>
369540SJoost.Mulders@Sun.COM #include <sys/debug.h>
379540SJoost.Mulders@Sun.COM #include <sys/conf.h>
389540SJoost.Mulders@Sun.COM #include <sys/mac.h>
399540SJoost.Mulders@Sun.COM #include <sys/mac_provider.h>
409540SJoost.Mulders@Sun.COM #include <sys/mac_ether.h>
419540SJoost.Mulders@Sun.COM #include <sys/sysmacros.h>
429540SJoost.Mulders@Sun.COM #include <sys/dditypes.h>
439540SJoost.Mulders@Sun.COM #include <sys/ddi.h>
449540SJoost.Mulders@Sun.COM #include <sys/sunddi.h>
459540SJoost.Mulders@Sun.COM #include <sys/miiregs.h>
469540SJoost.Mulders@Sun.COM #include <sys/byteorder.h>
479540SJoost.Mulders@Sun.COM #include <sys/note.h>
489540SJoost.Mulders@Sun.COM #include <sys/vlan.h>
499540SJoost.Mulders@Sun.COM
509540SJoost.Mulders@Sun.COM #include "vr.h"
519540SJoost.Mulders@Sun.COM #include "vr_impl.h"
529540SJoost.Mulders@Sun.COM
539540SJoost.Mulders@Sun.COM /*
549540SJoost.Mulders@Sun.COM * VR in a nutshell
559540SJoost.Mulders@Sun.COM * The card uses two rings of data structures to communicate with the host.
569540SJoost.Mulders@Sun.COM * These are referred to as "descriptor rings" and there is one for transmit
579540SJoost.Mulders@Sun.COM * (TX) and one for receive (RX).
589540SJoost.Mulders@Sun.COM *
599540SJoost.Mulders@Sun.COM * The driver uses a "DMA buffer" data type for mapping to those descriptor
609540SJoost.Mulders@Sun.COM * rings. This is a structure with handles and a DMA'able buffer attached to it.
619540SJoost.Mulders@Sun.COM *
629540SJoost.Mulders@Sun.COM * Receive
639540SJoost.Mulders@Sun.COM * The receive ring is filled with DMA buffers. Received packets are copied into
649540SJoost.Mulders@Sun.COM * a newly allocated mblk's and passed upstream.
659540SJoost.Mulders@Sun.COM *
669540SJoost.Mulders@Sun.COM * Transmit
679540SJoost.Mulders@Sun.COM * Each transmit descriptor has a DMA buffer attached to it. The data of TX
689540SJoost.Mulders@Sun.COM * packets is copied into the DMA buffer which is then enqueued for
699540SJoost.Mulders@Sun.COM * transmission.
709540SJoost.Mulders@Sun.COM *
719540SJoost.Mulders@Sun.COM * Reclaim of transmitted packets is done as a result of a transmit completion
729540SJoost.Mulders@Sun.COM * interrupt which is generated 3 times per ring at minimum.
739540SJoost.Mulders@Sun.COM */
749540SJoost.Mulders@Sun.COM
759540SJoost.Mulders@Sun.COM #if defined(DEBUG)
769540SJoost.Mulders@Sun.COM uint32_t vrdebug = 1;
779540SJoost.Mulders@Sun.COM #define VR_DEBUG(args) do { \
789540SJoost.Mulders@Sun.COM if (vrdebug > 0) \
799540SJoost.Mulders@Sun.COM (*vr_debug()) args; \
809540SJoost.Mulders@Sun.COM _NOTE(CONSTANTCONDITION) \
819540SJoost.Mulders@Sun.COM } while (0)
829540SJoost.Mulders@Sun.COM static void vr_prt(const char *fmt, ...);
839540SJoost.Mulders@Sun.COM void (*vr_debug())(const char *fmt, ...);
849540SJoost.Mulders@Sun.COM #else
859540SJoost.Mulders@Sun.COM #define VR_DEBUG(args) do ; _NOTE(CONSTANTCONDITION) while (0)
869540SJoost.Mulders@Sun.COM #endif
879540SJoost.Mulders@Sun.COM
88*12174Sjoostmnl@gmail.com static char vr_ident[] = "VIA Rhine Ethernet";
899540SJoost.Mulders@Sun.COM
909540SJoost.Mulders@Sun.COM /*
919540SJoost.Mulders@Sun.COM * Attributes for accessing registers and memory descriptors for this device.
929540SJoost.Mulders@Sun.COM */
939540SJoost.Mulders@Sun.COM static ddi_device_acc_attr_t vr_dev_dma_accattr = {
949540SJoost.Mulders@Sun.COM DDI_DEVICE_ATTR_V0,
959540SJoost.Mulders@Sun.COM DDI_STRUCTURE_LE_ACC,
969540SJoost.Mulders@Sun.COM DDI_STRICTORDER_ACC
979540SJoost.Mulders@Sun.COM };
989540SJoost.Mulders@Sun.COM
999540SJoost.Mulders@Sun.COM /*
1009540SJoost.Mulders@Sun.COM * Attributes for accessing data.
1019540SJoost.Mulders@Sun.COM */
1029540SJoost.Mulders@Sun.COM static ddi_device_acc_attr_t vr_data_dma_accattr = {
1039540SJoost.Mulders@Sun.COM DDI_DEVICE_ATTR_V0,
1049540SJoost.Mulders@Sun.COM DDI_NEVERSWAP_ACC,
1059540SJoost.Mulders@Sun.COM DDI_STRICTORDER_ACC
1069540SJoost.Mulders@Sun.COM };
1079540SJoost.Mulders@Sun.COM
1089540SJoost.Mulders@Sun.COM /*
1099540SJoost.Mulders@Sun.COM * DMA attributes for descriptors for communication with the device
1109540SJoost.Mulders@Sun.COM * This driver assumes that all descriptors of one ring fit in one consequitive
1119540SJoost.Mulders@Sun.COM * memory area of max 4K (256 descriptors) that does not cross a page boundary.
1129540SJoost.Mulders@Sun.COM * Therefore, we request 4K alignement.
1139540SJoost.Mulders@Sun.COM */
1149540SJoost.Mulders@Sun.COM static ddi_dma_attr_t vr_dev_dma_attr = {
1159540SJoost.Mulders@Sun.COM DMA_ATTR_V0, /* version number */
1169540SJoost.Mulders@Sun.COM 0, /* low DMA address range */
1179540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* high DMA address range */
1189540SJoost.Mulders@Sun.COM 0x7FFFFFFF, /* DMA counter register */
1199540SJoost.Mulders@Sun.COM 0x1000, /* DMA address alignment */
1209540SJoost.Mulders@Sun.COM 0x7F, /* DMA burstsizes */
1219540SJoost.Mulders@Sun.COM 1, /* min effective DMA size */
1229540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* max DMA xfer size */
1239540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* segment boundary */
1249540SJoost.Mulders@Sun.COM 1, /* s/g list length */
1259540SJoost.Mulders@Sun.COM 1, /* granularity of device */
1269540SJoost.Mulders@Sun.COM 0 /* DMA transfer flags */
1279540SJoost.Mulders@Sun.COM };
1289540SJoost.Mulders@Sun.COM
1299540SJoost.Mulders@Sun.COM /*
1309540SJoost.Mulders@Sun.COM * DMA attributes for the data moved to/from the device
1319540SJoost.Mulders@Sun.COM * Note that the alignement is set to 2K so hat a 1500 byte packet never
1329540SJoost.Mulders@Sun.COM * crosses a page boundary and thus that a DMA transfer is not split up in
1339540SJoost.Mulders@Sun.COM * multiple cookies with a 4K/8K pagesize
1349540SJoost.Mulders@Sun.COM */
1359540SJoost.Mulders@Sun.COM static ddi_dma_attr_t vr_data_dma_attr = {
1369540SJoost.Mulders@Sun.COM DMA_ATTR_V0, /* version number */
1379540SJoost.Mulders@Sun.COM 0, /* low DMA address range */
1389540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* high DMA address range */
1399540SJoost.Mulders@Sun.COM 0x7FFFFFFF, /* DMA counter register */
1409540SJoost.Mulders@Sun.COM 0x800, /* DMA address alignment */
1419540SJoost.Mulders@Sun.COM 0xfff, /* DMA burstsizes */
1429540SJoost.Mulders@Sun.COM 1, /* min effective DMA size */
1439540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* max DMA xfer size */
1449540SJoost.Mulders@Sun.COM 0xFFFFFFFF, /* segment boundary */
1459540SJoost.Mulders@Sun.COM 1, /* s/g list length */
1469540SJoost.Mulders@Sun.COM 1, /* granularity of device */
1479540SJoost.Mulders@Sun.COM 0 /* DMA transfer flags */
1489540SJoost.Mulders@Sun.COM };
1499540SJoost.Mulders@Sun.COM
1509540SJoost.Mulders@Sun.COM static mac_callbacks_t vr_mac_callbacks = {
15111878SVenu.Iyer@Sun.COM MC_SETPROP|MC_GETPROP|MC_PROPINFO, /* Which callbacks are set */
1529540SJoost.Mulders@Sun.COM vr_mac_getstat, /* Get the value of a statistic */
1539540SJoost.Mulders@Sun.COM vr_mac_start, /* Start the device */
1549540SJoost.Mulders@Sun.COM vr_mac_stop, /* Stop the device */
1559540SJoost.Mulders@Sun.COM vr_mac_set_promisc, /* Enable or disable promiscuous mode */
1569540SJoost.Mulders@Sun.COM vr_mac_set_multicast, /* Enable or disable a multicast addr */
1579540SJoost.Mulders@Sun.COM vr_mac_set_ether_addr, /* Set the unicast MAC address */
1589540SJoost.Mulders@Sun.COM vr_mac_tx_enqueue_list, /* Transmit a packet */
15911878SVenu.Iyer@Sun.COM NULL,
1609540SJoost.Mulders@Sun.COM NULL, /* Process an unknown ioctl */
1619540SJoost.Mulders@Sun.COM NULL, /* Get capability information */
1629540SJoost.Mulders@Sun.COM NULL, /* Open the device */
1639540SJoost.Mulders@Sun.COM NULL, /* Close the device */
1649540SJoost.Mulders@Sun.COM vr_mac_setprop, /* Set properties of the device */
16511878SVenu.Iyer@Sun.COM vr_mac_getprop, /* Get properties of the device */
16611878SVenu.Iyer@Sun.COM vr_mac_propinfo /* Get properties attributes */
1679540SJoost.Mulders@Sun.COM };
1689540SJoost.Mulders@Sun.COM
1699540SJoost.Mulders@Sun.COM /*
1709540SJoost.Mulders@Sun.COM * Table with bugs and features for each incarnation of the card.
1719540SJoost.Mulders@Sun.COM */
1729540SJoost.Mulders@Sun.COM static const chip_info_t vr_chip_info [] = {
1739540SJoost.Mulders@Sun.COM {
1749540SJoost.Mulders@Sun.COM 0x0, 0x0,
1759540SJoost.Mulders@Sun.COM "VIA Rhine Fast Ethernet",
1769540SJoost.Mulders@Sun.COM (VR_BUG_NO_MEMIO),
1779540SJoost.Mulders@Sun.COM (VR_FEATURE_NONE)
1789540SJoost.Mulders@Sun.COM },
1799540SJoost.Mulders@Sun.COM {
1809540SJoost.Mulders@Sun.COM 0x04, 0x21,
1819540SJoost.Mulders@Sun.COM "VIA VT86C100A Fast Ethernet",
1829540SJoost.Mulders@Sun.COM (VR_BUG_NEEDMODE2PCEROPT | VR_BUG_NO_TXQUEUEING |
1839540SJoost.Mulders@Sun.COM VR_BUG_NEEDMODE10T | VR_BUG_TXALIGN | VR_BUG_NO_MEMIO |
1849540SJoost.Mulders@Sun.COM VR_BUG_MIIPOLLSTOP),
1859540SJoost.Mulders@Sun.COM (VR_FEATURE_NONE)
1869540SJoost.Mulders@Sun.COM },
1879540SJoost.Mulders@Sun.COM {
1889540SJoost.Mulders@Sun.COM 0x40, 0x41,
1899540SJoost.Mulders@Sun.COM "VIA VT6102-A Rhine II Fast Ethernet",
1909540SJoost.Mulders@Sun.COM (VR_BUG_NEEDMODE2PCEROPT),
1919540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP)
1929540SJoost.Mulders@Sun.COM },
1939540SJoost.Mulders@Sun.COM {
1949540SJoost.Mulders@Sun.COM 0x42, 0x7f,
1959540SJoost.Mulders@Sun.COM "VIA VT6102-C Rhine II Fast Ethernet",
1969540SJoost.Mulders@Sun.COM (VR_BUG_NEEDMODE2PCEROPT),
1979540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP)
1989540SJoost.Mulders@Sun.COM },
1999540SJoost.Mulders@Sun.COM {
2009540SJoost.Mulders@Sun.COM 0x80, 0x82,
2019540SJoost.Mulders@Sun.COM "VIA VT6105-A Rhine III Fast Ethernet",
2029540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2039540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP)
2049540SJoost.Mulders@Sun.COM },
2059540SJoost.Mulders@Sun.COM {
2069540SJoost.Mulders@Sun.COM 0x83, 0x89,
2079540SJoost.Mulders@Sun.COM "VIA VT6105-B Rhine III Fast Ethernet",
2089540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2099540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP)
2109540SJoost.Mulders@Sun.COM },
2119540SJoost.Mulders@Sun.COM {
2129540SJoost.Mulders@Sun.COM 0x8a, 0x8b,
2139540SJoost.Mulders@Sun.COM "VIA VT6105-LOM Rhine III Fast Ethernet",
2149540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2159540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP)
2169540SJoost.Mulders@Sun.COM },
2179540SJoost.Mulders@Sun.COM {
2189540SJoost.Mulders@Sun.COM 0x8c, 0x8c,
2199540SJoost.Mulders@Sun.COM "VIA VT6107-A0 Rhine III Fast Ethernet",
2209540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2219540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP)
2229540SJoost.Mulders@Sun.COM },
2239540SJoost.Mulders@Sun.COM {
2249540SJoost.Mulders@Sun.COM 0x8d, 0x8f,
2259540SJoost.Mulders@Sun.COM "VIA VT6107-A1 Rhine III Fast Ethernet",
2269540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2279540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP |
2289540SJoost.Mulders@Sun.COM VR_FEATURE_MRDLNMULTIPLE)
2299540SJoost.Mulders@Sun.COM },
2309540SJoost.Mulders@Sun.COM {
2319540SJoost.Mulders@Sun.COM 0x90, 0x93,
2329540SJoost.Mulders@Sun.COM "VIA VT6105M-A0 Rhine III Fast Ethernet Management Adapter",
2339540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2349540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP |
2359540SJoost.Mulders@Sun.COM VR_FEATURE_TXCHKSUM | VR_FEATURE_RXCHKSUM |
2369540SJoost.Mulders@Sun.COM VR_FEATURE_CAMSUPPORT | VR_FEATURE_VLANTAGGING |
2379540SJoost.Mulders@Sun.COM VR_FEATURE_MIBCOUNTER)
2389540SJoost.Mulders@Sun.COM },
2399540SJoost.Mulders@Sun.COM {
2409540SJoost.Mulders@Sun.COM 0x94, 0xff,
2419540SJoost.Mulders@Sun.COM "VIA VT6105M-B1 Rhine III Fast Ethernet Management Adapter",
2429540SJoost.Mulders@Sun.COM (VR_BUG_NONE),
2439540SJoost.Mulders@Sun.COM (VR_FEATURE_RX_PAUSE_CAP | VR_FEATURE_TX_PAUSE_CAP |
2449540SJoost.Mulders@Sun.COM VR_FEATURE_TXCHKSUM | VR_FEATURE_RXCHKSUM |
2459540SJoost.Mulders@Sun.COM VR_FEATURE_CAMSUPPORT | VR_FEATURE_VLANTAGGING |
2469540SJoost.Mulders@Sun.COM VR_FEATURE_MIBCOUNTER)
2479540SJoost.Mulders@Sun.COM }
2489540SJoost.Mulders@Sun.COM };
2499540SJoost.Mulders@Sun.COM
2509540SJoost.Mulders@Sun.COM /*
2519540SJoost.Mulders@Sun.COM * Function prototypes
2529540SJoost.Mulders@Sun.COM */
2539540SJoost.Mulders@Sun.COM static vr_result_t vr_add_intr(vr_t *vrp);
2549540SJoost.Mulders@Sun.COM static void vr_remove_intr(vr_t *vrp);
2559540SJoost.Mulders@Sun.COM static int32_t vr_cam_index(vr_t *vrp, const uint8_t *maddr);
2569540SJoost.Mulders@Sun.COM static uint32_t ether_crc_be(const uint8_t *address);
2579540SJoost.Mulders@Sun.COM static void vr_tx_enqueue_msg(vr_t *vrp, mblk_t *mp);
2589540SJoost.Mulders@Sun.COM static void vr_log(vr_t *vrp, int level, const char *fmt, ...);
2599540SJoost.Mulders@Sun.COM static int vr_resume(dev_info_t *devinfo);
2609540SJoost.Mulders@Sun.COM static int vr_suspend(dev_info_t *devinfo);
2619540SJoost.Mulders@Sun.COM static vr_result_t vr_bus_config(vr_t *vrp);
2629540SJoost.Mulders@Sun.COM static void vr_bus_unconfig(vr_t *vrp);
2639540SJoost.Mulders@Sun.COM static void vr_reset(vr_t *vrp);
2649540SJoost.Mulders@Sun.COM static int vr_start(vr_t *vrp);
2659540SJoost.Mulders@Sun.COM static int vr_stop(vr_t *vrp);
2669540SJoost.Mulders@Sun.COM static vr_result_t vr_rings_init(vr_t *vrp);
2679540SJoost.Mulders@Sun.COM static void vr_rings_fini(vr_t *vrp);
2689540SJoost.Mulders@Sun.COM static vr_result_t vr_alloc_ring(vr_t *vrp, vr_ring_t *r, size_t n);
2699540SJoost.Mulders@Sun.COM static void vr_free_ring(vr_ring_t *r, size_t n);
2709540SJoost.Mulders@Sun.COM static vr_result_t vr_rxring_init(vr_t *vrp);
2719540SJoost.Mulders@Sun.COM static void vr_rxring_fini(vr_t *vrp);
2729540SJoost.Mulders@Sun.COM static vr_result_t vr_txring_init(vr_t *vrp);
2739540SJoost.Mulders@Sun.COM static void vr_txring_fini(vr_t *vrp);
2749540SJoost.Mulders@Sun.COM static vr_result_t vr_alloc_dmabuf(vr_t *vrp, vr_data_dma_t *dmap,
2759540SJoost.Mulders@Sun.COM uint_t flags);
2769540SJoost.Mulders@Sun.COM static void vr_free_dmabuf(vr_data_dma_t *dmap);
2779540SJoost.Mulders@Sun.COM static void vr_param_init(vr_t *vrp);
2789540SJoost.Mulders@Sun.COM static mblk_t *vr_receive(vr_t *vrp);
2799540SJoost.Mulders@Sun.COM static void vr_tx_reclaim(vr_t *vrp);
2809540SJoost.Mulders@Sun.COM static void vr_periodic(void *p);
2819540SJoost.Mulders@Sun.COM static void vr_error(vr_t *vrp);
2829540SJoost.Mulders@Sun.COM static void vr_phy_read(vr_t *vrp, int offset, uint16_t *value);
2839540SJoost.Mulders@Sun.COM static void vr_phy_write(vr_t *vrp, int offset, uint16_t value);
2849540SJoost.Mulders@Sun.COM static void vr_phy_autopoll_disable(vr_t *vrp);
2859540SJoost.Mulders@Sun.COM static void vr_phy_autopoll_enable(vr_t *vrp);
2869540SJoost.Mulders@Sun.COM static void vr_link_init(vr_t *vrp);
2879540SJoost.Mulders@Sun.COM static void vr_link_state(vr_t *vrp);
2889540SJoost.Mulders@Sun.COM static void vr_kstats_init(vr_t *vrp);
2899540SJoost.Mulders@Sun.COM static int vr_update_kstats(kstat_t *ksp, int access);
2909540SJoost.Mulders@Sun.COM static void vr_remove_kstats(vr_t *vrp);
2919540SJoost.Mulders@Sun.COM
2929540SJoost.Mulders@Sun.COM static int
vr_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)2939540SJoost.Mulders@Sun.COM vr_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
2949540SJoost.Mulders@Sun.COM {
2959540SJoost.Mulders@Sun.COM vr_t *vrp;
2969540SJoost.Mulders@Sun.COM mac_register_t *macreg;
2979540SJoost.Mulders@Sun.COM
2989540SJoost.Mulders@Sun.COM if (cmd == DDI_RESUME)
2999540SJoost.Mulders@Sun.COM return (vr_resume(devinfo));
3009540SJoost.Mulders@Sun.COM else if (cmd != DDI_ATTACH)
3019540SJoost.Mulders@Sun.COM return (DDI_FAILURE);
3029540SJoost.Mulders@Sun.COM
3039540SJoost.Mulders@Sun.COM /*
3049540SJoost.Mulders@Sun.COM * Attach.
3059540SJoost.Mulders@Sun.COM */
3069540SJoost.Mulders@Sun.COM vrp = kmem_zalloc(sizeof (vr_t), KM_SLEEP);
3079540SJoost.Mulders@Sun.COM ddi_set_driver_private(devinfo, vrp);
3089540SJoost.Mulders@Sun.COM vrp->devinfo = devinfo;
3099540SJoost.Mulders@Sun.COM
3109540SJoost.Mulders@Sun.COM /*
3119540SJoost.Mulders@Sun.COM * Store the name+instance of the module.
3129540SJoost.Mulders@Sun.COM */
3139540SJoost.Mulders@Sun.COM (void) snprintf(vrp->ifname, sizeof (vrp->ifname), "%s%d",
3149540SJoost.Mulders@Sun.COM MODULENAME, ddi_get_instance(devinfo));
3159540SJoost.Mulders@Sun.COM
3169540SJoost.Mulders@Sun.COM /*
3179540SJoost.Mulders@Sun.COM * Bus initialization.
3189540SJoost.Mulders@Sun.COM */
3199540SJoost.Mulders@Sun.COM if (vr_bus_config(vrp) != VR_SUCCESS) {
3209540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "vr_bus_config failed");
3219540SJoost.Mulders@Sun.COM goto fail0;
3229540SJoost.Mulders@Sun.COM }
3239540SJoost.Mulders@Sun.COM
3249540SJoost.Mulders@Sun.COM /*
3259540SJoost.Mulders@Sun.COM * Initialize default parameters.
3269540SJoost.Mulders@Sun.COM */
3279540SJoost.Mulders@Sun.COM vr_param_init(vrp);
3289540SJoost.Mulders@Sun.COM
3299540SJoost.Mulders@Sun.COM /*
3309540SJoost.Mulders@Sun.COM * Setup the descriptor rings.
3319540SJoost.Mulders@Sun.COM */
3329540SJoost.Mulders@Sun.COM if (vr_rings_init(vrp) != VR_SUCCESS) {
3339540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "vr_rings_init failed");
3349540SJoost.Mulders@Sun.COM goto fail1;
3359540SJoost.Mulders@Sun.COM }
3369540SJoost.Mulders@Sun.COM
3379540SJoost.Mulders@Sun.COM /*
3389540SJoost.Mulders@Sun.COM * Initialize kstats.
3399540SJoost.Mulders@Sun.COM */
3409540SJoost.Mulders@Sun.COM vr_kstats_init(vrp);
3419540SJoost.Mulders@Sun.COM
3429540SJoost.Mulders@Sun.COM /*
3439540SJoost.Mulders@Sun.COM * Add interrupt to the OS.
3449540SJoost.Mulders@Sun.COM */
3459540SJoost.Mulders@Sun.COM if (vr_add_intr(vrp) != VR_SUCCESS) {
3469540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "vr_add_intr failed in attach");
3479540SJoost.Mulders@Sun.COM goto fail3;
3489540SJoost.Mulders@Sun.COM }
3499540SJoost.Mulders@Sun.COM
3509540SJoost.Mulders@Sun.COM /*
3519540SJoost.Mulders@Sun.COM * Add mutexes.
3529540SJoost.Mulders@Sun.COM */
3539540SJoost.Mulders@Sun.COM mutex_init(&vrp->intrlock, NULL, MUTEX_DRIVER,
3549540SJoost.Mulders@Sun.COM DDI_INTR_PRI(vrp->intr_pri));
3559540SJoost.Mulders@Sun.COM mutex_init(&vrp->oplock, NULL, MUTEX_DRIVER, NULL);
3569540SJoost.Mulders@Sun.COM mutex_init(&vrp->tx.lock, NULL, MUTEX_DRIVER, NULL);
3579540SJoost.Mulders@Sun.COM
3589540SJoost.Mulders@Sun.COM /*
3599540SJoost.Mulders@Sun.COM * Enable interrupt.
3609540SJoost.Mulders@Sun.COM */
3619540SJoost.Mulders@Sun.COM if (ddi_intr_enable(vrp->intr_hdl) != DDI_SUCCESS) {
3629540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_enable failed");
3639540SJoost.Mulders@Sun.COM goto fail5;
3649540SJoost.Mulders@Sun.COM }
3659540SJoost.Mulders@Sun.COM
3669540SJoost.Mulders@Sun.COM /*
3679540SJoost.Mulders@Sun.COM * Register with parent, mac.
3689540SJoost.Mulders@Sun.COM */
3699540SJoost.Mulders@Sun.COM if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
3709540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "mac_alloc failed in attach");
3719540SJoost.Mulders@Sun.COM goto fail6;
3729540SJoost.Mulders@Sun.COM }
3739540SJoost.Mulders@Sun.COM
3749540SJoost.Mulders@Sun.COM macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
3759540SJoost.Mulders@Sun.COM macreg->m_driver = vrp;
3769540SJoost.Mulders@Sun.COM macreg->m_dip = devinfo;
3779540SJoost.Mulders@Sun.COM macreg->m_src_addr = vrp->vendor_ether_addr;
3789540SJoost.Mulders@Sun.COM macreg->m_callbacks = &vr_mac_callbacks;
3799540SJoost.Mulders@Sun.COM macreg->m_min_sdu = 0;
3809540SJoost.Mulders@Sun.COM macreg->m_max_sdu = ETHERMTU;
3819540SJoost.Mulders@Sun.COM macreg->m_margin = VLAN_TAGSZ;
3829540SJoost.Mulders@Sun.COM
3839540SJoost.Mulders@Sun.COM if (mac_register(macreg, &vrp->machdl) != 0) {
3849540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "mac_register failed in attach");
3859540SJoost.Mulders@Sun.COM goto fail7;
3869540SJoost.Mulders@Sun.COM }
3879540SJoost.Mulders@Sun.COM mac_free(macreg);
3889540SJoost.Mulders@Sun.COM return (DDI_SUCCESS);
3899540SJoost.Mulders@Sun.COM
3909540SJoost.Mulders@Sun.COM fail7:
3919540SJoost.Mulders@Sun.COM mac_free(macreg);
3929540SJoost.Mulders@Sun.COM fail6:
3939540SJoost.Mulders@Sun.COM (void) ddi_intr_disable(vrp->intr_hdl);
3949540SJoost.Mulders@Sun.COM fail5:
3959540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->tx.lock);
3969540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->oplock);
3979540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->intrlock);
3989540SJoost.Mulders@Sun.COM vr_remove_intr(vrp);
3999540SJoost.Mulders@Sun.COM fail3:
4009540SJoost.Mulders@Sun.COM vr_remove_kstats(vrp);
4019540SJoost.Mulders@Sun.COM fail2:
4029540SJoost.Mulders@Sun.COM vr_rings_fini(vrp);
4039540SJoost.Mulders@Sun.COM fail1:
4049540SJoost.Mulders@Sun.COM vr_bus_unconfig(vrp);
4059540SJoost.Mulders@Sun.COM fail0:
4069540SJoost.Mulders@Sun.COM kmem_free(vrp, sizeof (vr_t));
4079540SJoost.Mulders@Sun.COM return (DDI_FAILURE);
4089540SJoost.Mulders@Sun.COM }
4099540SJoost.Mulders@Sun.COM
4109540SJoost.Mulders@Sun.COM static int
vr_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)4119540SJoost.Mulders@Sun.COM vr_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
4129540SJoost.Mulders@Sun.COM {
4139540SJoost.Mulders@Sun.COM vr_t *vrp;
4149540SJoost.Mulders@Sun.COM
4159540SJoost.Mulders@Sun.COM vrp = ddi_get_driver_private(devinfo);
4169540SJoost.Mulders@Sun.COM
4179540SJoost.Mulders@Sun.COM if (cmd == DDI_SUSPEND)
4189540SJoost.Mulders@Sun.COM return (vr_suspend(devinfo));
4199540SJoost.Mulders@Sun.COM else if (cmd != DDI_DETACH)
4209540SJoost.Mulders@Sun.COM return (DDI_FAILURE);
4219540SJoost.Mulders@Sun.COM
4229540SJoost.Mulders@Sun.COM if (vrp->chip.state == CHIPSTATE_RUNNING)
4239540SJoost.Mulders@Sun.COM return (DDI_FAILURE);
4249540SJoost.Mulders@Sun.COM
4259540SJoost.Mulders@Sun.COM /*
4269540SJoost.Mulders@Sun.COM * Try to un-register from the MAC layer.
4279540SJoost.Mulders@Sun.COM */
4289540SJoost.Mulders@Sun.COM if (mac_unregister(vrp->machdl) != 0)
4299540SJoost.Mulders@Sun.COM return (DDI_FAILURE);
4309540SJoost.Mulders@Sun.COM
4319540SJoost.Mulders@Sun.COM (void) ddi_intr_disable(vrp->intr_hdl);
4329540SJoost.Mulders@Sun.COM vr_remove_intr(vrp);
4339540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->tx.lock);
4349540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->oplock);
4359540SJoost.Mulders@Sun.COM mutex_destroy(&vrp->intrlock);
4369540SJoost.Mulders@Sun.COM vr_remove_kstats(vrp);
4379540SJoost.Mulders@Sun.COM vr_rings_fini(vrp);
4389540SJoost.Mulders@Sun.COM vr_bus_unconfig(vrp);
4399540SJoost.Mulders@Sun.COM kmem_free(vrp, sizeof (vr_t));
4409540SJoost.Mulders@Sun.COM return (DDI_SUCCESS);
4419540SJoost.Mulders@Sun.COM }
4429540SJoost.Mulders@Sun.COM
4439540SJoost.Mulders@Sun.COM /*
4449540SJoost.Mulders@Sun.COM * quiesce the card for fast reboot.
4459540SJoost.Mulders@Sun.COM */
4469540SJoost.Mulders@Sun.COM int
vr_quiesce(dev_info_t * dev_info)4479540SJoost.Mulders@Sun.COM vr_quiesce(dev_info_t *dev_info)
4489540SJoost.Mulders@Sun.COM {
4499540SJoost.Mulders@Sun.COM vr_t *vrp;
4509540SJoost.Mulders@Sun.COM
4519540SJoost.Mulders@Sun.COM vrp = (vr_t *)ddi_get_driver_private(dev_info);
4529540SJoost.Mulders@Sun.COM
4539540SJoost.Mulders@Sun.COM /*
4549540SJoost.Mulders@Sun.COM * Stop interrupts.
4559540SJoost.Mulders@Sun.COM */
4569540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_ICR0, 0);
4579540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_ICR1, 0);
4589540SJoost.Mulders@Sun.COM
4599540SJoost.Mulders@Sun.COM /*
4609540SJoost.Mulders@Sun.COM * Stop DMA.
4619540SJoost.Mulders@Sun.COM */
4629540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_STOP);
4639540SJoost.Mulders@Sun.COM return (DDI_SUCCESS);
4649540SJoost.Mulders@Sun.COM }
4659540SJoost.Mulders@Sun.COM
4669540SJoost.Mulders@Sun.COM /*
4679540SJoost.Mulders@Sun.COM * Add an interrupt for our device to the OS.
4689540SJoost.Mulders@Sun.COM */
4699540SJoost.Mulders@Sun.COM static vr_result_t
vr_add_intr(vr_t * vrp)4709540SJoost.Mulders@Sun.COM vr_add_intr(vr_t *vrp)
4719540SJoost.Mulders@Sun.COM {
4729540SJoost.Mulders@Sun.COM int nintrs;
4739540SJoost.Mulders@Sun.COM int rc;
4749540SJoost.Mulders@Sun.COM
4759540SJoost.Mulders@Sun.COM rc = ddi_intr_alloc(vrp->devinfo, &vrp->intr_hdl,
4769540SJoost.Mulders@Sun.COM DDI_INTR_TYPE_FIXED, /* type */
4779540SJoost.Mulders@Sun.COM 0, /* number */
4789540SJoost.Mulders@Sun.COM 1, /* count */
4799540SJoost.Mulders@Sun.COM &nintrs, /* actualp */
4809540SJoost.Mulders@Sun.COM DDI_INTR_ALLOC_STRICT);
4819540SJoost.Mulders@Sun.COM
4829540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
4839540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_alloc failed: %d", rc);
4849540SJoost.Mulders@Sun.COM return (VR_FAILURE);
4859540SJoost.Mulders@Sun.COM }
4869540SJoost.Mulders@Sun.COM
4879540SJoost.Mulders@Sun.COM rc = ddi_intr_add_handler(vrp->intr_hdl, vr_intr, vrp, NULL);
4889540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
4899540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_add_handler failed");
4909540SJoost.Mulders@Sun.COM if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS)
4919540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_free failed");
4929540SJoost.Mulders@Sun.COM return (VR_FAILURE);
4939540SJoost.Mulders@Sun.COM }
4949540SJoost.Mulders@Sun.COM
4959540SJoost.Mulders@Sun.COM rc = ddi_intr_get_pri(vrp->intr_hdl, &vrp->intr_pri);
4969540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
4979540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_get_pri failed");
4989540SJoost.Mulders@Sun.COM if (ddi_intr_remove_handler(vrp->intr_hdl) != DDI_SUCCESS)
4999540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_remove_handler failed");
5009540SJoost.Mulders@Sun.COM
5019540SJoost.Mulders@Sun.COM if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS)
5029540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_free failed");
5039540SJoost.Mulders@Sun.COM
5049540SJoost.Mulders@Sun.COM return (VR_FAILURE);
5059540SJoost.Mulders@Sun.COM }
5069540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
5079540SJoost.Mulders@Sun.COM }
5089540SJoost.Mulders@Sun.COM
5099540SJoost.Mulders@Sun.COM /*
5109540SJoost.Mulders@Sun.COM * Remove our interrupt from the OS.
5119540SJoost.Mulders@Sun.COM */
5129540SJoost.Mulders@Sun.COM static void
vr_remove_intr(vr_t * vrp)5139540SJoost.Mulders@Sun.COM vr_remove_intr(vr_t *vrp)
5149540SJoost.Mulders@Sun.COM {
5159540SJoost.Mulders@Sun.COM if (ddi_intr_remove_handler(vrp->intr_hdl) != DDI_SUCCESS)
5169540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_remove_handler failed");
5179540SJoost.Mulders@Sun.COM
5189540SJoost.Mulders@Sun.COM if (ddi_intr_free(vrp->intr_hdl) != DDI_SUCCESS)
5199540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "ddi_intr_free failed");
5209540SJoost.Mulders@Sun.COM }
5219540SJoost.Mulders@Sun.COM
5229540SJoost.Mulders@Sun.COM /*
5239540SJoost.Mulders@Sun.COM * Resume operation after suspend.
5249540SJoost.Mulders@Sun.COM */
5259540SJoost.Mulders@Sun.COM static int
vr_resume(dev_info_t * devinfo)5269540SJoost.Mulders@Sun.COM vr_resume(dev_info_t *devinfo)
5279540SJoost.Mulders@Sun.COM {
5289540SJoost.Mulders@Sun.COM vr_t *vrp;
5299540SJoost.Mulders@Sun.COM
5309540SJoost.Mulders@Sun.COM vrp = (vr_t *)ddi_get_driver_private(devinfo);
5319540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
5329540SJoost.Mulders@Sun.COM if (vrp->chip.state == CHIPSTATE_SUSPENDED_RUNNING)
53311387SSurya.Prakki@Sun.COM (void) vr_start(vrp);
5349540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
5359540SJoost.Mulders@Sun.COM return (DDI_SUCCESS);
5369540SJoost.Mulders@Sun.COM }
5379540SJoost.Mulders@Sun.COM
5389540SJoost.Mulders@Sun.COM /*
5399540SJoost.Mulders@Sun.COM * Suspend operation.
5409540SJoost.Mulders@Sun.COM */
5419540SJoost.Mulders@Sun.COM static int
vr_suspend(dev_info_t * devinfo)5429540SJoost.Mulders@Sun.COM vr_suspend(dev_info_t *devinfo)
5439540SJoost.Mulders@Sun.COM {
5449540SJoost.Mulders@Sun.COM vr_t *vrp;
5459540SJoost.Mulders@Sun.COM
5469540SJoost.Mulders@Sun.COM vrp = (vr_t *)ddi_get_driver_private(devinfo);
5479540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
5489540SJoost.Mulders@Sun.COM if (vrp->chip.state == CHIPSTATE_RUNNING) {
5499540SJoost.Mulders@Sun.COM (void) vr_stop(vrp);
5509540SJoost.Mulders@Sun.COM vrp->chip.state = CHIPSTATE_SUSPENDED_RUNNING;
5519540SJoost.Mulders@Sun.COM }
5529540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
5539540SJoost.Mulders@Sun.COM return (DDI_SUCCESS);
5549540SJoost.Mulders@Sun.COM }
5559540SJoost.Mulders@Sun.COM
5569540SJoost.Mulders@Sun.COM /*
5579540SJoost.Mulders@Sun.COM * Initial bus- and device configuration during attach(9E).
5589540SJoost.Mulders@Sun.COM */
5599540SJoost.Mulders@Sun.COM static vr_result_t
vr_bus_config(vr_t * vrp)5609540SJoost.Mulders@Sun.COM vr_bus_config(vr_t *vrp)
5619540SJoost.Mulders@Sun.COM {
5629540SJoost.Mulders@Sun.COM uint32_t addr;
5639540SJoost.Mulders@Sun.COM int n, nsets, rc;
5649540SJoost.Mulders@Sun.COM uint_t elem;
5659540SJoost.Mulders@Sun.COM pci_regspec_t *regs;
5669540SJoost.Mulders@Sun.COM
5679540SJoost.Mulders@Sun.COM /*
5689540SJoost.Mulders@Sun.COM * Get the reg property which describes the various access methods.
5699540SJoost.Mulders@Sun.COM */
5709540SJoost.Mulders@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, vrp->devinfo,
5719540SJoost.Mulders@Sun.COM 0, "reg", (int **)®s, &elem) != DDI_PROP_SUCCESS) {
5729540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "Can't get reg property");
5739540SJoost.Mulders@Sun.COM return (VR_FAILURE);
5749540SJoost.Mulders@Sun.COM }
5759540SJoost.Mulders@Sun.COM nsets = (elem * sizeof (uint_t)) / sizeof (pci_regspec_t);
5769540SJoost.Mulders@Sun.COM
5779540SJoost.Mulders@Sun.COM /*
5789540SJoost.Mulders@Sun.COM * Setup access to all available sets.
5799540SJoost.Mulders@Sun.COM */
5809540SJoost.Mulders@Sun.COM vrp->nsets = nsets;
5819540SJoost.Mulders@Sun.COM vrp->regset = kmem_zalloc(nsets * sizeof (vr_acc_t), KM_SLEEP);
5829540SJoost.Mulders@Sun.COM for (n = 0; n < nsets; n++) {
5839540SJoost.Mulders@Sun.COM rc = ddi_regs_map_setup(vrp->devinfo, n,
5849540SJoost.Mulders@Sun.COM &vrp->regset[n].addr, 0, 0,
5859540SJoost.Mulders@Sun.COM &vr_dev_dma_accattr,
5869540SJoost.Mulders@Sun.COM &vrp->regset[n].hdl);
5879540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
5889540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE,
5899540SJoost.Mulders@Sun.COM "Setup of register set %d failed", n);
5909540SJoost.Mulders@Sun.COM while (--n >= 0)
5919540SJoost.Mulders@Sun.COM ddi_regs_map_free(&vrp->regset[n].hdl);
5929540SJoost.Mulders@Sun.COM kmem_free(vrp->regset, nsets * sizeof (vr_acc_t));
5939540SJoost.Mulders@Sun.COM ddi_prop_free(regs);
5949540SJoost.Mulders@Sun.COM return (VR_FAILURE);
5959540SJoost.Mulders@Sun.COM }
5969540SJoost.Mulders@Sun.COM bcopy(®s[n], &vrp->regset[n].reg, sizeof (pci_regspec_t));
5979540SJoost.Mulders@Sun.COM }
5989540SJoost.Mulders@Sun.COM ddi_prop_free(regs);
5999540SJoost.Mulders@Sun.COM
6009540SJoost.Mulders@Sun.COM /*
6019540SJoost.Mulders@Sun.COM * Assign type-named pointers to the register sets.
6029540SJoost.Mulders@Sun.COM */
6039540SJoost.Mulders@Sun.COM for (n = 0; n < nsets; n++) {
6049540SJoost.Mulders@Sun.COM addr = vrp->regset[n].reg.pci_phys_hi & PCI_REG_ADDR_M;
6059540SJoost.Mulders@Sun.COM if (addr == PCI_ADDR_CONFIG && vrp->acc_cfg == NULL)
6069540SJoost.Mulders@Sun.COM vrp->acc_cfg = &vrp->regset[n];
6079540SJoost.Mulders@Sun.COM else if (addr == PCI_ADDR_IO && vrp->acc_io == NULL)
6089540SJoost.Mulders@Sun.COM vrp->acc_io = &vrp->regset[n];
6099540SJoost.Mulders@Sun.COM else if (addr == PCI_ADDR_MEM32 && vrp->acc_mem == NULL)
6109540SJoost.Mulders@Sun.COM vrp->acc_mem = &vrp->regset[n];
6119540SJoost.Mulders@Sun.COM }
6129540SJoost.Mulders@Sun.COM
6139540SJoost.Mulders@Sun.COM /*
6149540SJoost.Mulders@Sun.COM * Assure there is one of each type.
6159540SJoost.Mulders@Sun.COM */
6169540SJoost.Mulders@Sun.COM if (vrp->acc_cfg == NULL ||
6179540SJoost.Mulders@Sun.COM vrp->acc_io == NULL ||
6189540SJoost.Mulders@Sun.COM vrp->acc_mem == NULL) {
6199540SJoost.Mulders@Sun.COM for (n = 0; n < nsets; n++)
6209540SJoost.Mulders@Sun.COM ddi_regs_map_free(&vrp->regset[n].hdl);
6219540SJoost.Mulders@Sun.COM kmem_free(vrp->regset, nsets * sizeof (vr_acc_t));
6229540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
6239540SJoost.Mulders@Sun.COM "Config-, I/O- and memory sets not available");
6249540SJoost.Mulders@Sun.COM return (VR_FAILURE);
6259540SJoost.Mulders@Sun.COM }
6269540SJoost.Mulders@Sun.COM
6279540SJoost.Mulders@Sun.COM /*
6289540SJoost.Mulders@Sun.COM * Store vendor/device/revision.
6299540SJoost.Mulders@Sun.COM */
6309540SJoost.Mulders@Sun.COM vrp->chip.vendor = VR_GET16(vrp->acc_cfg, PCI_CONF_VENID);
6319540SJoost.Mulders@Sun.COM vrp->chip.device = VR_GET16(vrp->acc_cfg, PCI_CONF_DEVID);
6329540SJoost.Mulders@Sun.COM vrp->chip.revision = VR_GET16(vrp->acc_cfg, PCI_CONF_REVID);
6339540SJoost.Mulders@Sun.COM
6349540SJoost.Mulders@Sun.COM /*
6359540SJoost.Mulders@Sun.COM * Copy the matching chip_info_t structure.
6369540SJoost.Mulders@Sun.COM */
6379540SJoost.Mulders@Sun.COM elem = sizeof (vr_chip_info) / sizeof (chip_info_t);
6389540SJoost.Mulders@Sun.COM for (n = 0; n < elem; n++) {
6399540SJoost.Mulders@Sun.COM if (vrp->chip.revision >= vr_chip_info[n].revmin &&
6409540SJoost.Mulders@Sun.COM vrp->chip.revision <= vr_chip_info[n].revmax) {
6419540SJoost.Mulders@Sun.COM bcopy((void*)&vr_chip_info[n],
6429540SJoost.Mulders@Sun.COM (void*)&vrp->chip.info,
6439540SJoost.Mulders@Sun.COM sizeof (chip_info_t));
6449540SJoost.Mulders@Sun.COM break;
6459540SJoost.Mulders@Sun.COM }
6469540SJoost.Mulders@Sun.COM }
6479540SJoost.Mulders@Sun.COM
6489540SJoost.Mulders@Sun.COM /*
6499540SJoost.Mulders@Sun.COM * If we didn't find a chip_info_t for this card, copy the first
6509540SJoost.Mulders@Sun.COM * entry of the info structures. This is a generic Rhine whith no
6519540SJoost.Mulders@Sun.COM * bugs and no features.
6529540SJoost.Mulders@Sun.COM */
6539540SJoost.Mulders@Sun.COM if (vrp->chip.info.name == NULL) {
6549540SJoost.Mulders@Sun.COM bcopy((void*)&vr_chip_info[0],
6559540SJoost.Mulders@Sun.COM (void*) &vrp->chip.info,
6569540SJoost.Mulders@Sun.COM sizeof (chip_info_t));
6579540SJoost.Mulders@Sun.COM }
6589540SJoost.Mulders@Sun.COM
6599540SJoost.Mulders@Sun.COM /*
6609540SJoost.Mulders@Sun.COM * Tell what is found.
6619540SJoost.Mulders@Sun.COM */
6629540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "pci%d,%d,%d: %s, revision 0x%0x",
6639540SJoost.Mulders@Sun.COM PCI_REG_BUS_G(vrp->acc_cfg->reg.pci_phys_hi),
6649540SJoost.Mulders@Sun.COM PCI_REG_DEV_G(vrp->acc_cfg->reg.pci_phys_hi),
6659540SJoost.Mulders@Sun.COM PCI_REG_FUNC_G(vrp->acc_cfg->reg.pci_phys_hi),
6669540SJoost.Mulders@Sun.COM vrp->chip.info.name,
6679540SJoost.Mulders@Sun.COM vrp->chip.revision);
6689540SJoost.Mulders@Sun.COM
6699540SJoost.Mulders@Sun.COM /*
6709540SJoost.Mulders@Sun.COM * Assure that the device is prepared for memory space accesses
6719540SJoost.Mulders@Sun.COM * This should be the default as the device advertises memory
6729540SJoost.Mulders@Sun.COM * access in it's BAR's. However, my VT6102 on a EPIA CL board doesn't
6739540SJoost.Mulders@Sun.COM * and thus we explicetely enable it.
6749540SJoost.Mulders@Sun.COM */
6759540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_io, VR_CFGD, VR_CFGD_MMIOEN);
6769540SJoost.Mulders@Sun.COM
6779540SJoost.Mulders@Sun.COM /*
6789540SJoost.Mulders@Sun.COM * Setup a handle for regular usage, prefer memory space accesses.
6799540SJoost.Mulders@Sun.COM */
6809540SJoost.Mulders@Sun.COM if (vrp->acc_mem != NULL &&
6819540SJoost.Mulders@Sun.COM (vrp->chip.info.bugs & VR_BUG_NO_MEMIO) == 0)
6829540SJoost.Mulders@Sun.COM vrp->acc_reg = vrp->acc_mem;
6839540SJoost.Mulders@Sun.COM else
6849540SJoost.Mulders@Sun.COM vrp->acc_reg = vrp->acc_io;
6859540SJoost.Mulders@Sun.COM
6869540SJoost.Mulders@Sun.COM /*
6879540SJoost.Mulders@Sun.COM * Store the vendor's MAC address.
6889540SJoost.Mulders@Sun.COM */
6899540SJoost.Mulders@Sun.COM for (n = 0; n < ETHERADDRL; n++) {
6909540SJoost.Mulders@Sun.COM vrp->vendor_ether_addr[n] = VR_GET8(vrp->acc_reg,
6919540SJoost.Mulders@Sun.COM VR_ETHERADDR + n);
6929540SJoost.Mulders@Sun.COM }
6939540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
6949540SJoost.Mulders@Sun.COM }
6959540SJoost.Mulders@Sun.COM
6969540SJoost.Mulders@Sun.COM static void
vr_bus_unconfig(vr_t * vrp)6979540SJoost.Mulders@Sun.COM vr_bus_unconfig(vr_t *vrp)
6989540SJoost.Mulders@Sun.COM {
6999540SJoost.Mulders@Sun.COM uint_t n;
7009540SJoost.Mulders@Sun.COM
7019540SJoost.Mulders@Sun.COM /*
7029540SJoost.Mulders@Sun.COM * Free the register access handles.
7039540SJoost.Mulders@Sun.COM */
7049540SJoost.Mulders@Sun.COM for (n = 0; n < vrp->nsets; n++)
7059540SJoost.Mulders@Sun.COM ddi_regs_map_free(&vrp->regset[n].hdl);
7069540SJoost.Mulders@Sun.COM kmem_free(vrp->regset, vrp->nsets * sizeof (vr_acc_t));
7079540SJoost.Mulders@Sun.COM }
7089540SJoost.Mulders@Sun.COM
7099540SJoost.Mulders@Sun.COM /*
7109540SJoost.Mulders@Sun.COM * Initialize parameter structures.
7119540SJoost.Mulders@Sun.COM */
7129540SJoost.Mulders@Sun.COM static void
vr_param_init(vr_t * vrp)7139540SJoost.Mulders@Sun.COM vr_param_init(vr_t *vrp)
7149540SJoost.Mulders@Sun.COM {
7159540SJoost.Mulders@Sun.COM /*
7169540SJoost.Mulders@Sun.COM * Initialize default link configuration parameters.
7179540SJoost.Mulders@Sun.COM */
7189540SJoost.Mulders@Sun.COM vrp->param.an_en = VR_LINK_AUTONEG_ON;
7199540SJoost.Mulders@Sun.COM vrp->param.anadv_en = 1; /* Select 802.3 autonegotiation */
7209540SJoost.Mulders@Sun.COM vrp->param.anadv_en |= MII_ABILITY_100BASE_T4;
7219540SJoost.Mulders@Sun.COM vrp->param.anadv_en |= MII_ABILITY_100BASE_TX_FD;
7229540SJoost.Mulders@Sun.COM vrp->param.anadv_en |= MII_ABILITY_100BASE_TX;
7239540SJoost.Mulders@Sun.COM vrp->param.anadv_en |= MII_ABILITY_10BASE_T_FD;
7249540SJoost.Mulders@Sun.COM vrp->param.anadv_en |= MII_ABILITY_10BASE_T;
7259540SJoost.Mulders@Sun.COM /* Not a PHY ability, but advertised on behalf of MAC */
7269860Sgdamore@opensolaris.org vrp->param.anadv_en |= MII_ABILITY_PAUSE;
7279540SJoost.Mulders@Sun.COM vrp->param.mtu = ETHERMTU;
7289540SJoost.Mulders@Sun.COM
7299540SJoost.Mulders@Sun.COM /*
7309540SJoost.Mulders@Sun.COM * Store the PHY identity.
7319540SJoost.Mulders@Sun.COM */
7329540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_PHYIDH, &vrp->chip.mii.identh);
7339540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_PHYIDL, &vrp->chip.mii.identl);
7349540SJoost.Mulders@Sun.COM
7359540SJoost.Mulders@Sun.COM /*
7369540SJoost.Mulders@Sun.COM * Clear incapabilities imposed by PHY in phymask.
7379540SJoost.Mulders@Sun.COM */
7389540SJoost.Mulders@Sun.COM vrp->param.an_phymask = vrp->param.anadv_en;
7399540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_STATUS, &vrp->chip.mii.status);
7409540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_10) == 0)
7419540SJoost.Mulders@Sun.COM vrp->param.an_phymask &= ~MII_ABILITY_10BASE_T;
7429540SJoost.Mulders@Sun.COM
7439540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_10_FD) == 0)
7449540SJoost.Mulders@Sun.COM vrp->param.an_phymask &= ~MII_ABILITY_10BASE_T_FD;
7459540SJoost.Mulders@Sun.COM
7469540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_100_BASEX) == 0)
7479540SJoost.Mulders@Sun.COM vrp->param.an_phymask &= ~MII_ABILITY_100BASE_TX;
7489540SJoost.Mulders@Sun.COM
7499540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_100_BASEX_FD) == 0)
7509540SJoost.Mulders@Sun.COM vrp->param.an_phymask &= ~MII_ABILITY_100BASE_TX_FD;
7519540SJoost.Mulders@Sun.COM
7529540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_100_BASE_T4) == 0)
7539540SJoost.Mulders@Sun.COM vrp->param.an_phymask &= ~MII_ABILITY_100BASE_T4;
7549540SJoost.Mulders@Sun.COM
7559540SJoost.Mulders@Sun.COM /*
7569540SJoost.Mulders@Sun.COM * Clear incapabilities imposed by MAC in macmask
7579540SJoost.Mulders@Sun.COM * Note that flowcontrol (FCS?) is never masked. All of our adapters
7589540SJoost.Mulders@Sun.COM * have the ability to honor incoming pause frames. Only the newer can
7599540SJoost.Mulders@Sun.COM * transmit pause frames. Since there's no asym flowcontrol in 100Mbit
7609540SJoost.Mulders@Sun.COM * Ethernet, we always advertise (symmetric) pause.
7619540SJoost.Mulders@Sun.COM */
7629540SJoost.Mulders@Sun.COM vrp->param.an_macmask = vrp->param.anadv_en;
7639540SJoost.Mulders@Sun.COM
7649540SJoost.Mulders@Sun.COM /*
7659540SJoost.Mulders@Sun.COM * Advertised capabilities is enabled minus incapable.
7669540SJoost.Mulders@Sun.COM */
7679540SJoost.Mulders@Sun.COM vrp->chip.mii.anadv = vrp->param.anadv_en &
7689540SJoost.Mulders@Sun.COM (vrp->param.an_phymask & vrp->param.an_macmask);
7699540SJoost.Mulders@Sun.COM
7709540SJoost.Mulders@Sun.COM /*
7719540SJoost.Mulders@Sun.COM * Ensure that autoneg of the PHY matches our default.
7729540SJoost.Mulders@Sun.COM */
7739540SJoost.Mulders@Sun.COM if (vrp->param.an_en == VR_LINK_AUTONEG_ON)
7749540SJoost.Mulders@Sun.COM vrp->chip.mii.control = MII_CONTROL_ANE;
7759540SJoost.Mulders@Sun.COM else
7769540SJoost.Mulders@Sun.COM vrp->chip.mii.control =
7779540SJoost.Mulders@Sun.COM (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
7789540SJoost.Mulders@Sun.COM }
7799540SJoost.Mulders@Sun.COM
7809540SJoost.Mulders@Sun.COM /*
7819540SJoost.Mulders@Sun.COM * Setup the descriptor rings.
7829540SJoost.Mulders@Sun.COM */
7839540SJoost.Mulders@Sun.COM static vr_result_t
vr_rings_init(vr_t * vrp)7849540SJoost.Mulders@Sun.COM vr_rings_init(vr_t *vrp)
7859540SJoost.Mulders@Sun.COM {
7869540SJoost.Mulders@Sun.COM
7879540SJoost.Mulders@Sun.COM vrp->rx.ndesc = VR_RX_N_DESC;
7889540SJoost.Mulders@Sun.COM vrp->tx.ndesc = VR_TX_N_DESC;
7899540SJoost.Mulders@Sun.COM
7909540SJoost.Mulders@Sun.COM /*
7919540SJoost.Mulders@Sun.COM * Create a ring for receive.
7929540SJoost.Mulders@Sun.COM */
7939540SJoost.Mulders@Sun.COM if (vr_alloc_ring(vrp, &vrp->rxring, vrp->rx.ndesc) != VR_SUCCESS)
7949540SJoost.Mulders@Sun.COM return (VR_FAILURE);
7959540SJoost.Mulders@Sun.COM
7969540SJoost.Mulders@Sun.COM /*
7979540SJoost.Mulders@Sun.COM * Create a ring for transmit.
7989540SJoost.Mulders@Sun.COM */
7999540SJoost.Mulders@Sun.COM if (vr_alloc_ring(vrp, &vrp->txring, vrp->tx.ndesc) != VR_SUCCESS) {
8009540SJoost.Mulders@Sun.COM vr_free_ring(&vrp->rxring, vrp->rx.ndesc);
8019540SJoost.Mulders@Sun.COM return (VR_FAILURE);
8029540SJoost.Mulders@Sun.COM }
8039540SJoost.Mulders@Sun.COM
8049540SJoost.Mulders@Sun.COM vrp->rx.ring = vrp->rxring.desc;
8059540SJoost.Mulders@Sun.COM vrp->tx.ring = vrp->txring.desc;
8069540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
8079540SJoost.Mulders@Sun.COM }
8089540SJoost.Mulders@Sun.COM
8099540SJoost.Mulders@Sun.COM static void
vr_rings_fini(vr_t * vrp)8109540SJoost.Mulders@Sun.COM vr_rings_fini(vr_t *vrp)
8119540SJoost.Mulders@Sun.COM {
8129540SJoost.Mulders@Sun.COM vr_free_ring(&vrp->rxring, vrp->rx.ndesc);
8139540SJoost.Mulders@Sun.COM vr_free_ring(&vrp->txring, vrp->tx.ndesc);
8149540SJoost.Mulders@Sun.COM }
8159540SJoost.Mulders@Sun.COM
8169540SJoost.Mulders@Sun.COM /*
8179540SJoost.Mulders@Sun.COM * Allocate a descriptor ring
8189540SJoost.Mulders@Sun.COM * The number of descriptor entries must fit in a single page so that the
8199540SJoost.Mulders@Sun.COM * whole ring fits in one consequtive space.
8209540SJoost.Mulders@Sun.COM * i386: 4K page / 16 byte descriptor = 256 entries
8219540SJoost.Mulders@Sun.COM * sparc: 8K page / 16 byte descriptor = 512 entries
8229540SJoost.Mulders@Sun.COM */
8239540SJoost.Mulders@Sun.COM static vr_result_t
vr_alloc_ring(vr_t * vrp,vr_ring_t * ring,size_t n)8249540SJoost.Mulders@Sun.COM vr_alloc_ring(vr_t *vrp, vr_ring_t *ring, size_t n)
8259540SJoost.Mulders@Sun.COM {
8269540SJoost.Mulders@Sun.COM ddi_dma_cookie_t desc_dma_cookie;
8279540SJoost.Mulders@Sun.COM uint_t desc_cookiecnt;
8289540SJoost.Mulders@Sun.COM int i, rc;
8299540SJoost.Mulders@Sun.COM size_t rbytes;
8309540SJoost.Mulders@Sun.COM
8319540SJoost.Mulders@Sun.COM /*
8329540SJoost.Mulders@Sun.COM * Allocate a DMA handle for the chip descriptors.
8339540SJoost.Mulders@Sun.COM */
8349540SJoost.Mulders@Sun.COM rc = ddi_dma_alloc_handle(vrp->devinfo,
8359540SJoost.Mulders@Sun.COM &vr_dev_dma_attr,
8369540SJoost.Mulders@Sun.COM DDI_DMA_SLEEP,
8379540SJoost.Mulders@Sun.COM NULL,
8389540SJoost.Mulders@Sun.COM &ring->handle);
8399540SJoost.Mulders@Sun.COM
8409540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
8419540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
8429540SJoost.Mulders@Sun.COM "ddi_dma_alloc_handle in vr_alloc_ring failed.");
8439540SJoost.Mulders@Sun.COM return (VR_FAILURE);
8449540SJoost.Mulders@Sun.COM }
8459540SJoost.Mulders@Sun.COM
8469540SJoost.Mulders@Sun.COM /*
8479540SJoost.Mulders@Sun.COM * Allocate memory for the chip descriptors.
8489540SJoost.Mulders@Sun.COM */
8499540SJoost.Mulders@Sun.COM rc = ddi_dma_mem_alloc(ring->handle,
8509540SJoost.Mulders@Sun.COM n * sizeof (vr_chip_desc_t),
8519540SJoost.Mulders@Sun.COM &vr_dev_dma_accattr,
8529540SJoost.Mulders@Sun.COM DDI_DMA_CONSISTENT,
8539540SJoost.Mulders@Sun.COM DDI_DMA_SLEEP,
8549540SJoost.Mulders@Sun.COM NULL,
8559540SJoost.Mulders@Sun.COM (caddr_t *)&ring->cdesc,
8569540SJoost.Mulders@Sun.COM &rbytes,
8579540SJoost.Mulders@Sun.COM &ring->acchdl);
8589540SJoost.Mulders@Sun.COM
8599540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
8609540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
8619540SJoost.Mulders@Sun.COM "ddi_dma_mem_alloc in vr_alloc_ring failed.");
8629540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&ring->handle);
8639540SJoost.Mulders@Sun.COM return (VR_FAILURE);
8649540SJoost.Mulders@Sun.COM }
8659540SJoost.Mulders@Sun.COM
8669540SJoost.Mulders@Sun.COM /*
8679540SJoost.Mulders@Sun.COM * Map the descriptor memory.
8689540SJoost.Mulders@Sun.COM */
8699540SJoost.Mulders@Sun.COM rc = ddi_dma_addr_bind_handle(ring->handle,
8709540SJoost.Mulders@Sun.COM NULL,
8719540SJoost.Mulders@Sun.COM (caddr_t)ring->cdesc,
8729540SJoost.Mulders@Sun.COM rbytes,
8739540SJoost.Mulders@Sun.COM DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
8749540SJoost.Mulders@Sun.COM DDI_DMA_SLEEP,
8759540SJoost.Mulders@Sun.COM NULL,
8769540SJoost.Mulders@Sun.COM &desc_dma_cookie,
8779540SJoost.Mulders@Sun.COM &desc_cookiecnt);
8789540SJoost.Mulders@Sun.COM
8799540SJoost.Mulders@Sun.COM if (rc != DDI_DMA_MAPPED || desc_cookiecnt > 1) {
8809540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
8819540SJoost.Mulders@Sun.COM "ddi_dma_addr_bind_handle in vr_alloc_ring failed: "
8829540SJoost.Mulders@Sun.COM "rc = %d, cookiecnt = %d", rc, desc_cookiecnt);
8839540SJoost.Mulders@Sun.COM ddi_dma_mem_free(&ring->acchdl);
8849540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&ring->handle);
8859540SJoost.Mulders@Sun.COM return (VR_FAILURE);
8869540SJoost.Mulders@Sun.COM }
8879540SJoost.Mulders@Sun.COM ring->cdesc_paddr = desc_dma_cookie.dmac_address;
8889540SJoost.Mulders@Sun.COM
8899540SJoost.Mulders@Sun.COM /*
8909540SJoost.Mulders@Sun.COM * Allocate memory for the host descriptor ring.
8919540SJoost.Mulders@Sun.COM */
8929540SJoost.Mulders@Sun.COM ring->desc =
8939540SJoost.Mulders@Sun.COM (vr_desc_t *)kmem_zalloc(n * sizeof (vr_desc_t), KM_SLEEP);
8949540SJoost.Mulders@Sun.COM
8959540SJoost.Mulders@Sun.COM /*
8969540SJoost.Mulders@Sun.COM * Interlink the descriptors and connect host- to chip descriptors.
8979540SJoost.Mulders@Sun.COM */
8989540SJoost.Mulders@Sun.COM for (i = 0; i < n; i++) {
8999540SJoost.Mulders@Sun.COM /*
9009540SJoost.Mulders@Sun.COM * Connect the host descriptor to a chip descriptor.
9019540SJoost.Mulders@Sun.COM */
9029540SJoost.Mulders@Sun.COM ring->desc[i].cdesc = &ring->cdesc[i];
9039540SJoost.Mulders@Sun.COM
9049540SJoost.Mulders@Sun.COM /*
9059540SJoost.Mulders@Sun.COM * Store the DMA address and offset in the descriptor
9069540SJoost.Mulders@Sun.COM * Offset is for ddi_dma_sync() and paddr is for ddi_get/-put().
9079540SJoost.Mulders@Sun.COM */
9089540SJoost.Mulders@Sun.COM ring->desc[i].offset = i * sizeof (vr_chip_desc_t);
9099540SJoost.Mulders@Sun.COM ring->desc[i].paddr = ring->cdesc_paddr + ring->desc[i].offset;
9109540SJoost.Mulders@Sun.COM
9119540SJoost.Mulders@Sun.COM /*
9129540SJoost.Mulders@Sun.COM * Link the previous descriptor to this one.
9139540SJoost.Mulders@Sun.COM */
9149540SJoost.Mulders@Sun.COM if (i > 0) {
9159540SJoost.Mulders@Sun.COM /* Host */
9169540SJoost.Mulders@Sun.COM ring->desc[i-1].next = &ring->desc[i];
9179540SJoost.Mulders@Sun.COM
9189540SJoost.Mulders@Sun.COM /* Chip */
9199540SJoost.Mulders@Sun.COM ddi_put32(ring->acchdl,
9209540SJoost.Mulders@Sun.COM &ring->cdesc[i-1].next,
9219540SJoost.Mulders@Sun.COM ring->desc[i].paddr);
9229540SJoost.Mulders@Sun.COM }
9239540SJoost.Mulders@Sun.COM }
9249540SJoost.Mulders@Sun.COM
9259540SJoost.Mulders@Sun.COM /*
9269540SJoost.Mulders@Sun.COM * Make rings out of this list by pointing last to first.
9279540SJoost.Mulders@Sun.COM */
9289540SJoost.Mulders@Sun.COM i = n - 1;
9299540SJoost.Mulders@Sun.COM ring->desc[i].next = &ring->desc[0];
9309540SJoost.Mulders@Sun.COM ddi_put32(ring->acchdl, &ring->cdesc[i].next, ring->desc[0].paddr);
9319540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
9329540SJoost.Mulders@Sun.COM }
9339540SJoost.Mulders@Sun.COM
9349540SJoost.Mulders@Sun.COM /*
9359540SJoost.Mulders@Sun.COM * Free the memory allocated for a ring.
9369540SJoost.Mulders@Sun.COM */
9379540SJoost.Mulders@Sun.COM static void
vr_free_ring(vr_ring_t * r,size_t n)9389540SJoost.Mulders@Sun.COM vr_free_ring(vr_ring_t *r, size_t n)
9399540SJoost.Mulders@Sun.COM {
9409540SJoost.Mulders@Sun.COM /*
9419540SJoost.Mulders@Sun.COM * Unmap and free the chip descriptors.
9429540SJoost.Mulders@Sun.COM */
9439540SJoost.Mulders@Sun.COM (void) ddi_dma_unbind_handle(r->handle);
9449540SJoost.Mulders@Sun.COM ddi_dma_mem_free(&r->acchdl);
9459540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&r->handle);
9469540SJoost.Mulders@Sun.COM
9479540SJoost.Mulders@Sun.COM /*
9489540SJoost.Mulders@Sun.COM * Free the memory for storing host descriptors
9499540SJoost.Mulders@Sun.COM */
9509540SJoost.Mulders@Sun.COM kmem_free(r->desc, n * sizeof (vr_desc_t));
9519540SJoost.Mulders@Sun.COM }
9529540SJoost.Mulders@Sun.COM
9539540SJoost.Mulders@Sun.COM /*
9549540SJoost.Mulders@Sun.COM * Initialize the receive ring.
9559540SJoost.Mulders@Sun.COM */
9569540SJoost.Mulders@Sun.COM static vr_result_t
vr_rxring_init(vr_t * vrp)9579540SJoost.Mulders@Sun.COM vr_rxring_init(vr_t *vrp)
9589540SJoost.Mulders@Sun.COM {
9599540SJoost.Mulders@Sun.COM int i, rc;
9609540SJoost.Mulders@Sun.COM vr_desc_t *rp;
9619540SJoost.Mulders@Sun.COM
9629540SJoost.Mulders@Sun.COM /*
9639540SJoost.Mulders@Sun.COM * Set the read pointer at the start of the ring.
9649540SJoost.Mulders@Sun.COM */
9659540SJoost.Mulders@Sun.COM vrp->rx.rp = &vrp->rx.ring[0];
9669540SJoost.Mulders@Sun.COM
9679540SJoost.Mulders@Sun.COM /*
9689540SJoost.Mulders@Sun.COM * Assign a DMA buffer to each receive descriptor.
9699540SJoost.Mulders@Sun.COM */
9709540SJoost.Mulders@Sun.COM for (i = 0; i < vrp->rx.ndesc; i++) {
9719540SJoost.Mulders@Sun.COM rp = &vrp->rx.ring[i];
9729540SJoost.Mulders@Sun.COM rc = vr_alloc_dmabuf(vrp,
9739540SJoost.Mulders@Sun.COM &vrp->rx.ring[i].dmabuf,
9749540SJoost.Mulders@Sun.COM DDI_DMA_STREAMING | DDI_DMA_READ);
9759540SJoost.Mulders@Sun.COM
9769540SJoost.Mulders@Sun.COM if (rc != VR_SUCCESS) {
9779540SJoost.Mulders@Sun.COM while (--i >= 0)
9789540SJoost.Mulders@Sun.COM vr_free_dmabuf(&vrp->rx.ring[i].dmabuf);
9799540SJoost.Mulders@Sun.COM return (VR_FAILURE);
9809540SJoost.Mulders@Sun.COM }
9819540SJoost.Mulders@Sun.COM
9829540SJoost.Mulders@Sun.COM /*
9839540SJoost.Mulders@Sun.COM * Store the address of the dma buffer in the chip descriptor
9849540SJoost.Mulders@Sun.COM */
9859540SJoost.Mulders@Sun.COM ddi_put32(vrp->rxring.acchdl,
9869540SJoost.Mulders@Sun.COM &rp->cdesc->data,
9879540SJoost.Mulders@Sun.COM rp->dmabuf.paddr);
9889540SJoost.Mulders@Sun.COM
9899540SJoost.Mulders@Sun.COM /*
9909540SJoost.Mulders@Sun.COM * Put the buffer length in the chip descriptor. Ensure that
9919540SJoost.Mulders@Sun.COM * length fits in the 11 bits of stat1 (2047/0x7FF)
9929540SJoost.Mulders@Sun.COM */
9939540SJoost.Mulders@Sun.COM ddi_put32(vrp->rxring.acchdl, &rp->cdesc->stat1,
9949540SJoost.Mulders@Sun.COM MIN(VR_MAX_PKTSZ, rp->dmabuf.bufsz));
9959540SJoost.Mulders@Sun.COM
9969540SJoost.Mulders@Sun.COM /*
9979540SJoost.Mulders@Sun.COM * Set descriptor ownership to the card
9989540SJoost.Mulders@Sun.COM */
9999540SJoost.Mulders@Sun.COM ddi_put32(vrp->rxring.acchdl, &rp->cdesc->stat0, VR_RDES0_OWN);
10009540SJoost.Mulders@Sun.COM
10019540SJoost.Mulders@Sun.COM /*
10029540SJoost.Mulders@Sun.COM * Sync the descriptor with main memory
10039540SJoost.Mulders@Sun.COM */
10049540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->rxring.handle, rp->offset,
10059540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORDEV);
10069540SJoost.Mulders@Sun.COM }
10079540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
10089540SJoost.Mulders@Sun.COM }
10099540SJoost.Mulders@Sun.COM
10109540SJoost.Mulders@Sun.COM /*
10119540SJoost.Mulders@Sun.COM * Free the DMA buffers assigned to the receive ring.
10129540SJoost.Mulders@Sun.COM */
10139540SJoost.Mulders@Sun.COM static void
vr_rxring_fini(vr_t * vrp)10149540SJoost.Mulders@Sun.COM vr_rxring_fini(vr_t *vrp)
10159540SJoost.Mulders@Sun.COM {
10169540SJoost.Mulders@Sun.COM int i;
10179540SJoost.Mulders@Sun.COM
10189540SJoost.Mulders@Sun.COM for (i = 0; i < vrp->rx.ndesc; i++)
10199540SJoost.Mulders@Sun.COM vr_free_dmabuf(&vrp->rx.ring[i].dmabuf);
10209540SJoost.Mulders@Sun.COM }
10219540SJoost.Mulders@Sun.COM
10229540SJoost.Mulders@Sun.COM static vr_result_t
vr_txring_init(vr_t * vrp)10239540SJoost.Mulders@Sun.COM vr_txring_init(vr_t *vrp)
10249540SJoost.Mulders@Sun.COM {
10259540SJoost.Mulders@Sun.COM vr_desc_t *wp;
10269540SJoost.Mulders@Sun.COM int i, rc;
10279540SJoost.Mulders@Sun.COM
10289540SJoost.Mulders@Sun.COM /*
10299540SJoost.Mulders@Sun.COM * Set the write- and claim pointer.
10309540SJoost.Mulders@Sun.COM */
10319540SJoost.Mulders@Sun.COM vrp->tx.wp = &vrp->tx.ring[0];
10329540SJoost.Mulders@Sun.COM vrp->tx.cp = &vrp->tx.ring[0];
10339540SJoost.Mulders@Sun.COM
10349540SJoost.Mulders@Sun.COM /*
10359540SJoost.Mulders@Sun.COM * (Re)set the TX bookkeeping.
10369540SJoost.Mulders@Sun.COM */
10379540SJoost.Mulders@Sun.COM vrp->tx.stallticks = 0;
10389540SJoost.Mulders@Sun.COM vrp->tx.resched = 0;
10399540SJoost.Mulders@Sun.COM
10409540SJoost.Mulders@Sun.COM /*
10419540SJoost.Mulders@Sun.COM * Every transmit decreases nfree. Every reclaim increases nfree.
10429540SJoost.Mulders@Sun.COM */
10439540SJoost.Mulders@Sun.COM vrp->tx.nfree = vrp->tx.ndesc;
10449540SJoost.Mulders@Sun.COM
10459540SJoost.Mulders@Sun.COM /*
10469540SJoost.Mulders@Sun.COM * Attach a DMA buffer to each transmit descriptor.
10479540SJoost.Mulders@Sun.COM */
10489540SJoost.Mulders@Sun.COM for (i = 0; i < vrp->tx.ndesc; i++) {
10499540SJoost.Mulders@Sun.COM rc = vr_alloc_dmabuf(vrp,
10509540SJoost.Mulders@Sun.COM &vrp->tx.ring[i].dmabuf,
10519540SJoost.Mulders@Sun.COM DDI_DMA_STREAMING | DDI_DMA_WRITE);
10529540SJoost.Mulders@Sun.COM
10539540SJoost.Mulders@Sun.COM if (rc != VR_SUCCESS) {
10549540SJoost.Mulders@Sun.COM while (--i >= 0)
10559540SJoost.Mulders@Sun.COM vr_free_dmabuf(&vrp->tx.ring[i].dmabuf);
10569540SJoost.Mulders@Sun.COM return (VR_FAILURE);
10579540SJoost.Mulders@Sun.COM }
10589540SJoost.Mulders@Sun.COM }
10599540SJoost.Mulders@Sun.COM
10609540SJoost.Mulders@Sun.COM /*
10619540SJoost.Mulders@Sun.COM * Init & sync the TX descriptors so the device sees a valid ring.
10629540SJoost.Mulders@Sun.COM */
10639540SJoost.Mulders@Sun.COM for (i = 0; i < vrp->tx.ndesc; i++) {
10649540SJoost.Mulders@Sun.COM wp = &vrp->tx.ring[i];
10659540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat0, 0);
10669540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat1, 0);
10679540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->data,
10689540SJoost.Mulders@Sun.COM wp->dmabuf.paddr);
10699540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->txring.handle, wp->offset,
10709540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t),
10719540SJoost.Mulders@Sun.COM DDI_DMA_SYNC_FORDEV);
10729540SJoost.Mulders@Sun.COM }
10739540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
10749540SJoost.Mulders@Sun.COM }
10759540SJoost.Mulders@Sun.COM
10769540SJoost.Mulders@Sun.COM /*
10779540SJoost.Mulders@Sun.COM * Free the DMA buffers attached to the TX ring.
10789540SJoost.Mulders@Sun.COM */
10799540SJoost.Mulders@Sun.COM static void
vr_txring_fini(vr_t * vrp)10809540SJoost.Mulders@Sun.COM vr_txring_fini(vr_t *vrp)
10819540SJoost.Mulders@Sun.COM {
10829540SJoost.Mulders@Sun.COM int i;
10839540SJoost.Mulders@Sun.COM
10849540SJoost.Mulders@Sun.COM /*
10859540SJoost.Mulders@Sun.COM * Free the DMA buffers attached to the TX ring
10869540SJoost.Mulders@Sun.COM */
10879540SJoost.Mulders@Sun.COM for (i = 0; i < vrp->tx.ndesc; i++)
10889540SJoost.Mulders@Sun.COM vr_free_dmabuf(&vrp->tx.ring[i].dmabuf);
10899540SJoost.Mulders@Sun.COM }
10909540SJoost.Mulders@Sun.COM
10919540SJoost.Mulders@Sun.COM /*
10929540SJoost.Mulders@Sun.COM * Allocate a DMA buffer.
10939540SJoost.Mulders@Sun.COM */
10949540SJoost.Mulders@Sun.COM static vr_result_t
vr_alloc_dmabuf(vr_t * vrp,vr_data_dma_t * dmap,uint_t dmaflags)10959540SJoost.Mulders@Sun.COM vr_alloc_dmabuf(vr_t *vrp, vr_data_dma_t *dmap, uint_t dmaflags)
10969540SJoost.Mulders@Sun.COM {
10979540SJoost.Mulders@Sun.COM ddi_dma_cookie_t dma_cookie;
10989540SJoost.Mulders@Sun.COM uint_t cookiecnt;
10999540SJoost.Mulders@Sun.COM int rc;
11009540SJoost.Mulders@Sun.COM
11019540SJoost.Mulders@Sun.COM /*
11029540SJoost.Mulders@Sun.COM * Allocate a DMA handle for the buffer
11039540SJoost.Mulders@Sun.COM */
11049540SJoost.Mulders@Sun.COM rc = ddi_dma_alloc_handle(vrp->devinfo,
11059540SJoost.Mulders@Sun.COM &vr_data_dma_attr,
11069540SJoost.Mulders@Sun.COM DDI_DMA_DONTWAIT, NULL,
11079540SJoost.Mulders@Sun.COM &dmap->handle);
11089540SJoost.Mulders@Sun.COM
11099540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
11109540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
11119540SJoost.Mulders@Sun.COM "ddi_dma_alloc_handle failed in vr_alloc_dmabuf");
11129540SJoost.Mulders@Sun.COM return (VR_FAILURE);
11139540SJoost.Mulders@Sun.COM }
11149540SJoost.Mulders@Sun.COM
11159540SJoost.Mulders@Sun.COM /*
11169540SJoost.Mulders@Sun.COM * Allocate the buffer
11179540SJoost.Mulders@Sun.COM * The allocated buffer is aligned on 2K boundary. This ensures that
11189540SJoost.Mulders@Sun.COM * a 1500 byte frame never cross a page boundary and thus that the DMA
11199540SJoost.Mulders@Sun.COM * mapping can be established in 1 fragment.
11209540SJoost.Mulders@Sun.COM */
11219540SJoost.Mulders@Sun.COM rc = ddi_dma_mem_alloc(dmap->handle,
11229540SJoost.Mulders@Sun.COM VR_DMABUFSZ,
11239540SJoost.Mulders@Sun.COM &vr_data_dma_accattr,
11249540SJoost.Mulders@Sun.COM DDI_DMA_RDWR | DDI_DMA_STREAMING,
11259540SJoost.Mulders@Sun.COM DDI_DMA_DONTWAIT, NULL,
11269540SJoost.Mulders@Sun.COM &dmap->buf,
11279540SJoost.Mulders@Sun.COM &dmap->bufsz,
11289540SJoost.Mulders@Sun.COM &dmap->acchdl);
11299540SJoost.Mulders@Sun.COM
11309540SJoost.Mulders@Sun.COM if (rc != DDI_SUCCESS) {
11319540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
11329540SJoost.Mulders@Sun.COM "ddi_dma_mem_alloc failed in vr_alloc_dmabuf");
11339540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&dmap->handle);
11349540SJoost.Mulders@Sun.COM return (VR_FAILURE);
11359540SJoost.Mulders@Sun.COM }
11369540SJoost.Mulders@Sun.COM
11379540SJoost.Mulders@Sun.COM /*
11389540SJoost.Mulders@Sun.COM * Map the memory
11399540SJoost.Mulders@Sun.COM */
11409540SJoost.Mulders@Sun.COM rc = ddi_dma_addr_bind_handle(dmap->handle,
11419540SJoost.Mulders@Sun.COM NULL,
11429540SJoost.Mulders@Sun.COM (caddr_t)dmap->buf,
11439540SJoost.Mulders@Sun.COM dmap->bufsz,
11449540SJoost.Mulders@Sun.COM dmaflags,
11459540SJoost.Mulders@Sun.COM DDI_DMA_DONTWAIT,
11469540SJoost.Mulders@Sun.COM NULL,
11479540SJoost.Mulders@Sun.COM &dma_cookie,
11489540SJoost.Mulders@Sun.COM &cookiecnt);
11499540SJoost.Mulders@Sun.COM
11509540SJoost.Mulders@Sun.COM /*
11519540SJoost.Mulders@Sun.COM * The cookiecount should never > 1 because we requested 2K alignment
11529540SJoost.Mulders@Sun.COM */
11539540SJoost.Mulders@Sun.COM if (rc != DDI_DMA_MAPPED || cookiecnt > 1) {
11549540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
11559540SJoost.Mulders@Sun.COM "dma_addr_bind_handle failed in vr_alloc_dmabuf: "
11569540SJoost.Mulders@Sun.COM "rc = %d, cookiecnt = %d", rc, cookiecnt);
11579540SJoost.Mulders@Sun.COM ddi_dma_mem_free(&dmap->acchdl);
11589540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&dmap->handle);
11599540SJoost.Mulders@Sun.COM return (VR_FAILURE);
11609540SJoost.Mulders@Sun.COM }
11619540SJoost.Mulders@Sun.COM dmap->paddr = dma_cookie.dmac_address;
11629540SJoost.Mulders@Sun.COM return (VR_SUCCESS);
11639540SJoost.Mulders@Sun.COM }
11649540SJoost.Mulders@Sun.COM
11659540SJoost.Mulders@Sun.COM /*
11669540SJoost.Mulders@Sun.COM * Destroy a DMA buffer.
11679540SJoost.Mulders@Sun.COM */
11689540SJoost.Mulders@Sun.COM static void
vr_free_dmabuf(vr_data_dma_t * dmap)11699540SJoost.Mulders@Sun.COM vr_free_dmabuf(vr_data_dma_t *dmap)
11709540SJoost.Mulders@Sun.COM {
11719540SJoost.Mulders@Sun.COM (void) ddi_dma_unbind_handle(dmap->handle);
11729540SJoost.Mulders@Sun.COM ddi_dma_mem_free(&dmap->acchdl);
11739540SJoost.Mulders@Sun.COM ddi_dma_free_handle(&dmap->handle);
11749540SJoost.Mulders@Sun.COM }
11759540SJoost.Mulders@Sun.COM
11769540SJoost.Mulders@Sun.COM /*
11779540SJoost.Mulders@Sun.COM * Interrupt service routine
11789540SJoost.Mulders@Sun.COM * When our vector is shared with another device, av_dispatch_autovect calls
11799540SJoost.Mulders@Sun.COM * all service routines for the vector until *none* of them return claimed
11809540SJoost.Mulders@Sun.COM * That means that, when sharing vectors, this routine is called at least
11819540SJoost.Mulders@Sun.COM * twice for each interrupt.
11829540SJoost.Mulders@Sun.COM */
11839540SJoost.Mulders@Sun.COM uint_t
vr_intr(caddr_t arg1,caddr_t arg2)11849540SJoost.Mulders@Sun.COM vr_intr(caddr_t arg1, caddr_t arg2)
11859540SJoost.Mulders@Sun.COM {
11869540SJoost.Mulders@Sun.COM vr_t *vrp;
11879540SJoost.Mulders@Sun.COM uint16_t status;
11889540SJoost.Mulders@Sun.COM mblk_t *lp = NULL;
11899540SJoost.Mulders@Sun.COM uint32_t tx_resched;
11909540SJoost.Mulders@Sun.COM uint32_t link_change;
11919540SJoost.Mulders@Sun.COM
11929540SJoost.Mulders@Sun.COM tx_resched = 0;
11939540SJoost.Mulders@Sun.COM link_change = 0;
11949540SJoost.Mulders@Sun.COM vrp = (void *)arg1;
11959540SJoost.Mulders@Sun.COM _NOTE(ARGUNUSED(arg2))
11969540SJoost.Mulders@Sun.COM
1197*12174Sjoostmnl@gmail.com mutex_enter(&vrp->intrlock);
1198*12174Sjoostmnl@gmail.com /*
1199*12174Sjoostmnl@gmail.com * If the driver is not in running state it is not our interrupt.
1200*12174Sjoostmnl@gmail.com * Shared interrupts can end up here without us being started.
1201*12174Sjoostmnl@gmail.com */
1202*12174Sjoostmnl@gmail.com if (vrp->chip.state != CHIPSTATE_RUNNING) {
1203*12174Sjoostmnl@gmail.com mutex_exit(&vrp->intrlock);
1204*12174Sjoostmnl@gmail.com return (DDI_INTR_UNCLAIMED);
1205*12174Sjoostmnl@gmail.com }
1206*12174Sjoostmnl@gmail.com
12079540SJoost.Mulders@Sun.COM /*
12089540SJoost.Mulders@Sun.COM * Read the status register to see if the interrupt is from our device
12099540SJoost.Mulders@Sun.COM * This read also ensures that posted writes are brought to main memory.
12109540SJoost.Mulders@Sun.COM */
12119540SJoost.Mulders@Sun.COM status = VR_GET16(vrp->acc_reg, VR_ISR0) & VR_ICR0_CFG;
12129540SJoost.Mulders@Sun.COM if (status == 0) {
12139540SJoost.Mulders@Sun.COM /*
12149540SJoost.Mulders@Sun.COM * Status contains no configured interrupts
12159540SJoost.Mulders@Sun.COM * The interrupt was not generated by our device.
12169540SJoost.Mulders@Sun.COM */
12179540SJoost.Mulders@Sun.COM vrp->stats.intr_unclaimed++;
12189540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
12199540SJoost.Mulders@Sun.COM return (DDI_INTR_UNCLAIMED);
12209540SJoost.Mulders@Sun.COM }
12219540SJoost.Mulders@Sun.COM vrp->stats.intr_claimed++;
12229540SJoost.Mulders@Sun.COM
12239540SJoost.Mulders@Sun.COM /*
12249540SJoost.Mulders@Sun.COM * Acknowledge the event(s) that caused interruption.
12259540SJoost.Mulders@Sun.COM */
12269540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_ISR0, status);
12279540SJoost.Mulders@Sun.COM
12289540SJoost.Mulders@Sun.COM /*
12299540SJoost.Mulders@Sun.COM * Receive completion.
12309540SJoost.Mulders@Sun.COM */
12319540SJoost.Mulders@Sun.COM if ((status & (VR_ISR0_RX_DONE | VR_ISR_RX_ERR_BITS)) != 0) {
12329540SJoost.Mulders@Sun.COM /*
12339540SJoost.Mulders@Sun.COM * Received some packets.
12349540SJoost.Mulders@Sun.COM */
12359540SJoost.Mulders@Sun.COM lp = vr_receive(vrp);
12369540SJoost.Mulders@Sun.COM
12379540SJoost.Mulders@Sun.COM /*
12389540SJoost.Mulders@Sun.COM * DMA stops after a conflict in the FIFO.
12399540SJoost.Mulders@Sun.COM */
12409540SJoost.Mulders@Sun.COM if ((status & VR_ISR_RX_ERR_BITS) != 0)
12419540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO);
12429540SJoost.Mulders@Sun.COM status &= ~(VR_ISR0_RX_DONE | VR_ISR_RX_ERR_BITS);
12439540SJoost.Mulders@Sun.COM }
12449540SJoost.Mulders@Sun.COM
12459540SJoost.Mulders@Sun.COM /*
12469540SJoost.Mulders@Sun.COM * Transmit completion.
12479540SJoost.Mulders@Sun.COM */
12489540SJoost.Mulders@Sun.COM if ((status & (VR_ISR0_TX_DONE | VR_ISR_TX_ERR_BITS)) != 0) {
12499540SJoost.Mulders@Sun.COM /*
12509540SJoost.Mulders@Sun.COM * Card done with transmitting some packets
12519540SJoost.Mulders@Sun.COM * TX_DONE is generated 3 times per ring but it appears
12529540SJoost.Mulders@Sun.COM * more often because it is also set when an RX_DONE
12539540SJoost.Mulders@Sun.COM * interrupt is generated.
12549540SJoost.Mulders@Sun.COM */
12559540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
12569540SJoost.Mulders@Sun.COM vr_tx_reclaim(vrp);
12579540SJoost.Mulders@Sun.COM tx_resched = vrp->tx.resched;
12589540SJoost.Mulders@Sun.COM vrp->tx.resched = 0;
12599540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
12609540SJoost.Mulders@Sun.COM status &= ~(VR_ISR0_TX_DONE | VR_ISR_TX_ERR_BITS);
12619540SJoost.Mulders@Sun.COM }
12629540SJoost.Mulders@Sun.COM
12639540SJoost.Mulders@Sun.COM /*
12649540SJoost.Mulders@Sun.COM * Link status change.
12659540SJoost.Mulders@Sun.COM */
12669540SJoost.Mulders@Sun.COM if ((status & VR_ICR0_LINKSTATUS) != 0) {
12679540SJoost.Mulders@Sun.COM /*
12689540SJoost.Mulders@Sun.COM * Get new link state and inform the mac layer.
12699540SJoost.Mulders@Sun.COM */
12709540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
12719540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
12729540SJoost.Mulders@Sun.COM vr_link_state(vrp);
12739540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
12749540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
12759540SJoost.Mulders@Sun.COM status &= ~VR_ICR0_LINKSTATUS;
12769540SJoost.Mulders@Sun.COM vrp->stats.linkchanges++;
12779540SJoost.Mulders@Sun.COM link_change = 1;
12789540SJoost.Mulders@Sun.COM }
12799540SJoost.Mulders@Sun.COM
12809540SJoost.Mulders@Sun.COM /*
12819540SJoost.Mulders@Sun.COM * Bus error.
12829540SJoost.Mulders@Sun.COM */
12839540SJoost.Mulders@Sun.COM if ((status & VR_ISR0_BUSERR) != 0) {
12849540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "bus error occured");
12859540SJoost.Mulders@Sun.COM vrp->reset = 1;
12869540SJoost.Mulders@Sun.COM status &= ~VR_ISR0_BUSERR;
12879540SJoost.Mulders@Sun.COM }
12889540SJoost.Mulders@Sun.COM
12899540SJoost.Mulders@Sun.COM /*
12909540SJoost.Mulders@Sun.COM * We must have handled all things here.
12919540SJoost.Mulders@Sun.COM */
12929540SJoost.Mulders@Sun.COM ASSERT(status == 0);
12939540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
12949540SJoost.Mulders@Sun.COM
12959540SJoost.Mulders@Sun.COM /*
12969540SJoost.Mulders@Sun.COM * Reset the device if requested
12979540SJoost.Mulders@Sun.COM * The request can come from the periodic tx check or from the interrupt
12989540SJoost.Mulders@Sun.COM * status.
12999540SJoost.Mulders@Sun.COM */
13009540SJoost.Mulders@Sun.COM if (vrp->reset != 0) {
13019540SJoost.Mulders@Sun.COM vr_error(vrp);
13029540SJoost.Mulders@Sun.COM vrp->reset = 0;
13039540SJoost.Mulders@Sun.COM }
13049540SJoost.Mulders@Sun.COM
13059540SJoost.Mulders@Sun.COM /*
13069540SJoost.Mulders@Sun.COM * Pass up the list with received packets.
13079540SJoost.Mulders@Sun.COM */
13089540SJoost.Mulders@Sun.COM if (lp != NULL)
13099540SJoost.Mulders@Sun.COM mac_rx(vrp->machdl, 0, lp);
13109540SJoost.Mulders@Sun.COM
13119540SJoost.Mulders@Sun.COM /*
13129540SJoost.Mulders@Sun.COM * Inform the upper layer on the linkstatus if there was a change.
13139540SJoost.Mulders@Sun.COM */
13149540SJoost.Mulders@Sun.COM if (link_change != 0)
13159540SJoost.Mulders@Sun.COM mac_link_update(vrp->machdl,
13169540SJoost.Mulders@Sun.COM (link_state_t)vrp->chip.link.state);
13179540SJoost.Mulders@Sun.COM /*
13189540SJoost.Mulders@Sun.COM * Restart transmissions if we were waiting for tx descriptors.
13199540SJoost.Mulders@Sun.COM */
13209540SJoost.Mulders@Sun.COM if (tx_resched == 1)
13219540SJoost.Mulders@Sun.COM mac_tx_update(vrp->machdl);
13229540SJoost.Mulders@Sun.COM
13239540SJoost.Mulders@Sun.COM /*
13249540SJoost.Mulders@Sun.COM * Read something from the card to ensure that all of our configuration
13259540SJoost.Mulders@Sun.COM * writes are delivered to the device before the interrupt is ended.
13269540SJoost.Mulders@Sun.COM */
13279540SJoost.Mulders@Sun.COM (void) VR_GET8(vrp->acc_reg, VR_ETHERADDR);
13289540SJoost.Mulders@Sun.COM return (DDI_INTR_CLAIMED);
13299540SJoost.Mulders@Sun.COM }
13309540SJoost.Mulders@Sun.COM
13319540SJoost.Mulders@Sun.COM /*
13329540SJoost.Mulders@Sun.COM * Respond to an unforseen situation by resetting the card and our bookkeeping.
13339540SJoost.Mulders@Sun.COM */
13349540SJoost.Mulders@Sun.COM static void
vr_error(vr_t * vrp)13359540SJoost.Mulders@Sun.COM vr_error(vr_t *vrp)
13369540SJoost.Mulders@Sun.COM {
13379540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "resetting MAC.");
13389540SJoost.Mulders@Sun.COM mutex_enter(&vrp->intrlock);
13399540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
13409540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
13419540SJoost.Mulders@Sun.COM (void) vr_stop(vrp);
13429540SJoost.Mulders@Sun.COM vr_reset(vrp);
13439540SJoost.Mulders@Sun.COM (void) vr_start(vrp);
13449540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
13459540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
13469540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
13479540SJoost.Mulders@Sun.COM vrp->stats.resets++;
13489540SJoost.Mulders@Sun.COM }
13499540SJoost.Mulders@Sun.COM
13509540SJoost.Mulders@Sun.COM /*
13519540SJoost.Mulders@Sun.COM * Collect received packets in a list.
13529540SJoost.Mulders@Sun.COM */
13539540SJoost.Mulders@Sun.COM static mblk_t *
vr_receive(vr_t * vrp)13549540SJoost.Mulders@Sun.COM vr_receive(vr_t *vrp)
13559540SJoost.Mulders@Sun.COM {
13569540SJoost.Mulders@Sun.COM mblk_t *lp, *mp, *np;
13579540SJoost.Mulders@Sun.COM vr_desc_t *rxp;
13589540SJoost.Mulders@Sun.COM vr_data_dma_t *dmap;
13599540SJoost.Mulders@Sun.COM uint32_t pklen;
13609540SJoost.Mulders@Sun.COM uint32_t rxstat0;
13619540SJoost.Mulders@Sun.COM uint32_t n;
13629540SJoost.Mulders@Sun.COM
13639540SJoost.Mulders@Sun.COM lp = NULL;
13649540SJoost.Mulders@Sun.COM n = 0;
13659540SJoost.Mulders@Sun.COM for (rxp = vrp->rx.rp; ; rxp = rxp->next, n++) {
13669540SJoost.Mulders@Sun.COM /*
13679540SJoost.Mulders@Sun.COM * Sync the descriptor before looking at it.
13689540SJoost.Mulders@Sun.COM */
13699540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->rxring.handle, rxp->offset,
13709540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORKERNEL);
13719540SJoost.Mulders@Sun.COM
13729540SJoost.Mulders@Sun.COM /*
13739540SJoost.Mulders@Sun.COM * Get the status from the descriptor.
13749540SJoost.Mulders@Sun.COM */
13759540SJoost.Mulders@Sun.COM rxstat0 = ddi_get32(vrp->rxring.acchdl, &rxp->cdesc->stat0);
13769540SJoost.Mulders@Sun.COM
13779540SJoost.Mulders@Sun.COM /*
13789540SJoost.Mulders@Sun.COM * We're done if the descriptor is owned by the card.
13799540SJoost.Mulders@Sun.COM */
13809540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_OWN) != 0)
13819540SJoost.Mulders@Sun.COM break;
13829540SJoost.Mulders@Sun.COM else if ((rxstat0 & VR_RDES0_RXOK) != 0) {
13839540SJoost.Mulders@Sun.COM /*
13849540SJoost.Mulders@Sun.COM * Received a good packet
13859540SJoost.Mulders@Sun.COM */
13869540SJoost.Mulders@Sun.COM dmap = &rxp->dmabuf;
13879540SJoost.Mulders@Sun.COM pklen = (rxstat0 >> 16) - ETHERFCSL;
13889540SJoost.Mulders@Sun.COM
13899540SJoost.Mulders@Sun.COM /*
13909540SJoost.Mulders@Sun.COM * Sync the data.
13919540SJoost.Mulders@Sun.COM */
13929540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(dmap->handle, 0,
13939540SJoost.Mulders@Sun.COM pklen, DDI_DMA_SYNC_FORKERNEL);
13949540SJoost.Mulders@Sun.COM
13959540SJoost.Mulders@Sun.COM /*
13969540SJoost.Mulders@Sun.COM * Send a new copied message upstream.
13979540SJoost.Mulders@Sun.COM */
13989540SJoost.Mulders@Sun.COM np = allocb(pklen, 0);
13999540SJoost.Mulders@Sun.COM if (np != NULL) {
14009540SJoost.Mulders@Sun.COM bcopy(dmap->buf, np->b_rptr, pklen);
14019540SJoost.Mulders@Sun.COM np->b_wptr = np->b_rptr + pklen;
14029540SJoost.Mulders@Sun.COM
14039540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_ipackets++;
14049540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_rbytes += pklen;
14059540SJoost.Mulders@Sun.COM
14069540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_BAR) != 0)
14079540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_brdcstrcv++;
14089540SJoost.Mulders@Sun.COM else if ((rxstat0 & VR_RDES0_MAR) != 0)
14099540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_multircv++;
14109540SJoost.Mulders@Sun.COM
14119540SJoost.Mulders@Sun.COM /*
14129540SJoost.Mulders@Sun.COM * Link this packet in the list.
14139540SJoost.Mulders@Sun.COM */
14149540SJoost.Mulders@Sun.COM np->b_next = NULL;
14159540SJoost.Mulders@Sun.COM if (lp == NULL)
14169540SJoost.Mulders@Sun.COM lp = mp = np;
14179540SJoost.Mulders@Sun.COM else {
14189540SJoost.Mulders@Sun.COM mp->b_next = np;
14199540SJoost.Mulders@Sun.COM mp = np;
14209540SJoost.Mulders@Sun.COM }
14219540SJoost.Mulders@Sun.COM } else {
14229540SJoost.Mulders@Sun.COM vrp->stats.allocbfail++;
14239540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_norcvbuf++;
14249540SJoost.Mulders@Sun.COM }
14259540SJoost.Mulders@Sun.COM
14269540SJoost.Mulders@Sun.COM } else {
14279540SJoost.Mulders@Sun.COM /*
14289540SJoost.Mulders@Sun.COM * Received with errors.
14299540SJoost.Mulders@Sun.COM */
14309540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_ierrors++;
14319540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_FAE) != 0)
14329540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_align_errors++;
14339540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_CRCERR) != 0)
14349540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_fcs_errors++;
14359540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_LONG) != 0)
14369540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_toolong_errors++;
14379540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_RUNT) != 0)
14389540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_tooshort_errors++;
14399540SJoost.Mulders@Sun.COM if ((rxstat0 & VR_RDES0_FOV) != 0)
14409540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_overflows++;
14419540SJoost.Mulders@Sun.COM }
14429540SJoost.Mulders@Sun.COM
14439540SJoost.Mulders@Sun.COM /*
14449540SJoost.Mulders@Sun.COM * Reset descriptor ownership to the MAC.
14459540SJoost.Mulders@Sun.COM */
14469540SJoost.Mulders@Sun.COM ddi_put32(vrp->rxring.acchdl,
14479540SJoost.Mulders@Sun.COM &rxp->cdesc->stat0,
14489540SJoost.Mulders@Sun.COM VR_RDES0_OWN);
14499540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->rxring.handle,
14509540SJoost.Mulders@Sun.COM rxp->offset,
14519540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t),
14529540SJoost.Mulders@Sun.COM DDI_DMA_SYNC_FORDEV);
14539540SJoost.Mulders@Sun.COM }
14549540SJoost.Mulders@Sun.COM vrp->rx.rp = rxp;
14559540SJoost.Mulders@Sun.COM
14569540SJoost.Mulders@Sun.COM /*
14579540SJoost.Mulders@Sun.COM * If we do flowcontrol and if the card can transmit pause frames,
14589540SJoost.Mulders@Sun.COM * increment the "available receive descriptors" register.
14599540SJoost.Mulders@Sun.COM */
14609540SJoost.Mulders@Sun.COM if (n > 0 && vrp->chip.link.flowctrl == VR_PAUSE_BIDIRECTIONAL) {
14619540SJoost.Mulders@Sun.COM /*
14629540SJoost.Mulders@Sun.COM * Whenever the card moves a fragment to host memory it
14639540SJoost.Mulders@Sun.COM * decrements the RXBUFCOUNT register. If the value in the
14649540SJoost.Mulders@Sun.COM * register reaches a low watermark, the card transmits a pause
14659540SJoost.Mulders@Sun.COM * frame. If the value in this register reaches a high
14669540SJoost.Mulders@Sun.COM * watermark, the card sends a "cancel pause" frame
14679540SJoost.Mulders@Sun.COM *
14689540SJoost.Mulders@Sun.COM * Non-zero values written to this byte register are added
14699540SJoost.Mulders@Sun.COM * by the chip to the register's contents, so we must write
14709540SJoost.Mulders@Sun.COM * the number of descriptors free'd.
14719540SJoost.Mulders@Sun.COM */
14729540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_FCR0_RXBUFCOUNT, MIN(n, 0xFF));
14739540SJoost.Mulders@Sun.COM }
14749540SJoost.Mulders@Sun.COM return (lp);
14759540SJoost.Mulders@Sun.COM }
14769540SJoost.Mulders@Sun.COM
14779540SJoost.Mulders@Sun.COM /*
14789540SJoost.Mulders@Sun.COM * Enqueue a list of packets for transmission
14799540SJoost.Mulders@Sun.COM * Return the packets not transmitted.
14809540SJoost.Mulders@Sun.COM */
14819540SJoost.Mulders@Sun.COM mblk_t *
vr_mac_tx_enqueue_list(void * p,mblk_t * mp)14829540SJoost.Mulders@Sun.COM vr_mac_tx_enqueue_list(void *p, mblk_t *mp)
14839540SJoost.Mulders@Sun.COM {
14849540SJoost.Mulders@Sun.COM vr_t *vrp;
14859540SJoost.Mulders@Sun.COM mblk_t *nextp;
14869540SJoost.Mulders@Sun.COM
14879540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
14889540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
14899540SJoost.Mulders@Sun.COM do {
14909540SJoost.Mulders@Sun.COM if (vrp->tx.nfree == 0) {
14919540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_defer_xmts++;
14929540SJoost.Mulders@Sun.COM vrp->tx.resched = 1;
14939540SJoost.Mulders@Sun.COM break;
14949540SJoost.Mulders@Sun.COM }
14959540SJoost.Mulders@Sun.COM nextp = mp->b_next;
14969540SJoost.Mulders@Sun.COM mp->b_next = mp->b_prev = NULL;
14979540SJoost.Mulders@Sun.COM vr_tx_enqueue_msg(vrp, mp);
14989540SJoost.Mulders@Sun.COM mp = nextp;
14999540SJoost.Mulders@Sun.COM vrp->tx.nfree--;
15009540SJoost.Mulders@Sun.COM } while (mp != NULL);
15019540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
15029540SJoost.Mulders@Sun.COM
15039540SJoost.Mulders@Sun.COM /*
15049540SJoost.Mulders@Sun.COM * Tell the chip to poll the TX ring.
15059540SJoost.Mulders@Sun.COM */
15069540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO);
15079540SJoost.Mulders@Sun.COM return (mp);
15089540SJoost.Mulders@Sun.COM }
15099540SJoost.Mulders@Sun.COM
15109540SJoost.Mulders@Sun.COM /*
15119540SJoost.Mulders@Sun.COM * Enqueue a message for transmission.
15129540SJoost.Mulders@Sun.COM */
15139540SJoost.Mulders@Sun.COM static void
vr_tx_enqueue_msg(vr_t * vrp,mblk_t * mp)15149540SJoost.Mulders@Sun.COM vr_tx_enqueue_msg(vr_t *vrp, mblk_t *mp)
15159540SJoost.Mulders@Sun.COM {
15169540SJoost.Mulders@Sun.COM vr_desc_t *wp;
15179540SJoost.Mulders@Sun.COM vr_data_dma_t *dmap;
15189540SJoost.Mulders@Sun.COM uint32_t pklen;
15199540SJoost.Mulders@Sun.COM uint32_t nextp;
15209540SJoost.Mulders@Sun.COM int padlen;
15219540SJoost.Mulders@Sun.COM
15229540SJoost.Mulders@Sun.COM if ((uchar_t)mp->b_rptr[0] == 0xff &&
15239540SJoost.Mulders@Sun.COM (uchar_t)mp->b_rptr[1] == 0xff &&
15249540SJoost.Mulders@Sun.COM (uchar_t)mp->b_rptr[2] == 0xff &&
15259540SJoost.Mulders@Sun.COM (uchar_t)mp->b_rptr[3] == 0xff &&
15269540SJoost.Mulders@Sun.COM (uchar_t)mp->b_rptr[4] == 0xff &&
15279540SJoost.Mulders@Sun.COM (uchar_t)mp->b_rptr[5] == 0xff)
15289540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_brdcstxmt++;
15299540SJoost.Mulders@Sun.COM else if ((uchar_t)mp->b_rptr[0] == 1)
15309540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_multixmt++;
15319540SJoost.Mulders@Sun.COM
15329540SJoost.Mulders@Sun.COM pklen = msgsize(mp);
15339540SJoost.Mulders@Sun.COM wp = vrp->tx.wp;
15349540SJoost.Mulders@Sun.COM dmap = &wp->dmabuf;
15359540SJoost.Mulders@Sun.COM
15369540SJoost.Mulders@Sun.COM /*
15379540SJoost.Mulders@Sun.COM * Copy the message into the pre-mapped buffer and free mp
15389540SJoost.Mulders@Sun.COM */
15399540SJoost.Mulders@Sun.COM mcopymsg(mp, dmap->buf);
15409540SJoost.Mulders@Sun.COM
15419540SJoost.Mulders@Sun.COM /*
15429540SJoost.Mulders@Sun.COM * Clean padlen bytes of short packet.
15439540SJoost.Mulders@Sun.COM */
15449540SJoost.Mulders@Sun.COM padlen = ETHERMIN - pklen;
15459540SJoost.Mulders@Sun.COM if (padlen > 0) {
15469540SJoost.Mulders@Sun.COM bzero(dmap->buf + pklen, padlen);
15479540SJoost.Mulders@Sun.COM pklen += padlen;
15489540SJoost.Mulders@Sun.COM }
15499540SJoost.Mulders@Sun.COM
15509540SJoost.Mulders@Sun.COM /*
15519540SJoost.Mulders@Sun.COM * Most of the statistics are updated on reclaim, after the actual
15529540SJoost.Mulders@Sun.COM * transmit. obytes is maintained here because the length is cleared
15539540SJoost.Mulders@Sun.COM * after transmission
15549540SJoost.Mulders@Sun.COM */
15559540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_obytes += pklen;
15569540SJoost.Mulders@Sun.COM
15579540SJoost.Mulders@Sun.COM /*
15589540SJoost.Mulders@Sun.COM * Sync the data so the device sees the new content too.
15599540SJoost.Mulders@Sun.COM */
15609540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(dmap->handle, 0, pklen, DDI_DMA_SYNC_FORDEV);
15619540SJoost.Mulders@Sun.COM
15629540SJoost.Mulders@Sun.COM /*
15639540SJoost.Mulders@Sun.COM * If we have reached the TX interrupt distance, enable a TX interrupt
15649540SJoost.Mulders@Sun.COM * for this packet. The Interrupt Control (IC) bit in the transmit
15659540SJoost.Mulders@Sun.COM * descriptor doesn't have any effect on the interrupt generation
15669540SJoost.Mulders@Sun.COM * despite the vague statements in the datasheet. Thus, we use the
15679540SJoost.Mulders@Sun.COM * more obscure interrupt suppress bit which is probably part of the
15689540SJoost.Mulders@Sun.COM * MAC's bookkeeping for TX interrupts and fragmented packets.
15699540SJoost.Mulders@Sun.COM */
15709540SJoost.Mulders@Sun.COM vrp->tx.intr_distance++;
15719540SJoost.Mulders@Sun.COM nextp = ddi_get32(vrp->txring.acchdl, &wp->cdesc->next);
15729540SJoost.Mulders@Sun.COM if (vrp->tx.intr_distance >= VR_TX_MAX_INTR_DISTANCE) {
15739540SJoost.Mulders@Sun.COM /*
15749540SJoost.Mulders@Sun.COM * Don't suppress the interrupt for this packet.
15759540SJoost.Mulders@Sun.COM */
15769540SJoost.Mulders@Sun.COM vrp->tx.intr_distance = 0;
15779540SJoost.Mulders@Sun.COM nextp &= (~VR_TDES3_SUPPRESS_INTR);
15789540SJoost.Mulders@Sun.COM } else {
15799540SJoost.Mulders@Sun.COM /*
15809540SJoost.Mulders@Sun.COM * Suppress the interrupt for this packet.
15819540SJoost.Mulders@Sun.COM */
15829540SJoost.Mulders@Sun.COM nextp |= VR_TDES3_SUPPRESS_INTR;
15839540SJoost.Mulders@Sun.COM }
15849540SJoost.Mulders@Sun.COM
15859540SJoost.Mulders@Sun.COM /*
15869540SJoost.Mulders@Sun.COM * Write and sync the chip's descriptor
15879540SJoost.Mulders@Sun.COM */
15889540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat1,
15899540SJoost.Mulders@Sun.COM pklen | (VR_TDES1_STP | VR_TDES1_EDP | VR_TDES1_CHN));
15909540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->next, nextp);
15919540SJoost.Mulders@Sun.COM ddi_put32(vrp->txring.acchdl, &wp->cdesc->stat0, VR_TDES0_OWN);
15929540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->txring.handle, wp->offset,
15939540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t), DDI_DMA_SYNC_FORDEV);
15949540SJoost.Mulders@Sun.COM
15959540SJoost.Mulders@Sun.COM /*
15969540SJoost.Mulders@Sun.COM * The ticks counter is cleared by reclaim when it reclaimed some
15979540SJoost.Mulders@Sun.COM * descriptors and incremented by the periodic TX stall check.
15989540SJoost.Mulders@Sun.COM */
15999540SJoost.Mulders@Sun.COM vrp->tx.stallticks = 1;
16009540SJoost.Mulders@Sun.COM vrp->tx.wp = wp->next;
16019540SJoost.Mulders@Sun.COM }
16029540SJoost.Mulders@Sun.COM
16039540SJoost.Mulders@Sun.COM /*
16049540SJoost.Mulders@Sun.COM * Free transmitted descriptors.
16059540SJoost.Mulders@Sun.COM */
16069540SJoost.Mulders@Sun.COM static void
vr_tx_reclaim(vr_t * vrp)16079540SJoost.Mulders@Sun.COM vr_tx_reclaim(vr_t *vrp)
16089540SJoost.Mulders@Sun.COM {
16099540SJoost.Mulders@Sun.COM vr_desc_t *cp;
16109540SJoost.Mulders@Sun.COM uint32_t stat0, stat1, freed, dirty;
16119540SJoost.Mulders@Sun.COM
16129540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(&vrp->tx.lock));
16139540SJoost.Mulders@Sun.COM
16149540SJoost.Mulders@Sun.COM freed = 0;
16159540SJoost.Mulders@Sun.COM dirty = vrp->tx.ndesc - vrp->tx.nfree;
16169540SJoost.Mulders@Sun.COM for (cp = vrp->tx.cp; dirty > 0; cp = cp->next) {
16179540SJoost.Mulders@Sun.COM /*
16189540SJoost.Mulders@Sun.COM * Sync & get descriptor status.
16199540SJoost.Mulders@Sun.COM */
16209540SJoost.Mulders@Sun.COM (void) ddi_dma_sync(vrp->txring.handle, cp->offset,
16219540SJoost.Mulders@Sun.COM sizeof (vr_chip_desc_t),
16229540SJoost.Mulders@Sun.COM DDI_DMA_SYNC_FORKERNEL);
16239540SJoost.Mulders@Sun.COM stat0 = ddi_get32(vrp->txring.acchdl, &cp->cdesc->stat0);
16249540SJoost.Mulders@Sun.COM
16259540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_OWN) != 0)
16269540SJoost.Mulders@Sun.COM break;
16279540SJoost.Mulders@Sun.COM
16289540SJoost.Mulders@Sun.COM /*
16299540SJoost.Mulders@Sun.COM * Do stats for the first descriptor in a chain.
16309540SJoost.Mulders@Sun.COM */
16319540SJoost.Mulders@Sun.COM stat1 = ddi_get32(vrp->txring.acchdl, &cp->cdesc->stat1);
16329540SJoost.Mulders@Sun.COM if ((stat1 & VR_TDES1_STP) != 0) {
16339540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_TERR) != 0) {
16349540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_macxmt_errors++;
16359540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_UDF) != 0)
16369540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_underflows++;
16379540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_ABT) != 0)
16389540SJoost.Mulders@Sun.COM vrp-> stats.ether_stat_ex_collisions++;
16399540SJoost.Mulders@Sun.COM /*
16409540SJoost.Mulders@Sun.COM * Abort and FIFO underflow stop the MAC.
16419540SJoost.Mulders@Sun.COM * Packet queueing must be disabled with HD
16429540SJoost.Mulders@Sun.COM * links because otherwise the MAC is also lost
16439540SJoost.Mulders@Sun.COM * after a few of these events.
16449540SJoost.Mulders@Sun.COM */
16459540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0,
16469540SJoost.Mulders@Sun.COM VR_CTRL0_DMA_GO);
16479540SJoost.Mulders@Sun.COM } else
16489540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_opackets++;
16499540SJoost.Mulders@Sun.COM
16509540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_COL) != 0) {
16519540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_NCR) == 1) {
16529540SJoost.Mulders@Sun.COM vrp->stats.
16539540SJoost.Mulders@Sun.COM ether_stat_first_collisions++;
16549540SJoost.Mulders@Sun.COM } else {
16559540SJoost.Mulders@Sun.COM vrp->stats.
16569540SJoost.Mulders@Sun.COM ether_stat_multi_collisions++;
16579540SJoost.Mulders@Sun.COM }
16589540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_collisions +=
16599540SJoost.Mulders@Sun.COM (stat0 & VR_TDES0_NCR);
16609540SJoost.Mulders@Sun.COM }
16619540SJoost.Mulders@Sun.COM
16629540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_CRS) != 0)
16639540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_carrier_errors++;
16649540SJoost.Mulders@Sun.COM
16659540SJoost.Mulders@Sun.COM if ((stat0 & VR_TDES0_OWC) != 0)
16669540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_tx_late_collisions++;
16679540SJoost.Mulders@Sun.COM }
16689540SJoost.Mulders@Sun.COM freed += 1;
16699540SJoost.Mulders@Sun.COM dirty -= 1;
16709540SJoost.Mulders@Sun.COM }
16719540SJoost.Mulders@Sun.COM vrp->tx.cp = cp;
16729540SJoost.Mulders@Sun.COM
16739540SJoost.Mulders@Sun.COM if (freed > 0) {
16749540SJoost.Mulders@Sun.COM vrp->tx.nfree += freed;
16759540SJoost.Mulders@Sun.COM vrp->tx.stallticks = 0;
16769540SJoost.Mulders@Sun.COM vrp->stats.txreclaims += 1;
16779540SJoost.Mulders@Sun.COM } else
16789540SJoost.Mulders@Sun.COM vrp->stats.txreclaim0 += 1;
16799540SJoost.Mulders@Sun.COM }
16809540SJoost.Mulders@Sun.COM
16819540SJoost.Mulders@Sun.COM /*
16829540SJoost.Mulders@Sun.COM * Check TX health every 2 seconds.
16839540SJoost.Mulders@Sun.COM */
16849540SJoost.Mulders@Sun.COM static void
vr_periodic(void * p)16859540SJoost.Mulders@Sun.COM vr_periodic(void *p)
16869540SJoost.Mulders@Sun.COM {
16879540SJoost.Mulders@Sun.COM vr_t *vrp;
16889540SJoost.Mulders@Sun.COM
16899540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
16909540SJoost.Mulders@Sun.COM if (vrp->chip.state == CHIPSTATE_RUNNING &&
16919540SJoost.Mulders@Sun.COM vrp->chip.link.state == VR_LINK_STATE_UP && vrp->reset == 0) {
16929540SJoost.Mulders@Sun.COM if (mutex_tryenter(&vrp->intrlock) != 0) {
16939540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
16949540SJoost.Mulders@Sun.COM if (vrp->tx.resched == 1) {
16959540SJoost.Mulders@Sun.COM if (vrp->tx.stallticks >= VR_MAXTXCHECKS) {
16969540SJoost.Mulders@Sun.COM /*
16979540SJoost.Mulders@Sun.COM * No succesful reclaim in the last n
16989540SJoost.Mulders@Sun.COM * intervals. Reset the MAC.
16999540SJoost.Mulders@Sun.COM */
17009540SJoost.Mulders@Sun.COM vrp->reset = 1;
17019540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
17029540SJoost.Mulders@Sun.COM "TX stalled, resetting MAC");
17039540SJoost.Mulders@Sun.COM vrp->stats.txstalls++;
17049540SJoost.Mulders@Sun.COM } else {
17059540SJoost.Mulders@Sun.COM /*
17069540SJoost.Mulders@Sun.COM * Increase until we find that we've
17079540SJoost.Mulders@Sun.COM * waited long enough.
17089540SJoost.Mulders@Sun.COM */
17099540SJoost.Mulders@Sun.COM vrp->tx.stallticks += 1;
17109540SJoost.Mulders@Sun.COM }
17119540SJoost.Mulders@Sun.COM }
17129540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
17139540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
17149540SJoost.Mulders@Sun.COM vrp->stats.txchecks++;
17159540SJoost.Mulders@Sun.COM }
17169540SJoost.Mulders@Sun.COM }
17179540SJoost.Mulders@Sun.COM vrp->stats.cyclics++;
17189540SJoost.Mulders@Sun.COM }
17199540SJoost.Mulders@Sun.COM
17209540SJoost.Mulders@Sun.COM /*
17219540SJoost.Mulders@Sun.COM * Bring the device to our desired initial state.
17229540SJoost.Mulders@Sun.COM */
17239540SJoost.Mulders@Sun.COM static void
vr_reset(vr_t * vrp)17249540SJoost.Mulders@Sun.COM vr_reset(vr_t *vrp)
17259540SJoost.Mulders@Sun.COM {
17269540SJoost.Mulders@Sun.COM uint32_t time;
17279540SJoost.Mulders@Sun.COM
17289540SJoost.Mulders@Sun.COM /*
17299540SJoost.Mulders@Sun.COM * Reset the MAC
17309540SJoost.Mulders@Sun.COM * If we don't wait long enough for the forced reset to complete,
17319540SJoost.Mulders@Sun.COM * MAC looses sync with PHY. Result link up, no link change interrupt
17329540SJoost.Mulders@Sun.COM * and no data transfer.
17339540SJoost.Mulders@Sun.COM */
17349540SJoost.Mulders@Sun.COM time = 0;
17359540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_io, VR_CTRL1, VR_CTRL1_RESET);
17369540SJoost.Mulders@Sun.COM do {
17379540SJoost.Mulders@Sun.COM drv_usecwait(100);
17389540SJoost.Mulders@Sun.COM time += 100;
17399540SJoost.Mulders@Sun.COM if (time >= 100000) {
17409540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_io, VR_MISC1, VR_MISC1_RESET);
17419540SJoost.Mulders@Sun.COM delay(drv_usectohz(200000));
17429540SJoost.Mulders@Sun.COM }
17439540SJoost.Mulders@Sun.COM } while ((VR_GET8(vrp->acc_io, VR_CTRL1) & VR_CTRL1_RESET) != 0);
17449540SJoost.Mulders@Sun.COM delay(drv_usectohz(10000));
17459540SJoost.Mulders@Sun.COM
17469540SJoost.Mulders@Sun.COM /*
17479540SJoost.Mulders@Sun.COM * Load the PROM contents into the MAC again.
17489540SJoost.Mulders@Sun.COM */
17499540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_io, VR_PROMCTL, VR_PROMCTL_RELOAD);
17509540SJoost.Mulders@Sun.COM delay(drv_usectohz(100000));
17519540SJoost.Mulders@Sun.COM
17529540SJoost.Mulders@Sun.COM /*
17539540SJoost.Mulders@Sun.COM * Tell the MAC via IO space that we like to use memory space for
17549540SJoost.Mulders@Sun.COM * accessing registers.
17559540SJoost.Mulders@Sun.COM */
17569540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_io, VR_CFGD, VR_CFGD_MMIOEN);
17579540SJoost.Mulders@Sun.COM }
17589540SJoost.Mulders@Sun.COM
17599540SJoost.Mulders@Sun.COM /*
17609540SJoost.Mulders@Sun.COM * Prepare and enable the card (MAC + PHY + PCI).
17619540SJoost.Mulders@Sun.COM */
17629540SJoost.Mulders@Sun.COM static int
vr_start(vr_t * vrp)17639540SJoost.Mulders@Sun.COM vr_start(vr_t *vrp)
17649540SJoost.Mulders@Sun.COM {
17659540SJoost.Mulders@Sun.COM uint8_t pci_latency, pci_mode;
17669540SJoost.Mulders@Sun.COM
17679540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(&vrp->oplock));
17689540SJoost.Mulders@Sun.COM
17699540SJoost.Mulders@Sun.COM /*
17709540SJoost.Mulders@Sun.COM * Allocate DMA buffers for RX.
17719540SJoost.Mulders@Sun.COM */
17729540SJoost.Mulders@Sun.COM if (vr_rxring_init(vrp) != VR_SUCCESS) {
17739540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "vr_rxring_init() failed");
17749540SJoost.Mulders@Sun.COM return (ENOMEM);
17759540SJoost.Mulders@Sun.COM }
17769540SJoost.Mulders@Sun.COM
17779540SJoost.Mulders@Sun.COM /*
17789540SJoost.Mulders@Sun.COM * Allocate DMA buffers for TX.
17799540SJoost.Mulders@Sun.COM */
17809540SJoost.Mulders@Sun.COM if (vr_txring_init(vrp) != VR_SUCCESS) {
17819540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "vr_txring_init() failed");
17829540SJoost.Mulders@Sun.COM vr_rxring_fini(vrp);
17839540SJoost.Mulders@Sun.COM return (ENOMEM);
17849540SJoost.Mulders@Sun.COM }
17859540SJoost.Mulders@Sun.COM
17869540SJoost.Mulders@Sun.COM /*
17879540SJoost.Mulders@Sun.COM * Changes of the chip specific registers as done in VIA's fet driver
17889540SJoost.Mulders@Sun.COM * These bits are not in the datasheet and controlled by vr_chip_info.
17899540SJoost.Mulders@Sun.COM */
17909540SJoost.Mulders@Sun.COM pci_mode = VR_GET8(vrp->acc_reg, VR_MODE2);
17919540SJoost.Mulders@Sun.COM if ((vrp->chip.info.bugs & VR_BUG_NEEDMODE10T) != 0)
17929540SJoost.Mulders@Sun.COM pci_mode |= VR_MODE2_MODE10T;
17939540SJoost.Mulders@Sun.COM
17949540SJoost.Mulders@Sun.COM if ((vrp->chip.info.bugs & VR_BUG_NEEDMODE2PCEROPT) != 0)
17959540SJoost.Mulders@Sun.COM pci_mode |= VR_MODE2_PCEROPT;
17969540SJoost.Mulders@Sun.COM
17979540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_MRDLNMULTIPLE) != 0)
17989540SJoost.Mulders@Sun.COM pci_mode |= VR_MODE2_MRDPL;
17999540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MODE2, pci_mode);
18009540SJoost.Mulders@Sun.COM
18019540SJoost.Mulders@Sun.COM pci_mode = VR_GET8(vrp->acc_reg, VR_MODE3);
18029540SJoost.Mulders@Sun.COM if ((vrp->chip.info.bugs & VR_BUG_NEEDMIION) != 0)
18039540SJoost.Mulders@Sun.COM pci_mode |= VR_MODE3_MIION;
18049540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MODE3, pci_mode);
18059540SJoost.Mulders@Sun.COM
18069540SJoost.Mulders@Sun.COM /*
18079540SJoost.Mulders@Sun.COM * RX: Accept broadcast packets.
18089540SJoost.Mulders@Sun.COM */
18099540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTBROAD);
18109540SJoost.Mulders@Sun.COM
18119540SJoost.Mulders@Sun.COM /*
18129540SJoost.Mulders@Sun.COM * RX: Start DMA when there are 256 bytes in the FIFO.
18139540SJoost.Mulders@Sun.COM */
18149540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_FIFO_THRESHOLD_BITS,
18159540SJoost.Mulders@Sun.COM VR_RXCFG_FIFO_THRESHOLD_256);
18169540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_BCR0, VR_BCR0_RX_FIFO_THRESHOLD_BITS,
18179540SJoost.Mulders@Sun.COM VR_BCR0_RX_FIFO_THRESHOLD_256);
18189540SJoost.Mulders@Sun.COM
18199540SJoost.Mulders@Sun.COM /*
18209540SJoost.Mulders@Sun.COM * TX: Start transmit when there are 256 bytes in the FIFO.
18219540SJoost.Mulders@Sun.COM */
18229540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_TXCFG, VR_TXCFG_FIFO_THRESHOLD_BITS,
18239540SJoost.Mulders@Sun.COM VR_TXCFG_FIFO_THRESHOLD_256);
18249540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_BCR1, VR_BCR1_TX_FIFO_THRESHOLD_BITS,
18259540SJoost.Mulders@Sun.COM VR_BCR1_TX_FIFO_THRESHOLD_256);
18269540SJoost.Mulders@Sun.COM
18279540SJoost.Mulders@Sun.COM /*
18289540SJoost.Mulders@Sun.COM * Burst transfers up to 256 bytes.
18299540SJoost.Mulders@Sun.COM */
18309540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_BCR0, VR_BCR0_DMABITS, VR_BCR0_DMA256);
18319540SJoost.Mulders@Sun.COM
18329540SJoost.Mulders@Sun.COM /*
18339540SJoost.Mulders@Sun.COM * Disable TX autopolling as it is bad for RX performance
18349540SJoost.Mulders@Sun.COM * I assume this is because the RX process finds the bus often occupied
18359540SJoost.Mulders@Sun.COM * by the polling process.
18369540SJoost.Mulders@Sun.COM */
18379540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_NOAUTOPOLL);
18389540SJoost.Mulders@Sun.COM
18399540SJoost.Mulders@Sun.COM /*
18409540SJoost.Mulders@Sun.COM * Honor the PCI latency timer if it is reasonable.
18419540SJoost.Mulders@Sun.COM */
18429540SJoost.Mulders@Sun.COM pci_latency = VR_GET8(vrp->acc_cfg, PCI_CONF_LATENCY_TIMER);
18439540SJoost.Mulders@Sun.COM if (pci_latency != 0 && pci_latency != 0xFF)
18449540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_LATENCYTIMER);
18459540SJoost.Mulders@Sun.COM else
18469540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_LATENCYTIMER);
18479540SJoost.Mulders@Sun.COM
18489540SJoost.Mulders@Sun.COM /*
18499540SJoost.Mulders@Sun.COM * Ensure that VLAN filtering is off, because this strips the tag.
18509540SJoost.Mulders@Sun.COM */
18519540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_VLANTAGGING) != 0) {
18529540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_BCR1, VR_BCR1_VLANFILTER);
18539540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_TXCFG, VR_TXCFG_8021PQ_EN);
18549540SJoost.Mulders@Sun.COM }
18559540SJoost.Mulders@Sun.COM
18569540SJoost.Mulders@Sun.COM /*
18579540SJoost.Mulders@Sun.COM * Clear the CAM filter.
18589540SJoost.Mulders@Sun.COM */
18599540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_CAMSUPPORT) != 0) {
18609540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_ENABLE);
18619540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_CAM_MASK, 0);
18629540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE);
18639540SJoost.Mulders@Sun.COM
18649540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
18659540SJoost.Mulders@Sun.COM VR_CAM_CTRL_ENABLE|VR_CAM_CTRL_SELECT_VLAN);
18669540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_VCAM0, 0);
18679540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_VCAM1, 0);
18689540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_WRITE);
18699540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_CAM_MASK, 1);
18709540SJoost.Mulders@Sun.COM drv_usecwait(2);
18719540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE);
18729540SJoost.Mulders@Sun.COM }
18739540SJoost.Mulders@Sun.COM
18749540SJoost.Mulders@Sun.COM /*
18759540SJoost.Mulders@Sun.COM * Give the start addresses of the descriptor rings to the DMA
18769540SJoost.Mulders@Sun.COM * controller on the MAC.
18779540SJoost.Mulders@Sun.COM */
18789540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_RXADDR, vrp->rx.rp->paddr);
18799540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_TXADDR, vrp->tx.wp->paddr);
18809540SJoost.Mulders@Sun.COM
18819540SJoost.Mulders@Sun.COM /*
18829540SJoost.Mulders@Sun.COM * We don't use the additionally invented interrupt ICR1 register,
18839540SJoost.Mulders@Sun.COM * so make sure these are disabled.
18849540SJoost.Mulders@Sun.COM */
18859540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_ISR1, 0xFF);
18869540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_ICR1, 0);
18879540SJoost.Mulders@Sun.COM
18889540SJoost.Mulders@Sun.COM /*
18899540SJoost.Mulders@Sun.COM * Enable interrupts.
18909540SJoost.Mulders@Sun.COM */
18919540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_ISR0, 0xFFFF);
18929540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_ICR0, VR_ICR0_CFG);
18939540SJoost.Mulders@Sun.COM
18949540SJoost.Mulders@Sun.COM /*
18959540SJoost.Mulders@Sun.COM * Enable the DMA controller.
18969540SJoost.Mulders@Sun.COM */
18979540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_GO);
18989540SJoost.Mulders@Sun.COM
18999540SJoost.Mulders@Sun.COM /*
19009540SJoost.Mulders@Sun.COM * Configure the link. Rely on the link change interrupt for getting
19019540SJoost.Mulders@Sun.COM * the link state into the driver.
19029540SJoost.Mulders@Sun.COM */
19039540SJoost.Mulders@Sun.COM vr_link_init(vrp);
19049540SJoost.Mulders@Sun.COM
19059540SJoost.Mulders@Sun.COM /*
19069540SJoost.Mulders@Sun.COM * Set the software view on the state to 'running'.
19079540SJoost.Mulders@Sun.COM */
19089540SJoost.Mulders@Sun.COM vrp->chip.state = CHIPSTATE_RUNNING;
19099540SJoost.Mulders@Sun.COM return (0);
19109540SJoost.Mulders@Sun.COM }
19119540SJoost.Mulders@Sun.COM
19129540SJoost.Mulders@Sun.COM /*
19139540SJoost.Mulders@Sun.COM * Stop DMA and interrupts.
19149540SJoost.Mulders@Sun.COM */
19159540SJoost.Mulders@Sun.COM static int
vr_stop(vr_t * vrp)19169540SJoost.Mulders@Sun.COM vr_stop(vr_t *vrp)
19179540SJoost.Mulders@Sun.COM {
19189540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(&vrp->oplock));
19199540SJoost.Mulders@Sun.COM
19209540SJoost.Mulders@Sun.COM /*
19219540SJoost.Mulders@Sun.COM * Stop interrupts.
19229540SJoost.Mulders@Sun.COM */
19239540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_ICR0, 0);
19249540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_ICR1, 0);
19259540SJoost.Mulders@Sun.COM
19269540SJoost.Mulders@Sun.COM /*
19279540SJoost.Mulders@Sun.COM * Stop DMA.
19289540SJoost.Mulders@Sun.COM */
19299540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CTRL0, VR_CTRL0_DMA_STOP);
19309540SJoost.Mulders@Sun.COM
19319540SJoost.Mulders@Sun.COM /*
19329540SJoost.Mulders@Sun.COM * Set the software view on the state to stopped.
19339540SJoost.Mulders@Sun.COM */
19349540SJoost.Mulders@Sun.COM vrp->chip.state = CHIPSTATE_STOPPED;
19359540SJoost.Mulders@Sun.COM
19369540SJoost.Mulders@Sun.COM /*
19379540SJoost.Mulders@Sun.COM * Remove DMA buffers from the rings.
19389540SJoost.Mulders@Sun.COM */
19399540SJoost.Mulders@Sun.COM vr_rxring_fini(vrp);
19409540SJoost.Mulders@Sun.COM vr_txring_fini(vrp);
19419540SJoost.Mulders@Sun.COM return (0);
19429540SJoost.Mulders@Sun.COM }
19439540SJoost.Mulders@Sun.COM
19449540SJoost.Mulders@Sun.COM int
vr_mac_start(void * p)19459540SJoost.Mulders@Sun.COM vr_mac_start(void *p)
19469540SJoost.Mulders@Sun.COM {
19479540SJoost.Mulders@Sun.COM vr_t *vrp;
19489540SJoost.Mulders@Sun.COM int rc;
19499540SJoost.Mulders@Sun.COM
19509540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
19519540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
19529540SJoost.Mulders@Sun.COM
19539540SJoost.Mulders@Sun.COM /*
19549540SJoost.Mulders@Sun.COM * Reset the card.
19559540SJoost.Mulders@Sun.COM */
19569540SJoost.Mulders@Sun.COM vr_reset(vrp);
19579540SJoost.Mulders@Sun.COM
19589540SJoost.Mulders@Sun.COM /*
19599540SJoost.Mulders@Sun.COM * Prepare and enable the card.
19609540SJoost.Mulders@Sun.COM */
19619540SJoost.Mulders@Sun.COM rc = vr_start(vrp);
19629540SJoost.Mulders@Sun.COM
19639540SJoost.Mulders@Sun.COM /*
19649540SJoost.Mulders@Sun.COM * Configure a cyclic function to keep the card & driver from diverting.
19659540SJoost.Mulders@Sun.COM */
19669540SJoost.Mulders@Sun.COM vrp->periodic_id =
19679540SJoost.Mulders@Sun.COM ddi_periodic_add(vr_periodic, vrp, VR_CHECK_INTERVAL, DDI_IPL_0);
19689540SJoost.Mulders@Sun.COM
19699540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
19709540SJoost.Mulders@Sun.COM return (rc);
19719540SJoost.Mulders@Sun.COM }
19729540SJoost.Mulders@Sun.COM
19739540SJoost.Mulders@Sun.COM void
vr_mac_stop(void * p)19749540SJoost.Mulders@Sun.COM vr_mac_stop(void *p)
19759540SJoost.Mulders@Sun.COM {
19769540SJoost.Mulders@Sun.COM vr_t *vrp = p;
19779540SJoost.Mulders@Sun.COM
19789540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
19799540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
19809540SJoost.Mulders@Sun.COM
19819540SJoost.Mulders@Sun.COM /*
19829540SJoost.Mulders@Sun.COM * Stop the device.
19839540SJoost.Mulders@Sun.COM */
19849540SJoost.Mulders@Sun.COM (void) vr_stop(vrp);
19859540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
19869540SJoost.Mulders@Sun.COM
19879540SJoost.Mulders@Sun.COM /*
19889540SJoost.Mulders@Sun.COM * Remove the cyclic from the system.
19899540SJoost.Mulders@Sun.COM */
19909540SJoost.Mulders@Sun.COM ddi_periodic_delete(vrp->periodic_id);
19919540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
19929540SJoost.Mulders@Sun.COM }
19939540SJoost.Mulders@Sun.COM
19949540SJoost.Mulders@Sun.COM /*
19959540SJoost.Mulders@Sun.COM * Add or remove a multicast address to/from the filter
19969540SJoost.Mulders@Sun.COM *
19979540SJoost.Mulders@Sun.COM * From the 21143 manual:
19989540SJoost.Mulders@Sun.COM * The 21143 can store 512 bits serving as hash bucket heads, and one physical
19999540SJoost.Mulders@Sun.COM * 48-bit Ethernet address. Incoming frames with multicast destination
20009540SJoost.Mulders@Sun.COM * addresses are subjected to imperfect filtering. Frames with physical
20019540SJoost.Mulders@Sun.COM * destination addresses are checked against the single physical address.
20029540SJoost.Mulders@Sun.COM * For any incoming frame with a multicast destination address, the 21143
20039540SJoost.Mulders@Sun.COM * applies the standard Ethernet cyclic redundancy check (CRC) function to the
20049540SJoost.Mulders@Sun.COM * first 6 bytes containing the destination address, then it uses the most
20059540SJoost.Mulders@Sun.COM * significant 9 bits of the result as a bit index into the table. If the
20069540SJoost.Mulders@Sun.COM * indexed bit is set, the frame is accepted. If the bit is cleared, the frame
20079540SJoost.Mulders@Sun.COM * is rejected. This filtering mode is called imperfect because multicast
20089540SJoost.Mulders@Sun.COM * frames not addressed to this station may slip through, but it still
20099540SJoost.Mulders@Sun.COM * decreases the number of frames that the host can receive.
20109540SJoost.Mulders@Sun.COM * I assume the above is also the way the VIA chips work. There's not a single
20119540SJoost.Mulders@Sun.COM * word about the multicast filter in the datasheet.
20129540SJoost.Mulders@Sun.COM *
20139540SJoost.Mulders@Sun.COM * Another word on the CAM filter on VT6105M controllers:
20149540SJoost.Mulders@Sun.COM * The VT6105M has content addressable memory which can be used for perfect
20159540SJoost.Mulders@Sun.COM * filtering of 32 multicast addresses and a few VLAN id's
20169540SJoost.Mulders@Sun.COM *
20179540SJoost.Mulders@Sun.COM * I think it works like this: When the controller receives a multicast
20189540SJoost.Mulders@Sun.COM * address, it looks up the address using CAM. When it is found, it takes the
20199540SJoost.Mulders@Sun.COM * matching cell address (index) and compares this to the bit position in the
20209540SJoost.Mulders@Sun.COM * cam mask. If the bit is set, the packet is passed up. If CAM lookup does not
20219540SJoost.Mulders@Sun.COM * result in a match, the packet is filtered using the hash based filter,
20229540SJoost.Mulders@Sun.COM * if that matches, the packet is passed up and dropped otherwise
20239540SJoost.Mulders@Sun.COM * Also, there's not a single word in the datasheet on how this cam is supposed
20249540SJoost.Mulders@Sun.COM * to work ...
20259540SJoost.Mulders@Sun.COM */
20269540SJoost.Mulders@Sun.COM int
vr_mac_set_multicast(void * p,boolean_t add,const uint8_t * mca)20279540SJoost.Mulders@Sun.COM vr_mac_set_multicast(void *p, boolean_t add, const uint8_t *mca)
20289540SJoost.Mulders@Sun.COM {
20299540SJoost.Mulders@Sun.COM vr_t *vrp;
20309540SJoost.Mulders@Sun.COM uint32_t crc_index;
20319540SJoost.Mulders@Sun.COM int32_t cam_index;
20329540SJoost.Mulders@Sun.COM uint32_t cam_mask;
20339540SJoost.Mulders@Sun.COM boolean_t use_hash_filter;
20349540SJoost.Mulders@Sun.COM ether_addr_t taddr;
20359540SJoost.Mulders@Sun.COM uint32_t a;
20369540SJoost.Mulders@Sun.COM
20379540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
20389540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
20399540SJoost.Mulders@Sun.COM mutex_enter(&vrp->intrlock);
20409540SJoost.Mulders@Sun.COM use_hash_filter = B_FALSE;
20419540SJoost.Mulders@Sun.COM
20429540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_CAMSUPPORT) != 0) {
20439540SJoost.Mulders@Sun.COM /*
20449540SJoost.Mulders@Sun.COM * Program the perfect filter.
20459540SJoost.Mulders@Sun.COM */
20469540SJoost.Mulders@Sun.COM cam_mask = VR_GET32(vrp->acc_reg, VR_CAM_MASK);
20479540SJoost.Mulders@Sun.COM if (add == B_TRUE) {
20489540SJoost.Mulders@Sun.COM /*
20499540SJoost.Mulders@Sun.COM * Get index of first empty slot.
20509540SJoost.Mulders@Sun.COM */
20519540SJoost.Mulders@Sun.COM bzero(&taddr, sizeof (taddr));
20529540SJoost.Mulders@Sun.COM cam_index = vr_cam_index(vrp, taddr);
20539540SJoost.Mulders@Sun.COM if (cam_index != -1) {
20549540SJoost.Mulders@Sun.COM /*
20559540SJoost.Mulders@Sun.COM * Add address at cam_index.
20569540SJoost.Mulders@Sun.COM */
20579540SJoost.Mulders@Sun.COM cam_mask |= (1 << cam_index);
20589540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
20599540SJoost.Mulders@Sun.COM VR_CAM_CTRL_ENABLE);
20609540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_ADDR, cam_index);
20619540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_CAM_MASK, cam_mask);
20629540SJoost.Mulders@Sun.COM for (a = 0; a < ETHERADDRL; a++) {
20639540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg,
20649540SJoost.Mulders@Sun.COM VR_MCAM0 + a, mca[a]);
20659540SJoost.Mulders@Sun.COM }
20669540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
20679540SJoost.Mulders@Sun.COM VR_CAM_CTRL_WRITE);
20689540SJoost.Mulders@Sun.COM drv_usecwait(2);
20699540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
20709540SJoost.Mulders@Sun.COM VR_CAM_CTRL_DONE);
20719540SJoost.Mulders@Sun.COM } else {
20729540SJoost.Mulders@Sun.COM /*
20739540SJoost.Mulders@Sun.COM * No free CAM slots available
20749540SJoost.Mulders@Sun.COM * Add mca to the imperfect filter.
20759540SJoost.Mulders@Sun.COM */
20769540SJoost.Mulders@Sun.COM use_hash_filter = B_TRUE;
20779540SJoost.Mulders@Sun.COM }
20789540SJoost.Mulders@Sun.COM } else {
20799540SJoost.Mulders@Sun.COM /*
20809540SJoost.Mulders@Sun.COM * Find the index of the entry to remove
20819540SJoost.Mulders@Sun.COM * If the entry was not found (-1), the addition was
20829540SJoost.Mulders@Sun.COM * probably done when the table was full.
20839540SJoost.Mulders@Sun.COM */
20849540SJoost.Mulders@Sun.COM cam_index = vr_cam_index(vrp, mca);
20859540SJoost.Mulders@Sun.COM if (cam_index != -1) {
20869540SJoost.Mulders@Sun.COM /*
20879540SJoost.Mulders@Sun.COM * Disable the corresponding mask bit.
20889540SJoost.Mulders@Sun.COM */
20899540SJoost.Mulders@Sun.COM cam_mask &= ~(1 << cam_index);
20909540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
20919540SJoost.Mulders@Sun.COM VR_CAM_CTRL_ENABLE);
20929540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_CAM_MASK, cam_mask);
20939540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL,
20949540SJoost.Mulders@Sun.COM VR_CAM_CTRL_DONE);
20959540SJoost.Mulders@Sun.COM } else {
20969540SJoost.Mulders@Sun.COM /*
20979540SJoost.Mulders@Sun.COM * The entry to be removed was not found
20989540SJoost.Mulders@Sun.COM * The likely cause is that the CAM was full
20999540SJoost.Mulders@Sun.COM * during addition. The entry is added to the
21009540SJoost.Mulders@Sun.COM * hash filter in that case and needs to be
21019540SJoost.Mulders@Sun.COM * removed there too.
21029540SJoost.Mulders@Sun.COM */
21039540SJoost.Mulders@Sun.COM use_hash_filter = B_TRUE;
21049540SJoost.Mulders@Sun.COM }
21059540SJoost.Mulders@Sun.COM }
21069540SJoost.Mulders@Sun.COM } else {
21079540SJoost.Mulders@Sun.COM /*
21089540SJoost.Mulders@Sun.COM * No CAM in the MAC, thus we need the hash filter.
21099540SJoost.Mulders@Sun.COM */
21109540SJoost.Mulders@Sun.COM use_hash_filter = B_TRUE;
21119540SJoost.Mulders@Sun.COM }
21129540SJoost.Mulders@Sun.COM
21139540SJoost.Mulders@Sun.COM if (use_hash_filter == B_TRUE) {
21149540SJoost.Mulders@Sun.COM /*
21159540SJoost.Mulders@Sun.COM * Get the CRC-32 of the multicast address
21169540SJoost.Mulders@Sun.COM * The card uses the "MSB first" direction when calculating the
21179540SJoost.Mulders@Sun.COM * the CRC. This is odd because ethernet is "LSB first"
21189540SJoost.Mulders@Sun.COM * We have to use that "big endian" approach as well.
21199540SJoost.Mulders@Sun.COM */
21209540SJoost.Mulders@Sun.COM crc_index = ether_crc_be(mca) >> (32 - 6);
21219540SJoost.Mulders@Sun.COM if (add == B_TRUE) {
21229540SJoost.Mulders@Sun.COM /*
21239540SJoost.Mulders@Sun.COM * Turn bit[crc_index] on.
21249540SJoost.Mulders@Sun.COM */
21259540SJoost.Mulders@Sun.COM if (crc_index < 32)
21269540SJoost.Mulders@Sun.COM vrp->mhash0 |= (1 << crc_index);
21279540SJoost.Mulders@Sun.COM else
21289540SJoost.Mulders@Sun.COM vrp->mhash1 |= (1 << (crc_index - 32));
21299540SJoost.Mulders@Sun.COM } else {
21309540SJoost.Mulders@Sun.COM /*
21319540SJoost.Mulders@Sun.COM * Turn bit[crc_index] off.
21329540SJoost.Mulders@Sun.COM */
21339540SJoost.Mulders@Sun.COM if (crc_index < 32)
21349540SJoost.Mulders@Sun.COM vrp->mhash0 &= ~(0 << crc_index);
21359540SJoost.Mulders@Sun.COM else
21369540SJoost.Mulders@Sun.COM vrp->mhash1 &= ~(0 << (crc_index - 32));
21379540SJoost.Mulders@Sun.COM }
21389540SJoost.Mulders@Sun.COM
21399540SJoost.Mulders@Sun.COM /*
21409540SJoost.Mulders@Sun.COM * When not promiscuous write the filter now. When promiscuous,
21419540SJoost.Mulders@Sun.COM * the filter is open and will be written when promiscuous ends.
21429540SJoost.Mulders@Sun.COM */
21439540SJoost.Mulders@Sun.COM if (vrp->promisc == B_FALSE) {
21449540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR0, vrp->mhash0);
21459540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR1, vrp->mhash1);
21469540SJoost.Mulders@Sun.COM }
21479540SJoost.Mulders@Sun.COM }
21489540SJoost.Mulders@Sun.COM
21499540SJoost.Mulders@Sun.COM /*
21509540SJoost.Mulders@Sun.COM * Enable/disable multicast receivements based on mcount.
21519540SJoost.Mulders@Sun.COM */
21529540SJoost.Mulders@Sun.COM if (add == B_TRUE)
21539540SJoost.Mulders@Sun.COM vrp->mcount++;
21549540SJoost.Mulders@Sun.COM else if (vrp->mcount != 0)
21559540SJoost.Mulders@Sun.COM vrp->mcount --;
21569540SJoost.Mulders@Sun.COM if (vrp->mcount != 0)
21579540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTMULTI);
21589540SJoost.Mulders@Sun.COM else
21599540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_RXCFG, VR_RXCFG_ACCEPTMULTI);
21609540SJoost.Mulders@Sun.COM
21619540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
21629540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
21639540SJoost.Mulders@Sun.COM return (0);
21649540SJoost.Mulders@Sun.COM }
21659540SJoost.Mulders@Sun.COM
21669540SJoost.Mulders@Sun.COM /*
21679540SJoost.Mulders@Sun.COM * Calculate the CRC32 for 6 bytes of multicast address in MSB(it) first order.
21689540SJoost.Mulders@Sun.COM * The MSB first order is a bit odd because Ethernet standard is LSB first
21699540SJoost.Mulders@Sun.COM */
21709540SJoost.Mulders@Sun.COM static uint32_t
ether_crc_be(const uint8_t * data)21719540SJoost.Mulders@Sun.COM ether_crc_be(const uint8_t *data)
21729540SJoost.Mulders@Sun.COM {
21739540SJoost.Mulders@Sun.COM uint32_t crc = (uint32_t)0xFFFFFFFFU;
21749540SJoost.Mulders@Sun.COM uint32_t carry;
21759540SJoost.Mulders@Sun.COM uint32_t bit;
21769540SJoost.Mulders@Sun.COM uint32_t length;
21779540SJoost.Mulders@Sun.COM uint8_t c;
21789540SJoost.Mulders@Sun.COM
21799540SJoost.Mulders@Sun.COM for (length = 0; length < ETHERADDRL; length++) {
21809540SJoost.Mulders@Sun.COM c = data[length];
21819540SJoost.Mulders@Sun.COM for (bit = 0; bit < 8; bit++) {
21829540SJoost.Mulders@Sun.COM carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01);
21839540SJoost.Mulders@Sun.COM crc <<= 1;
21849540SJoost.Mulders@Sun.COM c >>= 1;
21859540SJoost.Mulders@Sun.COM if (carry)
21869540SJoost.Mulders@Sun.COM crc = (crc ^ 0x04C11DB6) | carry;
21879540SJoost.Mulders@Sun.COM }
21889540SJoost.Mulders@Sun.COM }
21899540SJoost.Mulders@Sun.COM return (crc);
21909540SJoost.Mulders@Sun.COM }
21919540SJoost.Mulders@Sun.COM
21929540SJoost.Mulders@Sun.COM
21939540SJoost.Mulders@Sun.COM /*
21949540SJoost.Mulders@Sun.COM * Return the CAM index (base 0) of maddr or -1 if maddr is not found
21959540SJoost.Mulders@Sun.COM * If maddr is 0, return the index of an empty slot in CAM or -1 when no free
21969540SJoost.Mulders@Sun.COM * slots available.
21979540SJoost.Mulders@Sun.COM */
21989540SJoost.Mulders@Sun.COM static int32_t
vr_cam_index(vr_t * vrp,const uint8_t * maddr)21999540SJoost.Mulders@Sun.COM vr_cam_index(vr_t *vrp, const uint8_t *maddr)
22009540SJoost.Mulders@Sun.COM {
22019540SJoost.Mulders@Sun.COM ether_addr_t taddr;
22029540SJoost.Mulders@Sun.COM int32_t index;
22039540SJoost.Mulders@Sun.COM uint32_t mask;
22049540SJoost.Mulders@Sun.COM uint32_t a;
22059540SJoost.Mulders@Sun.COM
22069540SJoost.Mulders@Sun.COM bzero(&taddr, sizeof (taddr));
22079540SJoost.Mulders@Sun.COM
22089540SJoost.Mulders@Sun.COM /*
22099540SJoost.Mulders@Sun.COM * Read the CAM mask from the controller.
22109540SJoost.Mulders@Sun.COM */
22119540SJoost.Mulders@Sun.COM mask = VR_GET32(vrp->acc_reg, VR_CAM_MASK);
22129540SJoost.Mulders@Sun.COM
22139540SJoost.Mulders@Sun.COM /*
22149540SJoost.Mulders@Sun.COM * If maddr is 0, return the first unused slot or -1 for no unused.
22159540SJoost.Mulders@Sun.COM */
22169540SJoost.Mulders@Sun.COM if (bcmp(maddr, taddr, ETHERADDRL) == 0) {
22179540SJoost.Mulders@Sun.COM /*
22189540SJoost.Mulders@Sun.COM * Look for the first unused position in mask.
22199540SJoost.Mulders@Sun.COM */
22209540SJoost.Mulders@Sun.COM for (index = 0; index < VR_CAM_SZ; index++) {
22219540SJoost.Mulders@Sun.COM if (((mask >> index) & 1) == 0)
22229540SJoost.Mulders@Sun.COM return (index);
22239540SJoost.Mulders@Sun.COM }
22249540SJoost.Mulders@Sun.COM return (-1);
22259540SJoost.Mulders@Sun.COM } else {
22269540SJoost.Mulders@Sun.COM /*
22279540SJoost.Mulders@Sun.COM * Look for maddr in CAM.
22289540SJoost.Mulders@Sun.COM */
22299540SJoost.Mulders@Sun.COM for (index = 0; index < VR_CAM_SZ; index++) {
22309540SJoost.Mulders@Sun.COM /* Look at enabled entries only */
22319540SJoost.Mulders@Sun.COM if (((mask >> index) & 1) == 0)
22329540SJoost.Mulders@Sun.COM continue;
22339540SJoost.Mulders@Sun.COM
22349540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_ENABLE);
22359540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_ADDR, index);
22369540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_READ);
22379540SJoost.Mulders@Sun.COM drv_usecwait(2);
22389540SJoost.Mulders@Sun.COM for (a = 0; a < ETHERADDRL; a++)
22399540SJoost.Mulders@Sun.COM taddr[a] = VR_GET8(vrp->acc_reg, VR_MCAM0 + a);
22409540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_CAM_CTRL, VR_CAM_CTRL_DONE);
22419540SJoost.Mulders@Sun.COM if (bcmp(maddr, taddr, ETHERADDRL) == 0)
22429540SJoost.Mulders@Sun.COM return (index);
22439540SJoost.Mulders@Sun.COM }
22449540SJoost.Mulders@Sun.COM }
22459540SJoost.Mulders@Sun.COM return (-1);
22469540SJoost.Mulders@Sun.COM }
22479540SJoost.Mulders@Sun.COM
22489540SJoost.Mulders@Sun.COM /*
22499540SJoost.Mulders@Sun.COM * Set promiscuous mode on or off.
22509540SJoost.Mulders@Sun.COM */
22519540SJoost.Mulders@Sun.COM int
vr_mac_set_promisc(void * p,boolean_t promiscflag)22529540SJoost.Mulders@Sun.COM vr_mac_set_promisc(void *p, boolean_t promiscflag)
22539540SJoost.Mulders@Sun.COM {
22549540SJoost.Mulders@Sun.COM vr_t *vrp;
22559540SJoost.Mulders@Sun.COM uint8_t rxcfg;
22569540SJoost.Mulders@Sun.COM
22579540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
22589540SJoost.Mulders@Sun.COM
22599540SJoost.Mulders@Sun.COM mutex_enter(&vrp->intrlock);
22609540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
22619540SJoost.Mulders@Sun.COM mutex_enter(&vrp->tx.lock);
22629540SJoost.Mulders@Sun.COM
22639540SJoost.Mulders@Sun.COM /*
22649540SJoost.Mulders@Sun.COM * Get current receive configuration.
22659540SJoost.Mulders@Sun.COM */
22669540SJoost.Mulders@Sun.COM rxcfg = VR_GET8(vrp->acc_reg, VR_RXCFG);
22679540SJoost.Mulders@Sun.COM vrp->promisc = promiscflag;
22689540SJoost.Mulders@Sun.COM
22699540SJoost.Mulders@Sun.COM if (promiscflag == B_TRUE) {
22709540SJoost.Mulders@Sun.COM /*
22719540SJoost.Mulders@Sun.COM * Enable promiscuous mode and open the multicast filter.
22729540SJoost.Mulders@Sun.COM */
22739540SJoost.Mulders@Sun.COM rxcfg |= (VR_RXCFG_PROMISC | VR_RXCFG_ACCEPTMULTI);
22749540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR0, 0xffffffff);
22759540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR1, 0xffffffff);
22769540SJoost.Mulders@Sun.COM } else {
22779540SJoost.Mulders@Sun.COM /*
22789540SJoost.Mulders@Sun.COM * Restore the multicast filter and disable promiscuous mode.
22799540SJoost.Mulders@Sun.COM */
22809540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR0, vrp->mhash0);
22819540SJoost.Mulders@Sun.COM VR_PUT32(vrp->acc_reg, VR_MAR1, vrp->mhash1);
22829540SJoost.Mulders@Sun.COM rxcfg &= ~VR_RXCFG_PROMISC;
22839540SJoost.Mulders@Sun.COM if (vrp->mcount != 0)
22849540SJoost.Mulders@Sun.COM rxcfg |= VR_RXCFG_ACCEPTMULTI;
22859540SJoost.Mulders@Sun.COM }
22869540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_RXCFG, rxcfg);
22879540SJoost.Mulders@Sun.COM mutex_exit(&vrp->tx.lock);
22889540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
22899540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
22909540SJoost.Mulders@Sun.COM return (0);
22919540SJoost.Mulders@Sun.COM }
22929540SJoost.Mulders@Sun.COM
22939540SJoost.Mulders@Sun.COM int
vr_mac_getstat(void * arg,uint_t stat,uint64_t * val)22949540SJoost.Mulders@Sun.COM vr_mac_getstat(void *arg, uint_t stat, uint64_t *val)
22959540SJoost.Mulders@Sun.COM {
22969540SJoost.Mulders@Sun.COM vr_t *vrp;
22979540SJoost.Mulders@Sun.COM uint64_t v;
22989540SJoost.Mulders@Sun.COM
22999540SJoost.Mulders@Sun.COM vrp = (void *) arg;
23009540SJoost.Mulders@Sun.COM
23019540SJoost.Mulders@Sun.COM switch (stat) {
23029540SJoost.Mulders@Sun.COM default:
23039540SJoost.Mulders@Sun.COM return (ENOTSUP);
23049540SJoost.Mulders@Sun.COM
23059540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_100T4:
23069540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_T4) != 0;
23079540SJoost.Mulders@Sun.COM break;
23089540SJoost.Mulders@Sun.COM
23099540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_100FDX:
23109540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_TX_FD) != 0;
23119540SJoost.Mulders@Sun.COM break;
23129540SJoost.Mulders@Sun.COM
23139540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_100HDX:
23149540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_ABILITY_100BASE_TX) != 0;
23159540SJoost.Mulders@Sun.COM break;
23169540SJoost.Mulders@Sun.COM
23179540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_10FDX:
23189540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_ABILITY_10BASE_T_FD) != 0;
23199540SJoost.Mulders@Sun.COM break;
23209540SJoost.Mulders@Sun.COM
23219540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_10HDX:
23229540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_ABILITY_10BASE_T) != 0;
23239540SJoost.Mulders@Sun.COM break;
23249540SJoost.Mulders@Sun.COM
23259540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_ASMPAUSE:
23269540SJoost.Mulders@Sun.COM v = 0;
23279540SJoost.Mulders@Sun.COM break;
23289540SJoost.Mulders@Sun.COM
23299540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_AUTONEG:
23309540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.control & MII_CONTROL_ANE) != 0;
23319540SJoost.Mulders@Sun.COM break;
23329540SJoost.Mulders@Sun.COM
23339540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_CAP_PAUSE:
23349860Sgdamore@opensolaris.org v = (vrp->chip.mii.anadv & MII_ABILITY_PAUSE) != 0;
23359540SJoost.Mulders@Sun.COM break;
23369540SJoost.Mulders@Sun.COM
23379540SJoost.Mulders@Sun.COM case ETHER_STAT_ADV_REMFAULT:
23389540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anadv & MII_AN_ADVERT_REMFAULT) != 0;
23399540SJoost.Mulders@Sun.COM break;
23409540SJoost.Mulders@Sun.COM
23419540SJoost.Mulders@Sun.COM case ETHER_STAT_ALIGN_ERRORS:
23429540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_align_errors;
23439540SJoost.Mulders@Sun.COM break;
23449540SJoost.Mulders@Sun.COM
23459540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_100T4:
23469540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_100_BASE_T4) != 0;
23479540SJoost.Mulders@Sun.COM break;
23489540SJoost.Mulders@Sun.COM
23499540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_100FDX:
23509540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_100_BASEX_FD) != 0;
23519540SJoost.Mulders@Sun.COM break;
23529540SJoost.Mulders@Sun.COM
23539540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_100HDX:
23549540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_100_BASEX) != 0;
23559540SJoost.Mulders@Sun.COM break;
23569540SJoost.Mulders@Sun.COM
23579540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_10FDX:
23589540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_10_FD) != 0;
23599540SJoost.Mulders@Sun.COM break;
23609540SJoost.Mulders@Sun.COM
23619540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_10HDX:
23629540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_10) != 0;
23639540SJoost.Mulders@Sun.COM break;
23649540SJoost.Mulders@Sun.COM
23659540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_ASMPAUSE:
23669540SJoost.Mulders@Sun.COM v = 0;
23679540SJoost.Mulders@Sun.COM break;
23689540SJoost.Mulders@Sun.COM
23699540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_AUTONEG:
23709540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_CANAUTONEG) != 0;
23719540SJoost.Mulders@Sun.COM break;
23729540SJoost.Mulders@Sun.COM
23739540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_PAUSE:
23749540SJoost.Mulders@Sun.COM v = 1;
23759540SJoost.Mulders@Sun.COM break;
23769540SJoost.Mulders@Sun.COM
23779540SJoost.Mulders@Sun.COM case ETHER_STAT_CAP_REMFAULT:
23789540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0;
23799540SJoost.Mulders@Sun.COM break;
23809540SJoost.Mulders@Sun.COM
23819540SJoost.Mulders@Sun.COM case ETHER_STAT_CARRIER_ERRORS:
23829540SJoost.Mulders@Sun.COM /*
23839540SJoost.Mulders@Sun.COM * Number of times carrier was lost or never detected on a
23849540SJoost.Mulders@Sun.COM * transmission attempt.
23859540SJoost.Mulders@Sun.COM */
23869540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_carrier_errors;
23879540SJoost.Mulders@Sun.COM break;
23889540SJoost.Mulders@Sun.COM
23899540SJoost.Mulders@Sun.COM case ETHER_STAT_JABBER_ERRORS:
23909540SJoost.Mulders@Sun.COM return (ENOTSUP);
23919540SJoost.Mulders@Sun.COM
23929540SJoost.Mulders@Sun.COM case ETHER_STAT_DEFER_XMTS:
23939540SJoost.Mulders@Sun.COM /*
23949540SJoost.Mulders@Sun.COM * Packets without collisions where first transmit attempt was
23959540SJoost.Mulders@Sun.COM * delayed because the medium was busy.
23969540SJoost.Mulders@Sun.COM */
23979540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_defer_xmts;
23989540SJoost.Mulders@Sun.COM break;
23999540SJoost.Mulders@Sun.COM
24009540SJoost.Mulders@Sun.COM case ETHER_STAT_EX_COLLISIONS:
24019540SJoost.Mulders@Sun.COM /*
24029540SJoost.Mulders@Sun.COM * Frames where excess collisions occurred on transmit, causing
24039540SJoost.Mulders@Sun.COM * transmit failure.
24049540SJoost.Mulders@Sun.COM */
24059540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_ex_collisions;
24069540SJoost.Mulders@Sun.COM break;
24079540SJoost.Mulders@Sun.COM
24089540SJoost.Mulders@Sun.COM case ETHER_STAT_FCS_ERRORS:
24099540SJoost.Mulders@Sun.COM /*
24109540SJoost.Mulders@Sun.COM * Packets received with CRC errors.
24119540SJoost.Mulders@Sun.COM */
24129540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_fcs_errors;
24139540SJoost.Mulders@Sun.COM break;
24149540SJoost.Mulders@Sun.COM
24159540SJoost.Mulders@Sun.COM case ETHER_STAT_FIRST_COLLISIONS:
24169540SJoost.Mulders@Sun.COM /*
24179540SJoost.Mulders@Sun.COM * Packets successfully transmitted with exactly one collision.
24189540SJoost.Mulders@Sun.COM */
24199540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_first_collisions;
24209540SJoost.Mulders@Sun.COM break;
24219540SJoost.Mulders@Sun.COM
24229540SJoost.Mulders@Sun.COM case ETHER_STAT_LINK_ASMPAUSE:
24239540SJoost.Mulders@Sun.COM v = 0;
24249540SJoost.Mulders@Sun.COM break;
24259540SJoost.Mulders@Sun.COM
24269540SJoost.Mulders@Sun.COM case ETHER_STAT_LINK_AUTONEG:
24279540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.control & MII_CONTROL_ANE) != 0 &&
24289540SJoost.Mulders@Sun.COM (vrp->chip.mii.status & MII_STATUS_ANDONE) != 0;
24299540SJoost.Mulders@Sun.COM break;
24309540SJoost.Mulders@Sun.COM
24319540SJoost.Mulders@Sun.COM case ETHER_STAT_LINK_DUPLEX:
24329540SJoost.Mulders@Sun.COM v = vrp->chip.link.duplex;
24339540SJoost.Mulders@Sun.COM break;
24349540SJoost.Mulders@Sun.COM
24359540SJoost.Mulders@Sun.COM case ETHER_STAT_LINK_PAUSE:
24369540SJoost.Mulders@Sun.COM v = vrp->chip.link.flowctrl;
24379540SJoost.Mulders@Sun.COM break;
24389540SJoost.Mulders@Sun.COM
24399540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_100T4:
24409540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_T4) != 0;
24419540SJoost.Mulders@Sun.COM break;
24429540SJoost.Mulders@Sun.COM
24439540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_1000FDX:
24449540SJoost.Mulders@Sun.COM v = 0;
24459540SJoost.Mulders@Sun.COM break;
24469540SJoost.Mulders@Sun.COM
24479540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_1000HDX:
24489540SJoost.Mulders@Sun.COM v = 0;
24499540SJoost.Mulders@Sun.COM break;
24509540SJoost.Mulders@Sun.COM
24519540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_100FDX:
24529540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_TX_FD) != 0;
24539540SJoost.Mulders@Sun.COM break;
24549540SJoost.Mulders@Sun.COM
24559540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_100HDX:
24569540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.lpable & MII_ABILITY_100BASE_TX) != 0;
24579540SJoost.Mulders@Sun.COM break;
24589540SJoost.Mulders@Sun.COM
24599540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_10FDX:
24609540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.lpable & MII_ABILITY_10BASE_T_FD) != 0;
24619540SJoost.Mulders@Sun.COM break;
24629540SJoost.Mulders@Sun.COM
24639540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_10HDX:
24649540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.lpable & MII_ABILITY_10BASE_T) != 0;
24659540SJoost.Mulders@Sun.COM break;
24669540SJoost.Mulders@Sun.COM
24679540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_ASMPAUSE:
24689540SJoost.Mulders@Sun.COM v = 0;
24699540SJoost.Mulders@Sun.COM break;
24709540SJoost.Mulders@Sun.COM
24719540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_AUTONEG:
24729540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.anexp & MII_AN_EXP_LPCANAN) != 0;
24739540SJoost.Mulders@Sun.COM break;
24749540SJoost.Mulders@Sun.COM
24759540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_CAP_PAUSE:
24769860Sgdamore@opensolaris.org v = (vrp->chip.mii.lpable & MII_ABILITY_PAUSE) != 0;
24779540SJoost.Mulders@Sun.COM break;
24789540SJoost.Mulders@Sun.COM
24799540SJoost.Mulders@Sun.COM case ETHER_STAT_LP_REMFAULT:
24809540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0;
24819540SJoost.Mulders@Sun.COM break;
24829540SJoost.Mulders@Sun.COM
24839540SJoost.Mulders@Sun.COM case ETHER_STAT_MACRCV_ERRORS:
24849540SJoost.Mulders@Sun.COM /*
24859540SJoost.Mulders@Sun.COM * Packets received with MAC errors, except align_errors,
24869540SJoost.Mulders@Sun.COM * fcs_errors, and toolong_errors.
24879540SJoost.Mulders@Sun.COM */
24889540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_macrcv_errors;
24899540SJoost.Mulders@Sun.COM break;
24909540SJoost.Mulders@Sun.COM
24919540SJoost.Mulders@Sun.COM case ETHER_STAT_MACXMT_ERRORS:
24929540SJoost.Mulders@Sun.COM /*
24939540SJoost.Mulders@Sun.COM * Packets encountering transmit MAC failures, except carrier
24949540SJoost.Mulders@Sun.COM * and collision failures.
24959540SJoost.Mulders@Sun.COM */
24969540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_macxmt_errors;
24979540SJoost.Mulders@Sun.COM break;
24989540SJoost.Mulders@Sun.COM
24999540SJoost.Mulders@Sun.COM case ETHER_STAT_MULTI_COLLISIONS:
25009540SJoost.Mulders@Sun.COM /*
25019540SJoost.Mulders@Sun.COM * Packets successfully transmitted with multiple collisions.
25029540SJoost.Mulders@Sun.COM */
25039540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_multi_collisions;
25049540SJoost.Mulders@Sun.COM break;
25059540SJoost.Mulders@Sun.COM
25069540SJoost.Mulders@Sun.COM case ETHER_STAT_SQE_ERRORS:
25079540SJoost.Mulders@Sun.COM /*
25089540SJoost.Mulders@Sun.COM * Number of times signal quality error was reported
25099540SJoost.Mulders@Sun.COM * This one is reported by the PHY.
25109540SJoost.Mulders@Sun.COM */
25119540SJoost.Mulders@Sun.COM return (ENOTSUP);
25129540SJoost.Mulders@Sun.COM
25139540SJoost.Mulders@Sun.COM case ETHER_STAT_TOOLONG_ERRORS:
25149540SJoost.Mulders@Sun.COM /*
25159540SJoost.Mulders@Sun.COM * Packets received larger than the maximum permitted length.
25169540SJoost.Mulders@Sun.COM */
25179540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_toolong_errors;
25189540SJoost.Mulders@Sun.COM break;
25199540SJoost.Mulders@Sun.COM
25209540SJoost.Mulders@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS:
25219540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_tooshort_errors;
25229540SJoost.Mulders@Sun.COM break;
25239540SJoost.Mulders@Sun.COM
25249540SJoost.Mulders@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS:
25259540SJoost.Mulders@Sun.COM /*
25269540SJoost.Mulders@Sun.COM * Number of times a transmit collision occurred late
25279540SJoost.Mulders@Sun.COM * (after 512 bit times).
25289540SJoost.Mulders@Sun.COM */
25299540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_tx_late_collisions;
25309540SJoost.Mulders@Sun.COM break;
25319540SJoost.Mulders@Sun.COM
25329540SJoost.Mulders@Sun.COM case ETHER_STAT_XCVR_ADDR:
25339540SJoost.Mulders@Sun.COM /*
25349540SJoost.Mulders@Sun.COM * MII address in the 0 to 31 range of the physical layer
25359540SJoost.Mulders@Sun.COM * device in use for a given Ethernet device.
25369540SJoost.Mulders@Sun.COM */
25379540SJoost.Mulders@Sun.COM v = vrp->chip.phyaddr;
25389540SJoost.Mulders@Sun.COM break;
25399540SJoost.Mulders@Sun.COM
25409540SJoost.Mulders@Sun.COM case ETHER_STAT_XCVR_ID:
25419540SJoost.Mulders@Sun.COM /*
25429540SJoost.Mulders@Sun.COM * MII transceiver manufacturer and device ID.
25439540SJoost.Mulders@Sun.COM */
25449540SJoost.Mulders@Sun.COM v = (vrp->chip.mii.identh << 16) | vrp->chip.mii.identl;
25459540SJoost.Mulders@Sun.COM break;
25469540SJoost.Mulders@Sun.COM
25479540SJoost.Mulders@Sun.COM case ETHER_STAT_XCVR_INUSE:
25489540SJoost.Mulders@Sun.COM v = vrp->chip.link.mau;
25499540SJoost.Mulders@Sun.COM break;
25509540SJoost.Mulders@Sun.COM
25519540SJoost.Mulders@Sun.COM case MAC_STAT_BRDCSTRCV:
25529540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_brdcstrcv;
25539540SJoost.Mulders@Sun.COM break;
25549540SJoost.Mulders@Sun.COM
25559540SJoost.Mulders@Sun.COM case MAC_STAT_BRDCSTXMT:
25569540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_brdcstxmt;
25579540SJoost.Mulders@Sun.COM break;
25589540SJoost.Mulders@Sun.COM
25599540SJoost.Mulders@Sun.COM case MAC_STAT_MULTIXMT:
25609540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_multixmt;
25619540SJoost.Mulders@Sun.COM break;
25629540SJoost.Mulders@Sun.COM
25639540SJoost.Mulders@Sun.COM case MAC_STAT_COLLISIONS:
25649540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_collisions;
25659540SJoost.Mulders@Sun.COM break;
25669540SJoost.Mulders@Sun.COM
25679540SJoost.Mulders@Sun.COM case MAC_STAT_IERRORS:
25689540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_ierrors;
25699540SJoost.Mulders@Sun.COM break;
25709540SJoost.Mulders@Sun.COM
25719540SJoost.Mulders@Sun.COM case MAC_STAT_IFSPEED:
25729540SJoost.Mulders@Sun.COM if (vrp->chip.link.speed == VR_LINK_SPEED_100MBS)
25739540SJoost.Mulders@Sun.COM v = 100 * 1000 * 1000;
25749540SJoost.Mulders@Sun.COM else if (vrp->chip.link.speed == VR_LINK_SPEED_10MBS)
25759540SJoost.Mulders@Sun.COM v = 10 * 1000 * 1000;
25769540SJoost.Mulders@Sun.COM else
25779540SJoost.Mulders@Sun.COM v = 0;
25789540SJoost.Mulders@Sun.COM break;
25799540SJoost.Mulders@Sun.COM
25809540SJoost.Mulders@Sun.COM case MAC_STAT_IPACKETS:
25819540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_ipackets;
25829540SJoost.Mulders@Sun.COM break;
25839540SJoost.Mulders@Sun.COM
25849540SJoost.Mulders@Sun.COM case MAC_STAT_MULTIRCV:
25859540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_multircv;
25869540SJoost.Mulders@Sun.COM break;
25879540SJoost.Mulders@Sun.COM
25889540SJoost.Mulders@Sun.COM case MAC_STAT_NORCVBUF:
25899540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_norcvbuf +=
25909540SJoost.Mulders@Sun.COM VR_GET16(vrp->acc_reg, VR_TALLY_MPA);
25919540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_TALLY_MPA, 0);
25929540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_norcvbuf;
25939540SJoost.Mulders@Sun.COM break;
25949540SJoost.Mulders@Sun.COM
25959540SJoost.Mulders@Sun.COM case MAC_STAT_NOXMTBUF:
25969540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_noxmtbuf;
25979540SJoost.Mulders@Sun.COM break;
25989540SJoost.Mulders@Sun.COM
25999540SJoost.Mulders@Sun.COM case MAC_STAT_OBYTES:
26009540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_obytes;
26019540SJoost.Mulders@Sun.COM break;
26029540SJoost.Mulders@Sun.COM
26039540SJoost.Mulders@Sun.COM case MAC_STAT_OERRORS:
26049540SJoost.Mulders@Sun.COM v = vrp->stats.ether_stat_macxmt_errors +
26059540SJoost.Mulders@Sun.COM vrp->stats.mac_stat_underflows +
26069540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_align_errors +
26079540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_carrier_errors +
26089540SJoost.Mulders@Sun.COM vrp->stats.ether_stat_fcs_errors;
26099540SJoost.Mulders@Sun.COM break;
26109540SJoost.Mulders@Sun.COM
26119540SJoost.Mulders@Sun.COM case MAC_STAT_OPACKETS:
26129540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_opackets;
26139540SJoost.Mulders@Sun.COM break;
26149540SJoost.Mulders@Sun.COM
26159540SJoost.Mulders@Sun.COM case MAC_STAT_RBYTES:
26169540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_rbytes;
26179540SJoost.Mulders@Sun.COM break;
26189540SJoost.Mulders@Sun.COM
26199540SJoost.Mulders@Sun.COM case MAC_STAT_UNKNOWNS:
26209540SJoost.Mulders@Sun.COM /*
26219540SJoost.Mulders@Sun.COM * Isn't this something for the MAC layer to maintain?
26229540SJoost.Mulders@Sun.COM */
26239540SJoost.Mulders@Sun.COM return (ENOTSUP);
26249540SJoost.Mulders@Sun.COM
26259540SJoost.Mulders@Sun.COM case MAC_STAT_UNDERFLOWS:
26269540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_underflows;
26279540SJoost.Mulders@Sun.COM break;
26289540SJoost.Mulders@Sun.COM
26299540SJoost.Mulders@Sun.COM case MAC_STAT_OVERFLOWS:
26309540SJoost.Mulders@Sun.COM v = vrp->stats.mac_stat_overflows;
26319540SJoost.Mulders@Sun.COM break;
26329540SJoost.Mulders@Sun.COM }
26339540SJoost.Mulders@Sun.COM *val = v;
26349540SJoost.Mulders@Sun.COM return (0);
26359540SJoost.Mulders@Sun.COM }
26369540SJoost.Mulders@Sun.COM
26379540SJoost.Mulders@Sun.COM int
vr_mac_set_ether_addr(void * p,const uint8_t * ea)26389540SJoost.Mulders@Sun.COM vr_mac_set_ether_addr(void *p, const uint8_t *ea)
26399540SJoost.Mulders@Sun.COM {
26409540SJoost.Mulders@Sun.COM vr_t *vrp;
26419540SJoost.Mulders@Sun.COM int i;
26429540SJoost.Mulders@Sun.COM
26439540SJoost.Mulders@Sun.COM vrp = (vr_t *)p;
26449540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
26459540SJoost.Mulders@Sun.COM mutex_enter(&vrp->intrlock);
26469540SJoost.Mulders@Sun.COM
26479540SJoost.Mulders@Sun.COM /*
26489540SJoost.Mulders@Sun.COM * Set a new station address.
26499540SJoost.Mulders@Sun.COM */
26509540SJoost.Mulders@Sun.COM for (i = 0; i < ETHERADDRL; i++)
26519540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_ETHERADDR + i, ea[i]);
26529540SJoost.Mulders@Sun.COM
26539540SJoost.Mulders@Sun.COM mutex_exit(&vrp->intrlock);
26549540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
26559540SJoost.Mulders@Sun.COM return (0);
26569540SJoost.Mulders@Sun.COM }
26579540SJoost.Mulders@Sun.COM
26589540SJoost.Mulders@Sun.COM /*
26599540SJoost.Mulders@Sun.COM * Configure the ethernet link according to param and chip.mii.
26609540SJoost.Mulders@Sun.COM */
26619540SJoost.Mulders@Sun.COM static void
vr_link_init(vr_t * vrp)26629540SJoost.Mulders@Sun.COM vr_link_init(vr_t *vrp)
26639540SJoost.Mulders@Sun.COM {
26649540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(&vrp->oplock));
26659540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_ANE) != 0) {
26669540SJoost.Mulders@Sun.COM /*
26679540SJoost.Mulders@Sun.COM * If we do autoneg, ensure restart autoneg is ON.
26689540SJoost.Mulders@Sun.COM */
26699540SJoost.Mulders@Sun.COM vrp->chip.mii.control |= MII_CONTROL_RSAN;
26709540SJoost.Mulders@Sun.COM
26719540SJoost.Mulders@Sun.COM /*
26729540SJoost.Mulders@Sun.COM * The advertisements are prepared by param_init.
26739540SJoost.Mulders@Sun.COM */
26749540SJoost.Mulders@Sun.COM vr_phy_write(vrp, MII_AN_ADVERT, vrp->chip.mii.anadv);
26759540SJoost.Mulders@Sun.COM } else {
26769540SJoost.Mulders@Sun.COM /*
26779540SJoost.Mulders@Sun.COM * If we don't autoneg, we need speed, duplex and flowcontrol
26789540SJoost.Mulders@Sun.COM * to configure the link. However, dladm doesn't allow changes
26799540SJoost.Mulders@Sun.COM * to speed and duplex (readonly). The way this is solved
26809540SJoost.Mulders@Sun.COM * (ahem) is to select the highest enabled combination
26819540SJoost.Mulders@Sun.COM * Speed and duplex should be r/w when autoneg is off.
26829540SJoost.Mulders@Sun.COM */
26839540SJoost.Mulders@Sun.COM if ((vrp->param.anadv_en &
26849540SJoost.Mulders@Sun.COM MII_ABILITY_100BASE_TX_FD) != 0) {
26859540SJoost.Mulders@Sun.COM vrp->chip.mii.control |= MII_CONTROL_100MB;
26869540SJoost.Mulders@Sun.COM vrp->chip.mii.control |= MII_CONTROL_FDUPLEX;
26879540SJoost.Mulders@Sun.COM } else if ((vrp->param.anadv_en &
26889540SJoost.Mulders@Sun.COM MII_ABILITY_100BASE_TX) != 0) {
26899540SJoost.Mulders@Sun.COM vrp->chip.mii.control |= MII_CONTROL_100MB;
26909540SJoost.Mulders@Sun.COM vrp->chip.mii.control &= ~MII_CONTROL_FDUPLEX;
26919540SJoost.Mulders@Sun.COM } else if ((vrp->param.anadv_en &
26929540SJoost.Mulders@Sun.COM MII_ABILITY_10BASE_T_FD) != 0) {
26939540SJoost.Mulders@Sun.COM vrp->chip.mii.control |= MII_CONTROL_FDUPLEX;
26949540SJoost.Mulders@Sun.COM vrp->chip.mii.control &= ~MII_CONTROL_100MB;
26959540SJoost.Mulders@Sun.COM } else {
26969540SJoost.Mulders@Sun.COM vrp->chip.mii.control &= ~MII_CONTROL_100MB;
26979540SJoost.Mulders@Sun.COM vrp->chip.mii.control &= ~MII_CONTROL_FDUPLEX;
26989540SJoost.Mulders@Sun.COM }
26999540SJoost.Mulders@Sun.COM }
27009540SJoost.Mulders@Sun.COM /*
27019540SJoost.Mulders@Sun.COM * Write the control register.
27029540SJoost.Mulders@Sun.COM */
27039540SJoost.Mulders@Sun.COM vr_phy_write(vrp, MII_CONTROL, vrp->chip.mii.control);
27049540SJoost.Mulders@Sun.COM
27059540SJoost.Mulders@Sun.COM /*
27069540SJoost.Mulders@Sun.COM * With autoneg off we cannot rely on the link_change interrupt for
27079540SJoost.Mulders@Sun.COM * for getting the status into the driver.
27089540SJoost.Mulders@Sun.COM */
27099540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_ANE) == 0) {
27109540SJoost.Mulders@Sun.COM vr_link_state(vrp);
27119540SJoost.Mulders@Sun.COM mac_link_update(vrp->machdl,
27129540SJoost.Mulders@Sun.COM (link_state_t)vrp->chip.link.state);
27139540SJoost.Mulders@Sun.COM }
27149540SJoost.Mulders@Sun.COM }
27159540SJoost.Mulders@Sun.COM
27169540SJoost.Mulders@Sun.COM /*
27179540SJoost.Mulders@Sun.COM * Get link state in the driver and configure the MAC accordingly.
27189540SJoost.Mulders@Sun.COM */
27199540SJoost.Mulders@Sun.COM static void
vr_link_state(vr_t * vrp)27209540SJoost.Mulders@Sun.COM vr_link_state(vr_t *vrp)
27219540SJoost.Mulders@Sun.COM {
27229540SJoost.Mulders@Sun.COM uint16_t mask;
27239540SJoost.Mulders@Sun.COM
27249540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(&vrp->oplock));
27259540SJoost.Mulders@Sun.COM
27269540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_STATUS, &vrp->chip.mii.status);
27279540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_CONTROL, &vrp->chip.mii.control);
27289540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_AN_ADVERT, &vrp->chip.mii.anadv);
27299540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_AN_LPABLE, &vrp->chip.mii.lpable);
27309540SJoost.Mulders@Sun.COM vr_phy_read(vrp, MII_AN_EXPANSION, &vrp->chip.mii.anexp);
27319540SJoost.Mulders@Sun.COM
27329540SJoost.Mulders@Sun.COM /*
27339540SJoost.Mulders@Sun.COM * If we did autongeg, deduce the link type/speed by selecting the
27349540SJoost.Mulders@Sun.COM * highest common denominator.
27359540SJoost.Mulders@Sun.COM */
27369540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_ANE) != 0) {
27379540SJoost.Mulders@Sun.COM mask = vrp->chip.mii.anadv & vrp->chip.mii.lpable;
27389540SJoost.Mulders@Sun.COM if ((mask & MII_ABILITY_100BASE_TX_FD) != 0) {
27399540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_100MBS;
27409540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL;
27419540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_100X;
27429540SJoost.Mulders@Sun.COM } else if ((mask & MII_ABILITY_100BASE_T4) != 0) {
27439540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_100MBS;
27449540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF;
27459540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_100T4;
27469540SJoost.Mulders@Sun.COM } else if ((mask & MII_ABILITY_100BASE_TX) != 0) {
27479540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_100MBS;
27489540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF;
27499540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_100X;
27509540SJoost.Mulders@Sun.COM } else if ((mask & MII_ABILITY_10BASE_T_FD) != 0) {
27519540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_10MBS;
27529540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL;
27539540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_10;
27549540SJoost.Mulders@Sun.COM } else if ((mask & MII_ABILITY_10BASE_T) != 0) {
27559540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_10MBS;
27569540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF;
27579540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_10;
27589540SJoost.Mulders@Sun.COM } else {
27599540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_UNKNOWN;
27609540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_UNKNOWN;
27619540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_UNKNOWN;
27629540SJoost.Mulders@Sun.COM }
27639540SJoost.Mulders@Sun.COM
27649540SJoost.Mulders@Sun.COM /*
27659540SJoost.Mulders@Sun.COM * Did we negotiate pause?
27669540SJoost.Mulders@Sun.COM */
27679860Sgdamore@opensolaris.org if ((mask & MII_ABILITY_PAUSE) != 0 &&
27689540SJoost.Mulders@Sun.COM vrp->chip.link.duplex == VR_LINK_DUPLEX_FULL)
27699540SJoost.Mulders@Sun.COM vrp->chip.link.flowctrl = VR_PAUSE_BIDIRECTIONAL;
27709540SJoost.Mulders@Sun.COM else
27719540SJoost.Mulders@Sun.COM vrp->chip.link.flowctrl = VR_PAUSE_NONE;
27729540SJoost.Mulders@Sun.COM
27739540SJoost.Mulders@Sun.COM /*
27749540SJoost.Mulders@Sun.COM * Did either one detect a AN fault?
27759540SJoost.Mulders@Sun.COM */
27769540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_REMFAULT) != 0)
27779540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
27789540SJoost.Mulders@Sun.COM "AN remote fault reported by LP.");
27799540SJoost.Mulders@Sun.COM
27809540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.lpable & MII_AN_ADVERT_REMFAULT) != 0)
27819540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "AN remote fault caused for LP.");
27829540SJoost.Mulders@Sun.COM } else {
27839540SJoost.Mulders@Sun.COM /*
27849540SJoost.Mulders@Sun.COM * We didn't autoneg
27859540SJoost.Mulders@Sun.COM * The link type is defined by the control register.
27869540SJoost.Mulders@Sun.COM */
27879540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_100MB) != 0) {
27889540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_100MBS;
27899540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_100X;
27909540SJoost.Mulders@Sun.COM } else {
27919540SJoost.Mulders@Sun.COM vrp->chip.link.speed = VR_LINK_SPEED_10MBS;
27929540SJoost.Mulders@Sun.COM vrp->chip.link.mau = VR_MAU_10;
27939540SJoost.Mulders@Sun.COM }
27949540SJoost.Mulders@Sun.COM
27959540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_FDUPLEX) != 0)
27969540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_FULL;
27979540SJoost.Mulders@Sun.COM else {
27989540SJoost.Mulders@Sun.COM vrp->chip.link.duplex = VR_LINK_DUPLEX_HALF;
27999540SJoost.Mulders@Sun.COM /*
28009540SJoost.Mulders@Sun.COM * No pause on HDX links.
28019540SJoost.Mulders@Sun.COM */
28029540SJoost.Mulders@Sun.COM vrp->chip.link.flowctrl = VR_PAUSE_NONE;
28039540SJoost.Mulders@Sun.COM }
28049540SJoost.Mulders@Sun.COM }
28059540SJoost.Mulders@Sun.COM
28069540SJoost.Mulders@Sun.COM /*
28079540SJoost.Mulders@Sun.COM * Set the duplex mode on the MAC according to that of the PHY.
28089540SJoost.Mulders@Sun.COM */
28099540SJoost.Mulders@Sun.COM if (vrp->chip.link.duplex == VR_LINK_DUPLEX_FULL) {
28109540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_MACFULLDUPLEX);
28119540SJoost.Mulders@Sun.COM /*
28129540SJoost.Mulders@Sun.COM * Enable packet queueing on FDX links.
28139540SJoost.Mulders@Sun.COM */
28149540SJoost.Mulders@Sun.COM if ((vrp->chip.info.bugs & VR_BUG_NO_TXQUEUEING) == 0)
28159540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_QPKTDIS);
28169540SJoost.Mulders@Sun.COM } else {
28179540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_CTRL1, VR_CTRL1_MACFULLDUPLEX);
28189540SJoost.Mulders@Sun.COM /*
28199540SJoost.Mulders@Sun.COM * Disable packet queueing on HDX links. With queueing enabled,
28209540SJoost.Mulders@Sun.COM * this MAC get's lost after a TX abort (too many colisions).
28219540SJoost.Mulders@Sun.COM */
28229540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_CFGB, VR_CFGB_QPKTDIS);
28239540SJoost.Mulders@Sun.COM }
28249540SJoost.Mulders@Sun.COM
28259540SJoost.Mulders@Sun.COM /*
28269540SJoost.Mulders@Sun.COM * Set pause options on the MAC.
28279540SJoost.Mulders@Sun.COM */
28289540SJoost.Mulders@Sun.COM if (vrp->chip.link.flowctrl == VR_PAUSE_BIDIRECTIONAL) {
28299540SJoost.Mulders@Sun.COM /*
28309540SJoost.Mulders@Sun.COM * All of our MAC's can receive pause frames.
28319540SJoost.Mulders@Sun.COM */
28329540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_MISC0, VR_MISC0_FDXRFEN);
28339540SJoost.Mulders@Sun.COM
28349540SJoost.Mulders@Sun.COM /*
28359540SJoost.Mulders@Sun.COM * VT6105 and above can transmit pause frames.
28369540SJoost.Mulders@Sun.COM */
28379540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_TX_PAUSE_CAP) != 0) {
28389540SJoost.Mulders@Sun.COM /*
28399540SJoost.Mulders@Sun.COM * Set the number of available receive descriptors
28409540SJoost.Mulders@Sun.COM * Non-zero values written to this register are added
28419540SJoost.Mulders@Sun.COM * to the register's contents. Careful: Writing zero
28429540SJoost.Mulders@Sun.COM * clears the register and thus causes a (long) pause
28439540SJoost.Mulders@Sun.COM * request.
28449540SJoost.Mulders@Sun.COM */
28459540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_FCR0_RXBUFCOUNT,
28469540SJoost.Mulders@Sun.COM MIN(vrp->rx.ndesc, 0xFF) -
28479540SJoost.Mulders@Sun.COM VR_GET8(vrp->acc_reg,
28489540SJoost.Mulders@Sun.COM VR_FCR0_RXBUFCOUNT));
28499540SJoost.Mulders@Sun.COM
28509540SJoost.Mulders@Sun.COM /*
28519540SJoost.Mulders@Sun.COM * Request pause when we have 4 descs left.
28529540SJoost.Mulders@Sun.COM */
28539540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_FCR1,
28549540SJoost.Mulders@Sun.COM VR_FCR1_PAUSEONBITS, VR_FCR1_PAUSEON_04);
28559540SJoost.Mulders@Sun.COM
28569540SJoost.Mulders@Sun.COM /*
28579540SJoost.Mulders@Sun.COM * Cancel the pause when there are 24 descriptors again.
28589540SJoost.Mulders@Sun.COM */
28599540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_FCR1,
28609540SJoost.Mulders@Sun.COM VR_FCR1_PAUSEOFFBITS, VR_FCR1_PAUSEOFF_24);
28619540SJoost.Mulders@Sun.COM
28629540SJoost.Mulders@Sun.COM /*
28639540SJoost.Mulders@Sun.COM * Request a pause of FFFF bit-times. This long pause
28649540SJoost.Mulders@Sun.COM * is cancelled when the high watermark is reached.
28659540SJoost.Mulders@Sun.COM */
28669540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_FCR2_PAUSE, 0xFFFF);
28679540SJoost.Mulders@Sun.COM
28689540SJoost.Mulders@Sun.COM /*
28699540SJoost.Mulders@Sun.COM * Enable flow control on the MAC.
28709540SJoost.Mulders@Sun.COM */
28719540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_MISC0, VR_MISC0_FDXTFEN);
28729540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_FCR1, VR_FCR1_FD_RX_EN |
28739540SJoost.Mulders@Sun.COM VR_FCR1_FD_TX_EN | VR_FCR1_XONXOFF_EN);
28749540SJoost.Mulders@Sun.COM }
28759540SJoost.Mulders@Sun.COM } else {
28769540SJoost.Mulders@Sun.COM /*
28779540SJoost.Mulders@Sun.COM * Turn flow control OFF.
28789540SJoost.Mulders@Sun.COM */
28799540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg,
28809540SJoost.Mulders@Sun.COM VR_MISC0, VR_MISC0_FDXRFEN | VR_MISC0_FDXTFEN);
28819540SJoost.Mulders@Sun.COM if ((vrp->chip.info.features & VR_FEATURE_TX_PAUSE_CAP) != 0) {
28829540SJoost.Mulders@Sun.COM VR_CLRBIT8(vrp->acc_reg, VR_FCR1,
28839540SJoost.Mulders@Sun.COM VR_FCR1_FD_RX_EN | VR_FCR1_FD_TX_EN |
28849540SJoost.Mulders@Sun.COM VR_FCR1_XONXOFF_EN);
28859540SJoost.Mulders@Sun.COM }
28869540SJoost.Mulders@Sun.COM }
28879540SJoost.Mulders@Sun.COM
28889540SJoost.Mulders@Sun.COM /*
28899540SJoost.Mulders@Sun.COM * Set link state.
28909540SJoost.Mulders@Sun.COM */
28919540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status & MII_STATUS_LINKUP) != 0)
28929540SJoost.Mulders@Sun.COM vrp->chip.link.state = VR_LINK_STATE_UP;
28939540SJoost.Mulders@Sun.COM else
28949540SJoost.Mulders@Sun.COM vrp->chip.link.state = VR_LINK_STATE_DOWN;
28959540SJoost.Mulders@Sun.COM }
28969540SJoost.Mulders@Sun.COM
28979540SJoost.Mulders@Sun.COM /*
28989540SJoost.Mulders@Sun.COM * The PHY is automatically polled by the MAC once per 1024 MD clock cycles
28999540SJoost.Mulders@Sun.COM * MD is clocked once per 960ns so polling happens about every 1M ns, some
29009540SJoost.Mulders@Sun.COM * 1000 times per second
29019540SJoost.Mulders@Sun.COM * This polling process is required for the functionality of the link change
29029540SJoost.Mulders@Sun.COM * interrupt. Polling process must be disabled in order to access PHY registers
29039540SJoost.Mulders@Sun.COM * using MDIO
29049540SJoost.Mulders@Sun.COM *
29059540SJoost.Mulders@Sun.COM * Turn off PHY polling so that the PHY registers can be accessed.
29069540SJoost.Mulders@Sun.COM */
29079540SJoost.Mulders@Sun.COM static void
vr_phy_autopoll_disable(vr_t * vrp)29089540SJoost.Mulders@Sun.COM vr_phy_autopoll_disable(vr_t *vrp)
29099540SJoost.Mulders@Sun.COM {
29109540SJoost.Mulders@Sun.COM uint32_t time;
29119540SJoost.Mulders@Sun.COM uint8_t miicmd, miiaddr;
29129540SJoost.Mulders@Sun.COM
29139540SJoost.Mulders@Sun.COM /*
29149540SJoost.Mulders@Sun.COM * Special procedure to stop the autopolling.
29159540SJoost.Mulders@Sun.COM */
29169540SJoost.Mulders@Sun.COM if ((vrp->chip.info.bugs & VR_BUG_MIIPOLLSTOP) != 0) {
29179540SJoost.Mulders@Sun.COM /*
29189540SJoost.Mulders@Sun.COM * If polling is enabled.
29199540SJoost.Mulders@Sun.COM */
29209540SJoost.Mulders@Sun.COM miicmd = VR_GET8(vrp->acc_reg, VR_MIICMD);
29219540SJoost.Mulders@Sun.COM if ((miicmd & VR_MIICMD_MD_AUTO) != 0) {
29229540SJoost.Mulders@Sun.COM /*
29239540SJoost.Mulders@Sun.COM * Wait for the end of a cycle (mdone set).
29249540SJoost.Mulders@Sun.COM */
29259540SJoost.Mulders@Sun.COM time = 0;
29269540SJoost.Mulders@Sun.COM do {
29279540SJoost.Mulders@Sun.COM drv_usecwait(10);
29289540SJoost.Mulders@Sun.COM if (time >= VR_MMI_WAITMAX) {
29299540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
29309540SJoost.Mulders@Sun.COM "Timeout in "
29319540SJoost.Mulders@Sun.COM "disable MII polling");
29329540SJoost.Mulders@Sun.COM break;
29339540SJoost.Mulders@Sun.COM }
29349540SJoost.Mulders@Sun.COM time += VR_MMI_WAITINCR;
29359540SJoost.Mulders@Sun.COM miiaddr = VR_GET8(vrp->acc_reg, VR_MIIADDR);
29369540SJoost.Mulders@Sun.COM } while ((miiaddr & VR_MIIADDR_MDONE) == 0);
29379540SJoost.Mulders@Sun.COM }
29389540SJoost.Mulders@Sun.COM /*
29399540SJoost.Mulders@Sun.COM * Once paused, we can disable autopolling.
29409540SJoost.Mulders@Sun.COM */
29419540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MIICMD, 0);
29429540SJoost.Mulders@Sun.COM } else {
29439540SJoost.Mulders@Sun.COM /*
29449540SJoost.Mulders@Sun.COM * Turn off MII polling.
29459540SJoost.Mulders@Sun.COM */
29469540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MIICMD, 0);
29479540SJoost.Mulders@Sun.COM
29489540SJoost.Mulders@Sun.COM /*
29499540SJoost.Mulders@Sun.COM * Wait for MIDLE in MII address register.
29509540SJoost.Mulders@Sun.COM */
29519540SJoost.Mulders@Sun.COM time = 0;
29529540SJoost.Mulders@Sun.COM do {
29539540SJoost.Mulders@Sun.COM drv_usecwait(VR_MMI_WAITINCR);
29549540SJoost.Mulders@Sun.COM if (time >= VR_MMI_WAITMAX) {
29559540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN,
29569540SJoost.Mulders@Sun.COM "Timeout in disable MII polling");
29579540SJoost.Mulders@Sun.COM break;
29589540SJoost.Mulders@Sun.COM }
29599540SJoost.Mulders@Sun.COM time += VR_MMI_WAITINCR;
29609540SJoost.Mulders@Sun.COM miiaddr = VR_GET8(vrp->acc_reg, VR_MIIADDR);
29619540SJoost.Mulders@Sun.COM } while ((miiaddr & VR_MIIADDR_MIDLE) == 0);
29629540SJoost.Mulders@Sun.COM }
29639540SJoost.Mulders@Sun.COM }
29649540SJoost.Mulders@Sun.COM
29659540SJoost.Mulders@Sun.COM /*
29669540SJoost.Mulders@Sun.COM * Turn on PHY polling. PHY's registers cannot be accessed.
29679540SJoost.Mulders@Sun.COM */
29689540SJoost.Mulders@Sun.COM static void
vr_phy_autopoll_enable(vr_t * vrp)29699540SJoost.Mulders@Sun.COM vr_phy_autopoll_enable(vr_t *vrp)
29709540SJoost.Mulders@Sun.COM {
29719540SJoost.Mulders@Sun.COM uint32_t time;
29729540SJoost.Mulders@Sun.COM
29739540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MIICMD, 0);
29749540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MIIADDR, MII_STATUS|VR_MIIADDR_MAUTO);
29759540SJoost.Mulders@Sun.COM VR_PUT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_AUTO);
29769540SJoost.Mulders@Sun.COM
29779540SJoost.Mulders@Sun.COM /*
29789540SJoost.Mulders@Sun.COM * Wait for the polling process to finish.
29799540SJoost.Mulders@Sun.COM */
29809540SJoost.Mulders@Sun.COM time = 0;
29819540SJoost.Mulders@Sun.COM do {
29829540SJoost.Mulders@Sun.COM drv_usecwait(VR_MMI_WAITINCR);
29839540SJoost.Mulders@Sun.COM if (time >= VR_MMI_WAITMAX) {
29849540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "Timeout in enable MII polling");
29859540SJoost.Mulders@Sun.COM break;
29869540SJoost.Mulders@Sun.COM }
29879540SJoost.Mulders@Sun.COM time += VR_MMI_WAITINCR;
29889540SJoost.Mulders@Sun.COM } while ((VR_GET8(vrp->acc_reg, VR_MIIADDR) & VR_MIIADDR_MDONE) == 0);
29899540SJoost.Mulders@Sun.COM
29909540SJoost.Mulders@Sun.COM /*
29919540SJoost.Mulders@Sun.COM * Initiate a polling.
29929540SJoost.Mulders@Sun.COM */
29939540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_MAUTO);
29949540SJoost.Mulders@Sun.COM }
29959540SJoost.Mulders@Sun.COM
29969540SJoost.Mulders@Sun.COM /*
29979540SJoost.Mulders@Sun.COM * Read a register from the PHY using MDIO.
29989540SJoost.Mulders@Sun.COM */
29999540SJoost.Mulders@Sun.COM static void
vr_phy_read(vr_t * vrp,int offset,uint16_t * value)30009540SJoost.Mulders@Sun.COM vr_phy_read(vr_t *vrp, int offset, uint16_t *value)
30019540SJoost.Mulders@Sun.COM {
30029540SJoost.Mulders@Sun.COM uint32_t time;
30039540SJoost.Mulders@Sun.COM
30049540SJoost.Mulders@Sun.COM vr_phy_autopoll_disable(vrp);
30059540SJoost.Mulders@Sun.COM
30069540SJoost.Mulders@Sun.COM /*
30079540SJoost.Mulders@Sun.COM * Write the register number to the lower 5 bits of the MII address
30089540SJoost.Mulders@Sun.COM * register.
30099540SJoost.Mulders@Sun.COM */
30109540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_BITS, offset);
30119540SJoost.Mulders@Sun.COM
30129540SJoost.Mulders@Sun.COM /*
30139540SJoost.Mulders@Sun.COM * Write a READ command to the MII control register
30149540SJoost.Mulders@Sun.COM * This bit will be cleared when the read is finished.
30159540SJoost.Mulders@Sun.COM */
30169540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_READ);
30179540SJoost.Mulders@Sun.COM
30189540SJoost.Mulders@Sun.COM /*
30199540SJoost.Mulders@Sun.COM * Wait until the read is done.
30209540SJoost.Mulders@Sun.COM */
30219540SJoost.Mulders@Sun.COM time = 0;
30229540SJoost.Mulders@Sun.COM do {
30239540SJoost.Mulders@Sun.COM drv_usecwait(VR_MMI_WAITINCR);
30249540SJoost.Mulders@Sun.COM if (time >= VR_MMI_WAITMAX) {
30259540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "Timeout in MII read command");
30269540SJoost.Mulders@Sun.COM break;
30279540SJoost.Mulders@Sun.COM }
30289540SJoost.Mulders@Sun.COM time += VR_MMI_WAITINCR;
30299540SJoost.Mulders@Sun.COM } while ((VR_GET8(vrp->acc_reg, VR_MIICMD) & VR_MIICMD_MD_READ) != 0);
30309540SJoost.Mulders@Sun.COM
30319540SJoost.Mulders@Sun.COM *value = VR_GET16(vrp->acc_reg, VR_MIIDATA);
30329540SJoost.Mulders@Sun.COM vr_phy_autopoll_enable(vrp);
30339540SJoost.Mulders@Sun.COM }
30349540SJoost.Mulders@Sun.COM
30359540SJoost.Mulders@Sun.COM /*
30369540SJoost.Mulders@Sun.COM * Write to a PHY's register.
30379540SJoost.Mulders@Sun.COM */
30389540SJoost.Mulders@Sun.COM static void
vr_phy_write(vr_t * vrp,int offset,uint16_t value)30399540SJoost.Mulders@Sun.COM vr_phy_write(vr_t *vrp, int offset, uint16_t value)
30409540SJoost.Mulders@Sun.COM {
30419540SJoost.Mulders@Sun.COM uint32_t time;
30429540SJoost.Mulders@Sun.COM
30439540SJoost.Mulders@Sun.COM vr_phy_autopoll_disable(vrp);
30449540SJoost.Mulders@Sun.COM
30459540SJoost.Mulders@Sun.COM /*
30469540SJoost.Mulders@Sun.COM * Write the register number to the MII address register.
30479540SJoost.Mulders@Sun.COM */
30489540SJoost.Mulders@Sun.COM VR_SETBITS8(vrp->acc_reg, VR_MIIADDR, VR_MIIADDR_BITS, offset);
30499540SJoost.Mulders@Sun.COM
30509540SJoost.Mulders@Sun.COM /*
30519540SJoost.Mulders@Sun.COM * Write the value to the data register.
30529540SJoost.Mulders@Sun.COM */
30539540SJoost.Mulders@Sun.COM VR_PUT16(vrp->acc_reg, VR_MIIDATA, value);
30549540SJoost.Mulders@Sun.COM
30559540SJoost.Mulders@Sun.COM /*
30569540SJoost.Mulders@Sun.COM * Issue the WRITE command to the command register.
30579540SJoost.Mulders@Sun.COM * This bit will be cleared when the write is finished.
30589540SJoost.Mulders@Sun.COM */
30599540SJoost.Mulders@Sun.COM VR_SETBIT8(vrp->acc_reg, VR_MIICMD, VR_MIICMD_MD_WRITE);
30609540SJoost.Mulders@Sun.COM
30619540SJoost.Mulders@Sun.COM time = 0;
30629540SJoost.Mulders@Sun.COM do {
30639540SJoost.Mulders@Sun.COM drv_usecwait(VR_MMI_WAITINCR);
30649540SJoost.Mulders@Sun.COM if (time >= VR_MMI_WAITMAX) {
30659540SJoost.Mulders@Sun.COM vr_log(vrp, CE_NOTE, "Timeout in MII write command");
30669540SJoost.Mulders@Sun.COM break;
30679540SJoost.Mulders@Sun.COM }
30689540SJoost.Mulders@Sun.COM time += VR_MMI_WAITINCR;
30699540SJoost.Mulders@Sun.COM } while ((VR_GET8(vrp->acc_reg, VR_MIICMD) & VR_MIICMD_MD_WRITE) != 0);
30709540SJoost.Mulders@Sun.COM vr_phy_autopoll_enable(vrp);
30719540SJoost.Mulders@Sun.COM }
30729540SJoost.Mulders@Sun.COM
30739540SJoost.Mulders@Sun.COM /*
30749540SJoost.Mulders@Sun.COM * Initialize and install some private kstats.
30759540SJoost.Mulders@Sun.COM */
30769540SJoost.Mulders@Sun.COM typedef struct {
30779540SJoost.Mulders@Sun.COM char *name;
30789540SJoost.Mulders@Sun.COM uchar_t type;
30799540SJoost.Mulders@Sun.COM } vr_kstat_t;
30809540SJoost.Mulders@Sun.COM
30819540SJoost.Mulders@Sun.COM static const vr_kstat_t vr_driver_stats [] = {
30829540SJoost.Mulders@Sun.COM {"allocbfail", KSTAT_DATA_INT32},
30839540SJoost.Mulders@Sun.COM {"intr_claimed", KSTAT_DATA_INT64},
30849540SJoost.Mulders@Sun.COM {"intr_unclaimed", KSTAT_DATA_INT64},
30859540SJoost.Mulders@Sun.COM {"linkchanges", KSTAT_DATA_INT64},
30869540SJoost.Mulders@Sun.COM {"txnfree", KSTAT_DATA_INT32},
30879540SJoost.Mulders@Sun.COM {"txstalls", KSTAT_DATA_INT32},
30889540SJoost.Mulders@Sun.COM {"resets", KSTAT_DATA_INT32},
30899540SJoost.Mulders@Sun.COM {"txreclaims", KSTAT_DATA_INT64},
30909540SJoost.Mulders@Sun.COM {"txreclaim0", KSTAT_DATA_INT64},
30919540SJoost.Mulders@Sun.COM {"cyclics", KSTAT_DATA_INT64},
30929540SJoost.Mulders@Sun.COM {"txchecks", KSTAT_DATA_INT64},
30939540SJoost.Mulders@Sun.COM };
30949540SJoost.Mulders@Sun.COM
30959540SJoost.Mulders@Sun.COM static void
vr_kstats_init(vr_t * vrp)30969540SJoost.Mulders@Sun.COM vr_kstats_init(vr_t *vrp)
30979540SJoost.Mulders@Sun.COM {
30989540SJoost.Mulders@Sun.COM kstat_t *ksp;
30999540SJoost.Mulders@Sun.COM struct kstat_named *knp;
31009540SJoost.Mulders@Sun.COM int i;
31019540SJoost.Mulders@Sun.COM int nstats;
31029540SJoost.Mulders@Sun.COM
31039540SJoost.Mulders@Sun.COM nstats = sizeof (vr_driver_stats) / sizeof (vr_kstat_t);
31049540SJoost.Mulders@Sun.COM
31059540SJoost.Mulders@Sun.COM ksp = kstat_create(MODULENAME, ddi_get_instance(vrp->devinfo),
31069540SJoost.Mulders@Sun.COM "driver", "net", KSTAT_TYPE_NAMED, nstats, 0);
31079540SJoost.Mulders@Sun.COM
31089540SJoost.Mulders@Sun.COM if (ksp == NULL)
31099540SJoost.Mulders@Sun.COM vr_log(vrp, CE_WARN, "kstat_create failed");
31109540SJoost.Mulders@Sun.COM
31119540SJoost.Mulders@Sun.COM ksp->ks_update = vr_update_kstats;
31129540SJoost.Mulders@Sun.COM ksp->ks_private = (void*) vrp;
31139540SJoost.Mulders@Sun.COM knp = ksp->ks_data;
31149540SJoost.Mulders@Sun.COM
31159540SJoost.Mulders@Sun.COM for (i = 0; i < nstats; i++, knp++) {
31169540SJoost.Mulders@Sun.COM kstat_named_init(knp, vr_driver_stats[i].name,
31179540SJoost.Mulders@Sun.COM vr_driver_stats[i].type);
31189540SJoost.Mulders@Sun.COM }
31199540SJoost.Mulders@Sun.COM kstat_install(ksp);
31209540SJoost.Mulders@Sun.COM vrp->ksp = ksp;
31219540SJoost.Mulders@Sun.COM }
31229540SJoost.Mulders@Sun.COM
31239540SJoost.Mulders@Sun.COM static int
vr_update_kstats(kstat_t * ksp,int access)31249540SJoost.Mulders@Sun.COM vr_update_kstats(kstat_t *ksp, int access)
31259540SJoost.Mulders@Sun.COM {
31269540SJoost.Mulders@Sun.COM vr_t *vrp;
31279540SJoost.Mulders@Sun.COM struct kstat_named *knp;
31289540SJoost.Mulders@Sun.COM
31299540SJoost.Mulders@Sun.COM vrp = (vr_t *)ksp->ks_private;
31309540SJoost.Mulders@Sun.COM knp = ksp->ks_data;
31319540SJoost.Mulders@Sun.COM
31329540SJoost.Mulders@Sun.COM if (access != KSTAT_READ)
31339540SJoost.Mulders@Sun.COM return (EACCES);
31349540SJoost.Mulders@Sun.COM
31359540SJoost.Mulders@Sun.COM (knp++)->value.ui32 = vrp->stats.allocbfail;
31369540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.intr_claimed;
31379540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.intr_unclaimed;
31389540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.linkchanges;
31399540SJoost.Mulders@Sun.COM (knp++)->value.ui32 = vrp->tx.nfree;
31409540SJoost.Mulders@Sun.COM (knp++)->value.ui32 = vrp->stats.txstalls;
31419540SJoost.Mulders@Sun.COM (knp++)->value.ui32 = vrp->stats.resets;
31429540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.txreclaims;
31439540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.txreclaim0;
31449540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.cyclics;
31459540SJoost.Mulders@Sun.COM (knp++)->value.ui64 = vrp->stats.txchecks;
31469540SJoost.Mulders@Sun.COM return (0);
31479540SJoost.Mulders@Sun.COM }
31489540SJoost.Mulders@Sun.COM
31499540SJoost.Mulders@Sun.COM /*
31509540SJoost.Mulders@Sun.COM * Remove 'private' kstats.
31519540SJoost.Mulders@Sun.COM */
31529540SJoost.Mulders@Sun.COM static void
vr_remove_kstats(vr_t * vrp)31539540SJoost.Mulders@Sun.COM vr_remove_kstats(vr_t *vrp)
31549540SJoost.Mulders@Sun.COM {
31559540SJoost.Mulders@Sun.COM if (vrp->ksp != NULL)
31569540SJoost.Mulders@Sun.COM kstat_delete(vrp->ksp);
31579540SJoost.Mulders@Sun.COM }
31589540SJoost.Mulders@Sun.COM
31599540SJoost.Mulders@Sun.COM /*
31609540SJoost.Mulders@Sun.COM * Get a property of the device/driver
31619540SJoost.Mulders@Sun.COM * Remarks:
31629540SJoost.Mulders@Sun.COM * - pr_val is always an integer of size pr_valsize
31639540SJoost.Mulders@Sun.COM * - ENABLED (EN) is what is configured via dladm
31649540SJoost.Mulders@Sun.COM * - ADVERTISED (ADV) is ENABLED minus constraints, like PHY/MAC capabilities
31659540SJoost.Mulders@Sun.COM * - DEFAULT are driver- and hardware defaults (DEFAULT is implemented as a
31669540SJoost.Mulders@Sun.COM * flag in pr_flags instead of MAC_PROP_DEFAULT_)
31679540SJoost.Mulders@Sun.COM * - perm is the permission printed on ndd -get /.. \?
31689540SJoost.Mulders@Sun.COM */
31699540SJoost.Mulders@Sun.COM int
vr_mac_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)31709540SJoost.Mulders@Sun.COM vr_mac_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
317111878SVenu.Iyer@Sun.COM uint_t pr_valsize, void *pr_val)
31729540SJoost.Mulders@Sun.COM {
31739540SJoost.Mulders@Sun.COM vr_t *vrp;
31749540SJoost.Mulders@Sun.COM uint32_t err;
31759540SJoost.Mulders@Sun.COM uint64_t val;
31769540SJoost.Mulders@Sun.COM
31779540SJoost.Mulders@Sun.COM /* Since we have no private properties */
31789540SJoost.Mulders@Sun.COM _NOTE(ARGUNUSED(pr_name))
31799540SJoost.Mulders@Sun.COM
31809540SJoost.Mulders@Sun.COM err = 0;
31819540SJoost.Mulders@Sun.COM vrp = (vr_t *)arg;
318211878SVenu.Iyer@Sun.COM switch (pr_num) {
318311878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_1000FDX_CAP:
318411878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_1000HDX_CAP:
318511878SVenu.Iyer@Sun.COM case MAC_PROP_EN_1000FDX_CAP:
318611878SVenu.Iyer@Sun.COM case MAC_PROP_EN_1000HDX_CAP:
318711878SVenu.Iyer@Sun.COM val = 0;
318811878SVenu.Iyer@Sun.COM break;
318911878SVenu.Iyer@Sun.COM
319011878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100FDX_CAP:
319111878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.anadv &
319211878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_TX_FD) != 0;
319311878SVenu.Iyer@Sun.COM break;
319411878SVenu.Iyer@Sun.COM
319511878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100HDX_CAP:
319611878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.anadv &
319711878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_TX) != 0;
319811878SVenu.Iyer@Sun.COM break;
319911878SVenu.Iyer@Sun.COM
320011878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100T4_CAP:
320111878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.anadv &
320211878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_T4) != 0;
320311878SVenu.Iyer@Sun.COM break;
320411878SVenu.Iyer@Sun.COM
320511878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10FDX_CAP:
320611878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.anadv &
320711878SVenu.Iyer@Sun.COM MII_ABILITY_10BASE_T_FD) != 0;
320811878SVenu.Iyer@Sun.COM break;
320911878SVenu.Iyer@Sun.COM
321011878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10HDX_CAP:
321111878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.anadv &
321211878SVenu.Iyer@Sun.COM MII_ABILITY_10BASE_T) != 0;
321311878SVenu.Iyer@Sun.COM break;
321411878SVenu.Iyer@Sun.COM
321511878SVenu.Iyer@Sun.COM case MAC_PROP_AUTONEG:
321611878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.control &
321711878SVenu.Iyer@Sun.COM MII_CONTROL_ANE) != 0;
321811878SVenu.Iyer@Sun.COM break;
321911878SVenu.Iyer@Sun.COM
322011878SVenu.Iyer@Sun.COM case MAC_PROP_DUPLEX:
322111878SVenu.Iyer@Sun.COM val = vrp->chip.link.duplex;
322211878SVenu.Iyer@Sun.COM break;
322311878SVenu.Iyer@Sun.COM
322411878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100FDX_CAP:
322511878SVenu.Iyer@Sun.COM val = (vrp->param.anadv_en &
322611878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_TX_FD) != 0;
322711878SVenu.Iyer@Sun.COM break;
322811878SVenu.Iyer@Sun.COM
322911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100HDX_CAP:
323011878SVenu.Iyer@Sun.COM val = (vrp->param.anadv_en &
323111878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_TX) != 0;
323211878SVenu.Iyer@Sun.COM break;
323311878SVenu.Iyer@Sun.COM
323411878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100T4_CAP:
323511878SVenu.Iyer@Sun.COM val = (vrp->param.anadv_en &
323611878SVenu.Iyer@Sun.COM MII_ABILITY_100BASE_T4) != 0;
323711878SVenu.Iyer@Sun.COM break;
323811878SVenu.Iyer@Sun.COM
323911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10FDX_CAP:
324011878SVenu.Iyer@Sun.COM val = (vrp->param.anadv_en &
324111878SVenu.Iyer@Sun.COM MII_ABILITY_10BASE_T_FD) != 0;
324211878SVenu.Iyer@Sun.COM break;
324311878SVenu.Iyer@Sun.COM
324411878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10HDX_CAP:
324511878SVenu.Iyer@Sun.COM val = (vrp->param.anadv_en &
324611878SVenu.Iyer@Sun.COM MII_ABILITY_10BASE_T) != 0;
324711878SVenu.Iyer@Sun.COM break;
324811878SVenu.Iyer@Sun.COM
324911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_AUTONEG:
325011878SVenu.Iyer@Sun.COM val = vrp->param.an_en == VR_LINK_AUTONEG_ON;
325111878SVenu.Iyer@Sun.COM break;
325211878SVenu.Iyer@Sun.COM
325311878SVenu.Iyer@Sun.COM case MAC_PROP_FLOWCTRL:
325411878SVenu.Iyer@Sun.COM val = vrp->chip.link.flowctrl;
325511878SVenu.Iyer@Sun.COM break;
325611878SVenu.Iyer@Sun.COM
325711878SVenu.Iyer@Sun.COM case MAC_PROP_MTU:
325811878SVenu.Iyer@Sun.COM val = vrp->param.mtu;
325911878SVenu.Iyer@Sun.COM break;
326011878SVenu.Iyer@Sun.COM
326111878SVenu.Iyer@Sun.COM case MAC_PROP_SPEED:
326211878SVenu.Iyer@Sun.COM if (vrp->chip.link.speed ==
326311878SVenu.Iyer@Sun.COM VR_LINK_SPEED_100MBS)
32649540SJoost.Mulders@Sun.COM val = 100 * 1000 * 1000;
326511878SVenu.Iyer@Sun.COM else if (vrp->chip.link.speed ==
326611878SVenu.Iyer@Sun.COM VR_LINK_SPEED_10MBS)
326711878SVenu.Iyer@Sun.COM val = 10 * 1000 * 1000;
326811878SVenu.Iyer@Sun.COM else
32699540SJoost.Mulders@Sun.COM val = 0;
327011878SVenu.Iyer@Sun.COM break;
327111878SVenu.Iyer@Sun.COM
327211878SVenu.Iyer@Sun.COM case MAC_PROP_STATUS:
327311878SVenu.Iyer@Sun.COM val = vrp->chip.link.state;
327411878SVenu.Iyer@Sun.COM break;
327511878SVenu.Iyer@Sun.COM
327611878SVenu.Iyer@Sun.COM default:
327711878SVenu.Iyer@Sun.COM err = ENOTSUP;
327811878SVenu.Iyer@Sun.COM break;
32799540SJoost.Mulders@Sun.COM }
328011878SVenu.Iyer@Sun.COM
32819540SJoost.Mulders@Sun.COM if (err == 0 && pr_num != MAC_PROP_PRIVATE) {
32829540SJoost.Mulders@Sun.COM if (pr_valsize == sizeof (uint64_t))
32839540SJoost.Mulders@Sun.COM *(uint64_t *)pr_val = val;
32849540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint32_t))
32859540SJoost.Mulders@Sun.COM *(uint32_t *)pr_val = val;
32869540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint16_t))
32879540SJoost.Mulders@Sun.COM *(uint16_t *)pr_val = val;
32889540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint8_t))
32899540SJoost.Mulders@Sun.COM *(uint8_t *)pr_val = val;
32909540SJoost.Mulders@Sun.COM else
32919540SJoost.Mulders@Sun.COM err = EINVAL;
32929540SJoost.Mulders@Sun.COM }
32939540SJoost.Mulders@Sun.COM return (err);
32949540SJoost.Mulders@Sun.COM }
32959540SJoost.Mulders@Sun.COM
329611878SVenu.Iyer@Sun.COM void
vr_mac_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)329711878SVenu.Iyer@Sun.COM vr_mac_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
329811878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh)
329911878SVenu.Iyer@Sun.COM {
330011878SVenu.Iyer@Sun.COM vr_t *vrp = (vr_t *)arg;
330111878SVenu.Iyer@Sun.COM uint8_t val, perm;
330211878SVenu.Iyer@Sun.COM
330311878SVenu.Iyer@Sun.COM /* Since we have no private properties */
330411878SVenu.Iyer@Sun.COM _NOTE(ARGUNUSED(pr_name))
330511878SVenu.Iyer@Sun.COM
330611878SVenu.Iyer@Sun.COM switch (pr_num) {
330711878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_1000FDX_CAP:
330811878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_1000HDX_CAP:
330911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_1000FDX_CAP:
331011878SVenu.Iyer@Sun.COM case MAC_PROP_EN_1000HDX_CAP:
331111878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100FDX_CAP:
331211878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100HDX_CAP:
331311878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100T4_CAP:
331411878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10FDX_CAP:
331511878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10HDX_CAP:
331611878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
331711878SVenu.Iyer@Sun.COM return;
331811878SVenu.Iyer@Sun.COM
331911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100FDX_CAP:
332011878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
332111878SVenu.Iyer@Sun.COM MII_STATUS_100_BASEX_FD) != 0;
332211878SVenu.Iyer@Sun.COM break;
332311878SVenu.Iyer@Sun.COM
332411878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100HDX_CAP:
332511878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
332611878SVenu.Iyer@Sun.COM MII_STATUS_100_BASEX) != 0;
332711878SVenu.Iyer@Sun.COM break;
332811878SVenu.Iyer@Sun.COM
332911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100T4_CAP:
333011878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
333111878SVenu.Iyer@Sun.COM MII_STATUS_100_BASE_T4) != 0;
333211878SVenu.Iyer@Sun.COM break;
333311878SVenu.Iyer@Sun.COM
333411878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10FDX_CAP:
333511878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
333611878SVenu.Iyer@Sun.COM MII_STATUS_10_FD) != 0;
333711878SVenu.Iyer@Sun.COM break;
333811878SVenu.Iyer@Sun.COM
333911878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10HDX_CAP:
334011878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
334111878SVenu.Iyer@Sun.COM MII_STATUS_10) != 0;
334211878SVenu.Iyer@Sun.COM break;
334311878SVenu.Iyer@Sun.COM
334411878SVenu.Iyer@Sun.COM case MAC_PROP_AUTONEG:
334511878SVenu.Iyer@Sun.COM case MAC_PROP_EN_AUTONEG:
334611878SVenu.Iyer@Sun.COM val = (vrp->chip.mii.status &
334711878SVenu.Iyer@Sun.COM MII_STATUS_CANAUTONEG) != 0;
334811878SVenu.Iyer@Sun.COM break;
334911878SVenu.Iyer@Sun.COM
335011878SVenu.Iyer@Sun.COM case MAC_PROP_FLOWCTRL:
335111878SVenu.Iyer@Sun.COM mac_prop_info_set_default_link_flowctrl(prh,
335211878SVenu.Iyer@Sun.COM LINK_FLOWCTRL_BI);
335311878SVenu.Iyer@Sun.COM return;
335411878SVenu.Iyer@Sun.COM
335511878SVenu.Iyer@Sun.COM case MAC_PROP_MTU:
335611878SVenu.Iyer@Sun.COM mac_prop_info_set_range_uint32(prh,
335711878SVenu.Iyer@Sun.COM ETHERMTU, ETHERMTU);
335811878SVenu.Iyer@Sun.COM return;
335911878SVenu.Iyer@Sun.COM
336011878SVenu.Iyer@Sun.COM case MAC_PROP_DUPLEX:
336111878SVenu.Iyer@Sun.COM /*
336211878SVenu.Iyer@Sun.COM * Writability depends on autoneg.
336311878SVenu.Iyer@Sun.COM */
336411878SVenu.Iyer@Sun.COM perm = ((vrp->chip.mii.control &
336511878SVenu.Iyer@Sun.COM MII_CONTROL_ANE) == 0) ? MAC_PROP_PERM_RW :
336611878SVenu.Iyer@Sun.COM MAC_PROP_PERM_READ;
336711878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, perm);
336811878SVenu.Iyer@Sun.COM
336911878SVenu.Iyer@Sun.COM if (perm == MAC_PROP_PERM_RW) {
337011878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh,
337111878SVenu.Iyer@Sun.COM VR_LINK_DUPLEX_FULL);
337211878SVenu.Iyer@Sun.COM }
337311878SVenu.Iyer@Sun.COM return;
337411878SVenu.Iyer@Sun.COM
337511878SVenu.Iyer@Sun.COM case MAC_PROP_SPEED:
337611878SVenu.Iyer@Sun.COM perm = ((vrp->chip.mii.control &
337711878SVenu.Iyer@Sun.COM MII_CONTROL_ANE) == 0) ?
337811878SVenu.Iyer@Sun.COM MAC_PROP_PERM_RW : MAC_PROP_PERM_READ;
337911878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, perm);
338011878SVenu.Iyer@Sun.COM
338111878SVenu.Iyer@Sun.COM if (perm == MAC_PROP_PERM_RW) {
338211878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint64(prh,
338311878SVenu.Iyer@Sun.COM 100 * 1000 * 1000);
338411878SVenu.Iyer@Sun.COM }
338511878SVenu.Iyer@Sun.COM return;
338611878SVenu.Iyer@Sun.COM
338711878SVenu.Iyer@Sun.COM case MAC_PROP_STATUS:
338811878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
338911878SVenu.Iyer@Sun.COM return;
339011878SVenu.Iyer@Sun.COM
339111878SVenu.Iyer@Sun.COM default:
339211878SVenu.Iyer@Sun.COM return;
339311878SVenu.Iyer@Sun.COM }
339411878SVenu.Iyer@Sun.COM
339511878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(prh, val);
339611878SVenu.Iyer@Sun.COM }
339711878SVenu.Iyer@Sun.COM
33989540SJoost.Mulders@Sun.COM /*
33999540SJoost.Mulders@Sun.COM * Set a property of the device.
34009540SJoost.Mulders@Sun.COM */
34019540SJoost.Mulders@Sun.COM int
vr_mac_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)34029540SJoost.Mulders@Sun.COM vr_mac_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
34039540SJoost.Mulders@Sun.COM uint_t pr_valsize, const void *pr_val)
34049540SJoost.Mulders@Sun.COM {
34059540SJoost.Mulders@Sun.COM vr_t *vrp;
34069540SJoost.Mulders@Sun.COM uint32_t err;
34079540SJoost.Mulders@Sun.COM uint64_t val;
34089540SJoost.Mulders@Sun.COM
34099540SJoost.Mulders@Sun.COM /* Since we have no private properties */
34109540SJoost.Mulders@Sun.COM _NOTE(ARGUNUSED(pr_name))
34119540SJoost.Mulders@Sun.COM
34129540SJoost.Mulders@Sun.COM err = 0;
34139540SJoost.Mulders@Sun.COM vrp = (vr_t *)arg;
34149540SJoost.Mulders@Sun.COM mutex_enter(&vrp->oplock);
34159540SJoost.Mulders@Sun.COM
34169540SJoost.Mulders@Sun.COM /*
34179540SJoost.Mulders@Sun.COM * The current set of public property values are passed as integers
34189540SJoost.Mulders@Sun.COM * Private properties are passed as strings in pr_val length pr_valsize.
34199540SJoost.Mulders@Sun.COM */
34209540SJoost.Mulders@Sun.COM if (pr_num != MAC_PROP_PRIVATE) {
34219540SJoost.Mulders@Sun.COM if (pr_valsize == sizeof (uint64_t))
34229540SJoost.Mulders@Sun.COM val = *(uint64_t *)pr_val;
34239540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint32_t))
34249540SJoost.Mulders@Sun.COM val = *(uint32_t *)pr_val;
34259540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint16_t))
34269540SJoost.Mulders@Sun.COM val = *(uint32_t *)pr_val;
34279540SJoost.Mulders@Sun.COM else if (pr_valsize == sizeof (uint8_t))
34289540SJoost.Mulders@Sun.COM val = *(uint8_t *)pr_val;
34299540SJoost.Mulders@Sun.COM else {
34309540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
34319540SJoost.Mulders@Sun.COM return (EINVAL);
34329540SJoost.Mulders@Sun.COM }
34339540SJoost.Mulders@Sun.COM }
34349540SJoost.Mulders@Sun.COM
34359540SJoost.Mulders@Sun.COM switch (pr_num) {
34369540SJoost.Mulders@Sun.COM case MAC_PROP_DUPLEX:
34379540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.control & MII_CONTROL_ANE) == 0) {
34389540SJoost.Mulders@Sun.COM if (val == LINK_DUPLEX_FULL)
34399540SJoost.Mulders@Sun.COM vrp->chip.mii.control |=
34409540SJoost.Mulders@Sun.COM MII_CONTROL_FDUPLEX;
34419540SJoost.Mulders@Sun.COM else if (val == LINK_DUPLEX_HALF)
34429540SJoost.Mulders@Sun.COM vrp->chip.mii.control &=
34439540SJoost.Mulders@Sun.COM ~MII_CONTROL_FDUPLEX;
34449540SJoost.Mulders@Sun.COM else
34459540SJoost.Mulders@Sun.COM err = EINVAL;
34469540SJoost.Mulders@Sun.COM } else
34479540SJoost.Mulders@Sun.COM err = EINVAL;
34489540SJoost.Mulders@Sun.COM break;
34499540SJoost.Mulders@Sun.COM
34509540SJoost.Mulders@Sun.COM case MAC_PROP_EN_100FDX_CAP:
34519540SJoost.Mulders@Sun.COM if (val == 0)
34529540SJoost.Mulders@Sun.COM vrp->param.anadv_en &=
34539540SJoost.Mulders@Sun.COM ~MII_ABILITY_100BASE_TX_FD;
34549540SJoost.Mulders@Sun.COM else
34559540SJoost.Mulders@Sun.COM vrp->param.anadv_en |=
34569540SJoost.Mulders@Sun.COM MII_ABILITY_100BASE_TX_FD;
34579540SJoost.Mulders@Sun.COM break;
34589540SJoost.Mulders@Sun.COM
34599540SJoost.Mulders@Sun.COM case MAC_PROP_EN_100HDX_CAP:
34609540SJoost.Mulders@Sun.COM if (val == 0)
34619540SJoost.Mulders@Sun.COM vrp->param.anadv_en &=
34629540SJoost.Mulders@Sun.COM ~MII_ABILITY_100BASE_TX;
34639540SJoost.Mulders@Sun.COM else
34649540SJoost.Mulders@Sun.COM vrp->param.anadv_en |=
34659540SJoost.Mulders@Sun.COM MII_ABILITY_100BASE_TX;
34669540SJoost.Mulders@Sun.COM break;
34679540SJoost.Mulders@Sun.COM
34689540SJoost.Mulders@Sun.COM case MAC_PROP_EN_100T4_CAP:
34699540SJoost.Mulders@Sun.COM if (val == 0)
34709540SJoost.Mulders@Sun.COM vrp->param.anadv_en &=
34719540SJoost.Mulders@Sun.COM ~MII_ABILITY_100BASE_T4;
34729540SJoost.Mulders@Sun.COM else
34739540SJoost.Mulders@Sun.COM vrp->param.anadv_en |=
34749540SJoost.Mulders@Sun.COM MII_ABILITY_100BASE_T4;
34759540SJoost.Mulders@Sun.COM break;
34769540SJoost.Mulders@Sun.COM
34779540SJoost.Mulders@Sun.COM case MAC_PROP_EN_10FDX_CAP:
34789540SJoost.Mulders@Sun.COM if (val == 0)
34799540SJoost.Mulders@Sun.COM vrp->param.anadv_en &=
34809540SJoost.Mulders@Sun.COM ~MII_ABILITY_10BASE_T_FD;
34819540SJoost.Mulders@Sun.COM else
34829540SJoost.Mulders@Sun.COM vrp->param.anadv_en |=
34839540SJoost.Mulders@Sun.COM MII_ABILITY_10BASE_T_FD;
34849540SJoost.Mulders@Sun.COM break;
34859540SJoost.Mulders@Sun.COM
34869540SJoost.Mulders@Sun.COM case MAC_PROP_EN_10HDX_CAP:
34879540SJoost.Mulders@Sun.COM if (val == 0)
34889540SJoost.Mulders@Sun.COM vrp->param.anadv_en &=
34899540SJoost.Mulders@Sun.COM ~MII_ABILITY_10BASE_T;
34909540SJoost.Mulders@Sun.COM else
34919540SJoost.Mulders@Sun.COM vrp->param.anadv_en |=
34929540SJoost.Mulders@Sun.COM MII_ABILITY_10BASE_T;
34939540SJoost.Mulders@Sun.COM break;
34949540SJoost.Mulders@Sun.COM
34959540SJoost.Mulders@Sun.COM case MAC_PROP_AUTONEG:
34969540SJoost.Mulders@Sun.COM case MAC_PROP_EN_AUTONEG:
34979540SJoost.Mulders@Sun.COM if (val == 0) {
34989540SJoost.Mulders@Sun.COM vrp->param.an_en = VR_LINK_AUTONEG_OFF;
34999540SJoost.Mulders@Sun.COM vrp->chip.mii.control &= ~MII_CONTROL_ANE;
35009540SJoost.Mulders@Sun.COM } else {
35019540SJoost.Mulders@Sun.COM vrp->param.an_en = VR_LINK_AUTONEG_ON;
35029540SJoost.Mulders@Sun.COM if ((vrp->chip.mii.status &
35039540SJoost.Mulders@Sun.COM MII_STATUS_CANAUTONEG) != 0)
35049540SJoost.Mulders@Sun.COM vrp->chip.mii.control |=
35059540SJoost.Mulders@Sun.COM MII_CONTROL_ANE;
35069540SJoost.Mulders@Sun.COM else
35079540SJoost.Mulders@Sun.COM err = EINVAL;
35089540SJoost.Mulders@Sun.COM }
35099540SJoost.Mulders@Sun.COM break;
35109540SJoost.Mulders@Sun.COM
35119540SJoost.Mulders@Sun.COM case MAC_PROP_FLOWCTRL:
35129540SJoost.Mulders@Sun.COM if (val == LINK_FLOWCTRL_NONE)
35139860Sgdamore@opensolaris.org vrp->param.anadv_en &= ~MII_ABILITY_PAUSE;
35149540SJoost.Mulders@Sun.COM else if (val == LINK_FLOWCTRL_BI)
35159860Sgdamore@opensolaris.org vrp->param.anadv_en |= MII_ABILITY_PAUSE;
35169540SJoost.Mulders@Sun.COM else
35179540SJoost.Mulders@Sun.COM err = EINVAL;
35189540SJoost.Mulders@Sun.COM break;
35199540SJoost.Mulders@Sun.COM
35209540SJoost.Mulders@Sun.COM case MAC_PROP_MTU:
35219540SJoost.Mulders@Sun.COM if (val >= ETHERMIN && val <= ETHERMTU)
35229540SJoost.Mulders@Sun.COM vrp->param.mtu = (uint32_t)val;
35239540SJoost.Mulders@Sun.COM else
35249540SJoost.Mulders@Sun.COM err = EINVAL;
35259540SJoost.Mulders@Sun.COM break;
35269540SJoost.Mulders@Sun.COM
35279540SJoost.Mulders@Sun.COM case MAC_PROP_SPEED:
35289540SJoost.Mulders@Sun.COM if (val == 10 * 1000 * 1000)
35299540SJoost.Mulders@Sun.COM vrp->chip.link.speed =
35309540SJoost.Mulders@Sun.COM VR_LINK_SPEED_10MBS;
35319540SJoost.Mulders@Sun.COM else if (val == 100 * 1000 * 1000)
35329540SJoost.Mulders@Sun.COM vrp->chip.link.speed =
35339540SJoost.Mulders@Sun.COM VR_LINK_SPEED_100MBS;
35349540SJoost.Mulders@Sun.COM else
35359540SJoost.Mulders@Sun.COM err = EINVAL;
35369540SJoost.Mulders@Sun.COM break;
35379540SJoost.Mulders@Sun.COM
35389540SJoost.Mulders@Sun.COM default:
35399540SJoost.Mulders@Sun.COM err = ENOTSUP;
35409540SJoost.Mulders@Sun.COM break;
35419540SJoost.Mulders@Sun.COM }
35429540SJoost.Mulders@Sun.COM if (err == 0 && pr_num != MAC_PROP_PRIVATE) {
35439540SJoost.Mulders@Sun.COM vrp->chip.mii.anadv = vrp->param.anadv_en &
35449540SJoost.Mulders@Sun.COM (vrp->param.an_phymask & vrp->param.an_macmask);
35459540SJoost.Mulders@Sun.COM vr_link_init(vrp);
35469540SJoost.Mulders@Sun.COM }
35479540SJoost.Mulders@Sun.COM mutex_exit(&vrp->oplock);
35489540SJoost.Mulders@Sun.COM return (err);
35499540SJoost.Mulders@Sun.COM }
35509540SJoost.Mulders@Sun.COM
35519540SJoost.Mulders@Sun.COM
35529540SJoost.Mulders@Sun.COM /*
35539540SJoost.Mulders@Sun.COM * Logging and debug functions.
35549540SJoost.Mulders@Sun.COM */
35559540SJoost.Mulders@Sun.COM static struct {
35569540SJoost.Mulders@Sun.COM kmutex_t mutex[1];
35579540SJoost.Mulders@Sun.COM const char *ifname;
35589540SJoost.Mulders@Sun.COM const char *fmt;
35599540SJoost.Mulders@Sun.COM int level;
35609540SJoost.Mulders@Sun.COM } prtdata;
35619540SJoost.Mulders@Sun.COM
35629540SJoost.Mulders@Sun.COM static void
vr_vprt(const char * fmt,va_list args)35639540SJoost.Mulders@Sun.COM vr_vprt(const char *fmt, va_list args)
35649540SJoost.Mulders@Sun.COM {
35659540SJoost.Mulders@Sun.COM char buf[512];
35669540SJoost.Mulders@Sun.COM
35679540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(prtdata.mutex));
35689540SJoost.Mulders@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, args);
35699540SJoost.Mulders@Sun.COM cmn_err(prtdata.level, prtdata.fmt, prtdata.ifname, buf);
35709540SJoost.Mulders@Sun.COM }
35719540SJoost.Mulders@Sun.COM
35729540SJoost.Mulders@Sun.COM static void
vr_log(vr_t * vrp,int level,const char * fmt,...)35739540SJoost.Mulders@Sun.COM vr_log(vr_t *vrp, int level, const char *fmt, ...)
35749540SJoost.Mulders@Sun.COM {
35759540SJoost.Mulders@Sun.COM va_list args;
35769540SJoost.Mulders@Sun.COM
35779540SJoost.Mulders@Sun.COM mutex_enter(prtdata.mutex);
35789540SJoost.Mulders@Sun.COM prtdata.ifname = vrp->ifname;
35799540SJoost.Mulders@Sun.COM prtdata.fmt = "!%s: %s";
35809540SJoost.Mulders@Sun.COM prtdata.level = level;
35819540SJoost.Mulders@Sun.COM
35829540SJoost.Mulders@Sun.COM va_start(args, fmt);
35839540SJoost.Mulders@Sun.COM vr_vprt(fmt, args);
35849540SJoost.Mulders@Sun.COM va_end(args);
35859540SJoost.Mulders@Sun.COM
35869540SJoost.Mulders@Sun.COM mutex_exit(prtdata.mutex);
35879540SJoost.Mulders@Sun.COM }
35889540SJoost.Mulders@Sun.COM
35899540SJoost.Mulders@Sun.COM #if defined(DEBUG)
35909540SJoost.Mulders@Sun.COM static void
vr_prt(const char * fmt,...)35919540SJoost.Mulders@Sun.COM vr_prt(const char *fmt, ...)
35929540SJoost.Mulders@Sun.COM {
35939540SJoost.Mulders@Sun.COM va_list args;
35949540SJoost.Mulders@Sun.COM
35959540SJoost.Mulders@Sun.COM ASSERT(mutex_owned(prtdata.mutex));
35969540SJoost.Mulders@Sun.COM
35979540SJoost.Mulders@Sun.COM va_start(args, fmt);
35989540SJoost.Mulders@Sun.COM vr_vprt(fmt, args);
35999540SJoost.Mulders@Sun.COM va_end(args);
36009540SJoost.Mulders@Sun.COM
36019540SJoost.Mulders@Sun.COM mutex_exit(prtdata.mutex);
36029540SJoost.Mulders@Sun.COM }
36039540SJoost.Mulders@Sun.COM
36049540SJoost.Mulders@Sun.COM void
vr_debug()36059540SJoost.Mulders@Sun.COM (*vr_debug())(const char *fmt, ...)
36069540SJoost.Mulders@Sun.COM {
36079540SJoost.Mulders@Sun.COM mutex_enter(prtdata.mutex);
36089540SJoost.Mulders@Sun.COM prtdata.ifname = MODULENAME;
36099540SJoost.Mulders@Sun.COM prtdata.fmt = "^%s: %s\n";
36109540SJoost.Mulders@Sun.COM prtdata.level = CE_CONT;
36119540SJoost.Mulders@Sun.COM
36129540SJoost.Mulders@Sun.COM return (vr_prt);
36139540SJoost.Mulders@Sun.COM }
36149540SJoost.Mulders@Sun.COM #endif /* DEBUG */
36159540SJoost.Mulders@Sun.COM
36169540SJoost.Mulders@Sun.COM DDI_DEFINE_STREAM_OPS(vr_dev_ops, nulldev, nulldev, vr_attach, vr_detach,
36179540SJoost.Mulders@Sun.COM nodev, NULL, D_MP, NULL, vr_quiesce);
36189540SJoost.Mulders@Sun.COM
36199540SJoost.Mulders@Sun.COM static struct modldrv vr_modldrv = {
36209540SJoost.Mulders@Sun.COM &mod_driverops, /* Type of module. This one is a driver */
36219540SJoost.Mulders@Sun.COM vr_ident, /* short description */
36229540SJoost.Mulders@Sun.COM &vr_dev_ops /* driver specific ops */
36239540SJoost.Mulders@Sun.COM };
36249540SJoost.Mulders@Sun.COM
36259540SJoost.Mulders@Sun.COM static struct modlinkage modlinkage = {
36269540SJoost.Mulders@Sun.COM MODREV_1, (void *)&vr_modldrv, NULL
36279540SJoost.Mulders@Sun.COM };
36289540SJoost.Mulders@Sun.COM
36299540SJoost.Mulders@Sun.COM int
_info(struct modinfo * modinfop)36309540SJoost.Mulders@Sun.COM _info(struct modinfo *modinfop)
36319540SJoost.Mulders@Sun.COM {
36329540SJoost.Mulders@Sun.COM return (mod_info(&modlinkage, modinfop));
36339540SJoost.Mulders@Sun.COM }
36349540SJoost.Mulders@Sun.COM
36359540SJoost.Mulders@Sun.COM int
_init(void)36369540SJoost.Mulders@Sun.COM _init(void)
36379540SJoost.Mulders@Sun.COM {
36389540SJoost.Mulders@Sun.COM int status;
36399540SJoost.Mulders@Sun.COM
36409540SJoost.Mulders@Sun.COM mac_init_ops(&vr_dev_ops, MODULENAME);
36419540SJoost.Mulders@Sun.COM status = mod_install(&modlinkage);
36429540SJoost.Mulders@Sun.COM if (status == DDI_SUCCESS)
36439540SJoost.Mulders@Sun.COM mutex_init(prtdata.mutex, NULL, MUTEX_DRIVER, NULL);
36449540SJoost.Mulders@Sun.COM else
36459540SJoost.Mulders@Sun.COM mac_fini_ops(&vr_dev_ops);
36469540SJoost.Mulders@Sun.COM return (status);
36479540SJoost.Mulders@Sun.COM }
36489540SJoost.Mulders@Sun.COM
36499540SJoost.Mulders@Sun.COM int
_fini(void)36509540SJoost.Mulders@Sun.COM _fini(void)
36519540SJoost.Mulders@Sun.COM {
36529540SJoost.Mulders@Sun.COM int status;
36539540SJoost.Mulders@Sun.COM
36549540SJoost.Mulders@Sun.COM status = mod_remove(&modlinkage);
36559540SJoost.Mulders@Sun.COM if (status == 0) {
36569540SJoost.Mulders@Sun.COM mac_fini_ops(&vr_dev_ops);
36579540SJoost.Mulders@Sun.COM mutex_destroy(prtdata.mutex);
36589540SJoost.Mulders@Sun.COM }
36599540SJoost.Mulders@Sun.COM return (status);
36609540SJoost.Mulders@Sun.COM }
3661