82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * This file and its contents are supplied under the terms of the
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * You may only use this file in accordance with the terms of version
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * 1.0 of the CDDL.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * A full copy of the text of the CDDL should have accompanied this
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * source. A copy of the CDDL is also available via the Internet at
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * http://www.illumos.org/license/CDDL.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
197c9523b8946cf70fab2bc4ee633b18fc5bde68Marcel Telka * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Intel Pro/100B Ethernet Driver
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/types.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/modctl.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/conf.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/kmem.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/ksynch.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/cmn_err.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/note.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/pci.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/pci_cap.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/ethernet.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/mii.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/miiregs.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/mac.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/mac_ether.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/ethernet.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/vlan.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/list.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/sysmacros.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/varargs.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/stream.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/strsun.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/ddi.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include <sys/sunddi.h>
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include "iprb.h"
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#include "rcvbundl.h"
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Intel has openly documented the programming interface for these
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * parts in the "Intel 8255x 10/100 Mbps Ethernet Controller Family
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Open Source Software Developer Manual".
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * While some open source systems have utilized many of the features
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * of some models in this family (especially scatter gather and IP
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * checksum support), we have elected to offer only the basic
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * functionality. These are only 10/100 parts, and the additional
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * complexity is not justified by the minimal performance benefit.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * KISS. So, we are only supporting the simple 82557 features.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic uint16_t iprb_mii_read(void *, uint8_t, uint8_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_mii_write(void *, uint8_t, uint8_t, uint16_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_mii_notify(void *, link_state_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_attach(dev_info_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_detach(dev_info_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_quiesce(dev_info_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_suspend(dev_info_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_resume(dev_info_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_stat(void *, uint_t, uint64_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_start(void *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_m_stop(void *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_promisc(void *, boolean_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_multicst(void *, boolean_t, const uint8_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_unicst(void *, const uint8_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic mblk_t *iprb_m_tx(void *, mblk_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_m_ioctl(void *, queue_t *, mblk_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore const void *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore void *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_m_propinfo(void *, const char *, mac_prop_id_t,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_prop_info_handle_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_destroy(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_configure(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_eeprom_sendbits(iprb_t *, uint32_t, uint8_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic uint16_t iprb_eeprom_read(iprb_t *, uint16_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_identify(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_cmd_submit(iprb_t *, uint16_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_cmd_reclaim(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_cmd_ready(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_cmd_drain(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_rx_add(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_rx_init(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic mblk_t *iprb_rx(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic mblk_t *iprb_send(iprb_t *, mblk_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic uint_t iprb_intr(caddr_t, caddr_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_periodic(void *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_add_intr(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_dma_alloc(iprb_t *, iprb_dma_t *, size_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_dma_free(iprb_dma_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic iprb_dma_t *iprb_cmd_next(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_set_config(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_set_unicast(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_set_multicast(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_set_ucode(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_update_stats(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_start(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_stop(iprb_t *);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic int iprb_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic void iprb_error(iprb_t *, const char *, ...);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic mii_ops_t iprb_mii_ops = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore MII_OPS_VERSION,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mii_read,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mii_write,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mii_notify,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore NULL, /* reset */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic mac_callbacks_t iprb_m_callbacks = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_stat,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_start,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_stop,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_promisc,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_multicst,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_unicst,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_tx,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore NULL,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_ioctl, /* mc_ioctl */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore NULL, /* mc_getcapab */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore NULL, /* mc_open */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore NULL, /* mc_close */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_setprop,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_getprop,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_m_propinfo
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Stream information
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDDI_DEFINE_STREAM_OPS(iprb_devops, nulldev, nulldev,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_ddi_attach, iprb_ddi_detach, nodev, NULL, D_MP, NULL, iprb_quiesce);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic struct modldrv iprb_modldrv = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &mod_driverops, /* drv_modops */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore "Intel 8255x Ethernet", /* drv_linkinfo */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &iprb_devops /* drv_dev_ops */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic struct modlinkage iprb_modlinkage = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore MODREV_1, /* ml_rev */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { &iprb_modldrv, NULL } /* ml_linkage */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic ddi_device_acc_attr_t acc_attr = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_DEVICE_ATTR_V0,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_STRUCTURE_LE_ACC,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_STRICTORDER_ACC
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic ddi_device_acc_attr_t buf_attr = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_DEVICE_ATTR_V0,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_NEVERSWAP_ACC,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_STORECACHING_OK_ACC
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * The 8225x is a 32-bit addressing engine, but it can only address up
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * to 31 bits on a single transaction. (Far less in reality it turns
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * out.) Statistics buffers have to be 16-byte aligned, and as we
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * allocate individual data pieces for other things, there is no
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * compelling reason to use another attribute with support for less
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * strict alignment.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic ddi_dma_attr_t dma_attr = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DMA_ATTR_V0, /* dma_attr_version */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0, /* dma_attr_addr_lo */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0xFFFFFFFFU, /* dma_attr_addr_hi */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0x7FFFFFFFU, /* dma_attr_count_max */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 16, /* dma_attr_align */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0x100, /* dma_attr_burstsizes */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 1, /* dma_attr_minxfer */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0xFFFFFFFFU, /* dma_attr_maxxfer */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0xFFFFFFFFU, /* dma_attr_seg */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 1, /* dma_attr_sgllen */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 1, /* dma_attr_granular */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 0 /* dma_attr_flags */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#define DECL_UCODE(x) \
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore static const uint32_t x ## _WORDS[] = x ## _RCVBUNDLE_UCODE
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D101_A);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D101_B0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D101M_B);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D101S);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D102_B);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D102_C);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'AmoreDECL_UCODE(D102_E);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic uint8_t iprb_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore/*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * We don't bother allowing for tuning of the CPU saver algorithm.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * The ucode has reasonable defaults built-in. However, some variants
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * apparently have bug fixes delivered via this ucode, so we still
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * need to support the ucode upload.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoretypedef struct {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint8_t rev;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint8_t length;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore const uint32_t *ucode;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore} iprb_ucode_t;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore#define UCODE(x) \
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore sizeof (x ## _WORDS) / sizeof (uint32_t), x ## _WORDS
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorestatic const iprb_ucode_t iprb_ucode[] = {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82558_A4, UCODE(D101_A) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82558_B0, UCODE(D101_B0) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82559_A0, UCODE(D101M_B) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82559S_A, UCODE(D101S) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82550, UCODE(D102_B) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82550_C, UCODE(D102_C) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { REV_82551_F, UCODE(D102_E) },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore { 0 },
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore};
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore_init(void)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int rv;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_init_ops(&iprb_devops, "iprb");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((rv = mod_install(&iprb_modlinkage)) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_fini_ops(&iprb_devops);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (rv);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore_fini(void)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int rv;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((rv = mod_remove(&iprb_modlinkage)) == DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_fini_ops(&iprb_devops);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (rv);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore_info(struct modinfo *modinfop)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mod_info(&iprb_modlinkage, modinfop));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_attach(dev_info_t *dip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t w;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_register_t *macp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip = kmem_zalloc(sizeof (*ip), KM_SLEEP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_set_driver_private(dip, ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->dip = dip;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_create(&ip->mcast, sizeof (struct iprb_mcast),
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore offsetof(struct iprb_mcast, node));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* we don't support high level interrupts, so we don't need cookies */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_init(&ip->culock, NULL, MUTEX_DRIVER, NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_init(&ip->rulock, NULL, MUTEX_DRIVER, NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (pci_config_setup(dip, &ip->pcih) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to map configuration space");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_regs_map_setup(dip, 1, &ip->regs, 0, 0, &acc_attr,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &ip->regsh) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to map device registers");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Reset, but first go into idle state */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SEL_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SW_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_INTCTL, INTCTL_MASK);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_INTCTL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Precalculate watchdog times.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ip->tx_timeout = TX_WATCHDOG;
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ip->rx_timeout = RX_WATCHDOG;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_identify(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Obtain our factory MAC address */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore w = iprb_eeprom_read(ip, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[0] = w & 0xff;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[1] = w >> 8;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore w = iprb_eeprom_read(ip, 1);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[2] = w & 0xff;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[3] = w >> 8;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore w = iprb_eeprom_read(ip, 2);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[4] = w & 0xff;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->factaddr[5] = w >> 8;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(ip->factaddr, ip->curraddr, 6);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->resumebug) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Generally, most devices we will ever see will
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * already have fixed firmware. Since I can't verify
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * the validity of the fix (no suitably downrev
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * hardware), we'll just do our best to avoid it for
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * devices that exhibit this behavior.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((iprb_eeprom_read(ip, 10) & 0x02) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* EEPROM fix was already applied, assume safe. */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->resumebug = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((iprb_eeprom_read(ip, 3) & 0x3) != 0x3) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmn_err(CE_CONT, "?Enabling RX errata workaround.\n");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rxhangbug = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Determine whether we have an MII or a legacy 80c24 */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore w = iprb_eeprom_read(ip, 6);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((w & 0x3f00) != 0x0600) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((ip->miih = mii_alloc(ip, dip, &iprb_mii_ops)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to allocate MII ops vector");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->canpause) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_set_pauseable(ip->miih, B_TRUE, B_FALSE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Allocate cmds and tx region */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_TX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Command blocks */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_dma_alloc(ip, &ip->cmds[i], CB_SIZE) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_TX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb = &ip->cmds[i];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Link the command blocks into a ring */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB32(cb, CB_LNK_OFFSET, (ip->cmds[(i + 1) % NUM_TX].paddr));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_RX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Rx packet buffers */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_dma_alloc(ip, &ip->rxb[i], RFD_SIZE) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_dma_alloc(ip, &ip->stats, STATS_SIZE) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_add_intr(ip) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to allocate mac structure");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_driver = ip;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_dip = dip;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_src_addr = ip->curraddr;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_callbacks = &iprb_m_callbacks;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_min_sdu = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_max_sdu = ETHERMTU;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore macp->m_margin = VLAN_TAGSZ;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mac_register(macp, &ip->mach) != 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to register mac with framework");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_free(macp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_free(macp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_detach(dev_info_t *dip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip = ddi_get_driver_private(dip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(ip != NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mac_disable(ip->mach) != 0)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) mac_unregister(ip->mach);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_destroy(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_add_intr(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int actual;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_intr_alloc(ip->dip, &ip->intrh, DDI_INTR_TYPE_FIXED, 0, 1,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "failed allocating interrupt handle");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_intr_add_handler(ip->intrh, iprb_intr, ip, NULL) !=
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_free(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->intrh = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "failed adding interrupt handler");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_intr_enable(ip->intrh) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_remove_handler(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_free(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->intrh = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "failed enabling interrupt");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_dma_alloc(iprb_t *ip, iprb_dma_t *h, size_t size)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore size_t rlen;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_dma_cookie_t dmac;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint_t ndmac;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_dma_alloc_handle(ip->dip, &dma_attr, DDI_DMA_SLEEP, NULL,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &h->dmah) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to allocate dma handle");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_dma_mem_alloc(h->dmah, size, &buf_attr, DDI_DMA_CONSISTENT,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_DMA_SLEEP, NULL, &h->vaddr, &rlen, &h->acch) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to allocate dma memory");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bzero(h->vaddr, size);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_dma_addr_bind_handle(h->dmah, NULL, h->vaddr, size,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_SLEEP, NULL,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore &dmac, &ndmac) != DDI_DMA_MAPPED) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to map command memory");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore h->paddr = dmac.dmac_address;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_dma_free(iprb_dma_t *h)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (h->paddr != 0)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_dma_unbind_handle(h->dmah);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore h->paddr = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (h->acch != NULL)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_dma_mem_free(&h->acch);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore h->acch = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (h->dmah != NULL)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_dma_free_handle(&h->dmah);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore h->dmah = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_destroy(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mcast_t *mc;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* shut down interrupts */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->intrh != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_disable(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_remove_handler(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) ddi_intr_free(ip->intrh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* release DMA resources */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_TX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_free(&ip->cmds[i]);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_RX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_free(&ip->rxb[i]);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_free(&ip->stats);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_free(ip->miih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* clean up the multicast list */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore while ((mc = list_head(&ip->mcast)) != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_remove(&ip->mcast, mc);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore kmem_free(mc, sizeof (*mc));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* tear down register mappings */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->pcih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore pci_config_teardown(&ip->pcih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->regsh)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_regs_map_free(&ip->regsh);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* clean the dip */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_set_driver_private(ip->dip, NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_destroy(&ip->mcast);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_destroy(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_destroy(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* and finally toss the structure itself */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore kmem_free(ip, sizeof (*ip));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_identify(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->devid = pci_config_get16(ip->pcih, PCI_CONF_DEVID);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->revid = pci_config_get8(ip->pcih, PCI_CONF_REVID);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (ip->devid) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1229: /* 8255x family */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1030: /* Intel InBusiness */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->revid >= REV_82558_A4) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canpause = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canmwi = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->is557 = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->revid >= REV_82559_A0)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->resumebug = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1209: /* Embedded 82559ER */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canpause = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->resumebug = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canmwi = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x2449: /* ICH2 */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1031: /* Pro/100 VE (ICH3) */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1032: /* Pro/100 VE (ICH3) */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1033: /* Pro/100 VM (ICH3) */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1034: /* Pro/100 VM (ICH3) */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case 0x1038: /* Pro/100 VM (ICH3) */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->resumebug = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->revid >= REV_82558_A4)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canpause = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore default:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->revid >= REV_82558_A4)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canpause = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Allow property override MWI support - not normally needed. */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ddi_prop_get_int(DDI_DEV_T_ANY, ip->dip, 0, "MWIEnable", 1) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->canmwi = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_eeprom_sendbits(iprb_t *ip, uint32_t val, uint8_t nbits)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint32_t mask;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t x;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mask = 1U << (nbits - 1);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore while (mask) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore x = (mask & val) ? EEPROM_EEDI : 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EESK | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mask >>= 1;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreuint16_t
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_eeprom_read(iprb_t *ip, uint16_t address)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t val;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int mask;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t n;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t bits;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* if we don't know the address size yet call again to determine it */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((address != 0) && (ip->eeprom_bits == 0))
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_eeprom_read(ip, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((bits = ip->eeprom_bits) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bits = 8;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(address == 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* enable the EEPROM chip select */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* send a read command */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_eeprom_sendbits(ip, 6, 3);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore n = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (mask = (1U << (bits - 1)); mask != 0; mask >>= 1) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t x = (mask & address) ? EEPROM_EEDI : 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EESK | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, x | EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore n++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* check the dummy 0 bit */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((GET16(ip, CSR_EECTL) & EEPROM_EEDO) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->eeprom_bits == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->eeprom_bits = n;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmn_err(CE_CONT, "?EEPROM size %d words.\n",
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore 1U << ip->eeprom_bits);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (n != ip->eeprom_bits) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "cannot determine EEPROM size (%d, %d)",
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->eeprom_bits, n);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* shift out a 16-bit word */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore val = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (mask = 0x8000; mask; mask >>= 1) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, EEPROM_EECS | EEPROM_EESK);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (GET16(ip, CSR_EECTL) & EEPROM_EEDO)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore val |= mask;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, EEPROM_EECS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* and disable the eeprom */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT16(ip, CSR_EECTL, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(100);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (val);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_cmd_ready(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* wait for pending SCB commands to be accepted */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (int cnt = 1000000; cnt != 0; cnt -= 10) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (GET8(ip, CSR_CMD) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "timeout waiting for chip to become ready");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_cmd_reclaim(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore while (ip->cmd_count) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb = &ip->cmds[ip->cmd_tail];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCCB(cb, CB_STS_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((GETCB16(cb, CB_STS_OFFSET) & CB_STS_C) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_tail++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_tail %= NUM_TX;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_count--;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->cmd_count == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->tx_wdog = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ip->tx_wdog = gethrtime();
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_cmd_drain(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (int i = 1000000; i; i -= 10) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_cmd_reclaim(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->cmd_count == 0)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "time out waiting for commands to drain");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_cmd_submit(iprb_t *ip, uint16_t cmd)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *ncb = &ip->cmds[ip->cmd_head];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *lcb = &ip->cmds[ip->cmd_last];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* If this command will consume the last CB, interrupt when done */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT((ip->cmd_count) < NUM_TX);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->cmd_count == (NUM_TX - 1)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmd |= CB_CMD_I;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* clear the status entry */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB16(ncb, CB_STS_OFFSET, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* suspend upon completion of this new command */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmd |= CB_CMD_S;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB16(ncb, CB_CMD_OFFSET, cmd);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCCB(ncb, 0, 0, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* clear the suspend flag from the last submitted command */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCCB(lcb, CB_CMD_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB16(lcb, CB_CMD_OFFSET, GETCB16(lcb, CB_CMD_OFFSET) & ~CB_CMD_S);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCCB(lcb, CB_CMD_OFFSET, 2, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * If the chip has a resume bug, then we need to try this as a work
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * around. Some anecdotal evidence is that this will help solve
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * the resume bug. Its a performance hit, but only if the EEPROM
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * is not updated. (In theory we could do this only for 10Mbps HDX,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * but since it should just about never get used, we keep it simple.)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->resumebug) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_NOP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(1);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* wait for the SCB to be ready to accept a new command */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Finally we can resume the CU. Note that if this the first
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * command in the sequence (i.e. if the CU is IDLE), or if the
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * CU is already busy working, then this CU resume command
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * will not have any effect.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_RESUME);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD); /* flush CSR */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ip->tx_wdog = gethrtime();
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_last = ip->cmd_head;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_head++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_head %= NUM_TX;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_count++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_dma_t *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_cmd_next(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->cmd_count == NUM_TX) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(ip->cmd_count < NUM_TX);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (&ip->cmds[ip->cmd_head]);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_set_unicast(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((cb = iprb_cmd_next(ip)) == NULL)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCBEA(cb, CB_IAS_ADR_OFFSET, ip->curraddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_cmd_submit(ip, CB_CMD_IAS));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_set_multicast(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mcast_t *mc;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_t *l;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((ip->nmcast <= 0) || (ip->nmcast > CB_MCS_CNT_MAX)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Only send the list if the total number of multicast
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * address is nonzero and small enough to fit. We
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * don't error out if it is too big, because in that
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * case we will use the "allmulticast" support
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * via iprb_set_config instead.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((cb = iprb_cmd_next(ip)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore l = &ip->mcast;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (mc = list_head(l), i = 0; mc; mc = list_next(l, mc), i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCBEA(cb, CB_MCS_ADR_OFFSET + (i * 6), mc->addr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(i == ip->nmcast);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB16(cb, CB_MCS_CNT_OFFSET, i);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_cmd_submit(ip, CB_CMD_MCS));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_set_config(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((cb = iprb_cmd_next(ip)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 0, 0x16);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 1, 0x8);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 2, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 3, (ip->canmwi ? 1 : 0));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 4, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 5, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 6, (ip->promisc ? 0x80 : 0) | 0x3a);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 7, (ip->promisc ? 0 : 0x1) | 2);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 8, (ip->miih ? 0x1 : 0));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 9, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 10, 0x2e);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 11, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 12, (ip->is557 ? 0 : 1) | 0x60);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 13, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 14, 0xf2);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 15,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (ip->miih ? 0x80 : 0) | (ip->promisc ? 0x1 : 0) | 0x48);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 16, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 17, (ip->canpause ? 0x40 : 0));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 18, (ip->is557 ? 0 : 0x8) | 0xf2);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 19,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((ip->revid < REV_82558_B0) ? 0 : 0x80) |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (ip->canpause ? 0x18 : 0));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 20, 0x3f);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_CONFIG_OFFSET + 21,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((ip->nmcast >= CB_MCS_CNT_MAX) ? 0x8 : 0) | 0x5);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_cmd_submit(ip, CB_CMD_CONFIG));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_set_ucode(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore const iprb_ucode_t *uc = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; iprb_ucode[i].length; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_ucode[i].rev == ip->revid) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uc = &iprb_ucode[i];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (uc == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* no matching firmware found, assume success */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((cb = iprb_cmd_next(ip)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < uc->length; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB32(cb, (CB_UCODE_OFFSET + i * 4), uc->ucode[i]);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_cmd_submit(ip, CB_CMD_UCODE));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_configure(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_drain(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_set_config(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_set_unicast(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_set_multicast(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_stop(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* go idle */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SEL_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET32(ip, CSR_PORT);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(50);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* shut off device interrupts */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_INTCTL, INTCTL_MASK);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_start(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->rulock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Reset, but first go into idle state */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SEL_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET32(ip, CSR_PORT);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(50);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SW_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET32(ip, CSR_PORT);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_INTCTL, INTCTL_MASK);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Reset pointers */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_head = ip->cmd_tail = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->cmd_last = NUM_TX - 1;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_CUBASE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, RUC_RUBASE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Send a NOP. This will be the first command seen by the device. */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cb = iprb_cmd_next(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(cb);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_submit(ip, CB_CMD_NOP) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* as that was the first command, go ahead and submit a CU start */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, cb->paddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_START);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Upload firmware. */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_set_ucode(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Set up RFDs */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_init(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, ip->rxb[0].paddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* wait for the SCB */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_cmd_ready(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, RUC_START);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD); /* flush CSR */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Enable device interrupts */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_INTCTL, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_INTCTL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_update_stats(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *sp = &ip->stats;
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek hrtime_t tstamp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Collect the hardware stats, but don't keep redoing it */
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek tstamp = gethrtime();
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek if (tstamp / NANOSEC == ip->stats_time / NANOSEC)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTSTAT(sp, STATS_DONE_OFFSET, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCSTATS(sp, 0, 0, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, sp->paddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_STATSBASE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_ready(ip) != DDI_SUCCESS)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, CUC_STATS_RST);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD); /* flush wb */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 10000; i; i -= 10) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCSTATS(sp, 0, 0, DDI_DMA_SYNC_FORKERNEL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (GETSTAT(sp, STATS_DONE_OFFSET) == STATS_RST_DONE) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* yay stats are updated */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (i == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "time out acquiring hardware statistics");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->ex_coll += GETSTAT(sp, STATS_TX_MAXCOL_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->late_coll += GETSTAT(sp, STATS_TX_LATECOL_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->uflo += GETSTAT(sp, STATS_TX_UFLO_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->defer_xmt += GETSTAT(sp, STATS_TX_DEFER_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->one_coll += GETSTAT(sp, STATS_TX_ONECOL_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->multi_coll += GETSTAT(sp, STATS_TX_MULTCOL_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->collisions += GETSTAT(sp, STATS_TX_TOTCOL_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->fcs_errs += GETSTAT(sp, STATS_RX_FCS_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->align_errs += GETSTAT(sp, STATS_RX_ALIGN_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->norcvbuf += GETSTAT(sp, STATS_RX_NOBUF_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->oflo += GETSTAT(sp, STATS_RX_OFLO_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->runt += GETSTAT(sp, STATS_RX_SHORT_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->stats_time = tstamp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoremblk_t *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_send(iprb_t *ip, mblk_t *mp)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *cb;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore size_t sz;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->culock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* possibly reclaim some CBs */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_cmd_reclaim(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cb = iprb_cmd_next(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (cb == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* flow control */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->wantw = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((sz = msgsize(mp)) > (ETHERMAX + VLAN_TAGSZ)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Generally this should never occur */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->macxmt_errs++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore freemsg(mp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->opackets++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->obytes += sz;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB32(cb, CB_TX_TBD_OFFSET, 0xffffffffU);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB16(cb, CB_TX_COUNT_OFFSET, (sz & 0x3fff) | CB_TX_EOF);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_TX_THRESH_OFFSET, (sz / 8) & 0xff);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTCB8(cb, CB_TX_NUMBER_OFFSET, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mcopymsg(mp, cb->vaddr + CB_TX_DATA_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (cb->vaddr[CB_TX_DATA_OFFSET] & 0x1) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (bcmp(cb->vaddr + CB_TX_DATA_OFFSET, &iprb_bcast, 6) != 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->multixmt++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->brdcstxmt++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCCB(cb, 0, CB_TX_DATA_OFFSET + sz, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_cmd_submit(ip, CB_CMD_TX) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->macxmt_errs++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (NULL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_rx_add(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t last, curr, next;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *rfd, *nfd, *lfd;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ASSERT(mutex_owned(&ip->rulock));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore curr = ip->rx_index;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore last = ip->rx_last;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore next = (curr + 1) % NUM_RX;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_last = curr;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_index = next;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore lfd = &ip->rxb[last];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore rfd = &ip->rxb[curr];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore nfd = &ip->rxb[next];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTRFD32(rfd, RFD_LNK_OFFSET, nfd->paddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTRFD16(rfd, RFD_CTL_OFFSET, RFD_CTL_EL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTRFD16(rfd, RFD_SIZ_OFFSET, RFD_SIZE - RFD_PKT_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTRFD16(rfd, RFD_CNT_OFFSET, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCRFD(rfd, 0, RFD_PKT_OFFSET, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* clear the suspend & EL bits from the previous RFD */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUTRFD16(lfd, RFD_CTL_OFFSET, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCRFD(rfd, RFD_CTL_OFFSET, 2, DDI_DMA_SYNC_FORDEV);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_rx_init(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_index = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_last = NUM_RX - 1;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (int i = 0; i < NUM_RX; i++)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_add(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_index = 0;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rx_last = NUM_RX - 1;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoremblk_t *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_rx(iprb_t *ip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_dma_t *rfd;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t cnt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint16_t sts;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int i;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mblk_t *mplist;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mblk_t **mpp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mblk_t *mp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mplist = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mpp = &mplist;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (i = 0; i < NUM_RX; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore rfd = &ip->rxb[ip->rx_index];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCRFD(rfd, RFD_STS_OFFSET, 2, DDI_DMA_SYNC_FORKERNEL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((GETRFD16(rfd, RFD_STS_OFFSET) & RFD_STS_C) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ip->rx_wdog = gethrtime();
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore SYNCRFD(rfd, 0, 0, DDI_DMA_SYNC_FORKERNEL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cnt = GETRFD16(rfd, RFD_CNT_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cnt &= ~(RFD_CNT_EOF | RFD_CNT_F);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore sts = GETRFD16(rfd, RFD_STS_OFFSET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (cnt > (ETHERMAX + VLAN_TAGSZ)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->toolong++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_add(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore continue;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (((sts & RFD_STS_OK) == 0) && (sts & RFD_STS_ERRS)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_add(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore continue;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((mp = allocb(cnt, BPRI_MED)) == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->norcvbuf++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_add(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore continue;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(rfd->vaddr + RFD_PKT_OFFSET, mp->b_wptr, cnt);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* return it to the RFD list */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_add(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp->b_wptr += cnt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->ipackets++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->rbytes += cnt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mp->b_rptr[0] & 0x1) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (bcmp(mp->b_rptr, &iprb_bcast, 6) != 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->multircv++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->brdcstrcv++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *mpp = mp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mpp = &mp->b_next;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mplist);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_promisc(void *arg, boolean_t on)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->promisc = on;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running && !ip->suspended)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_configure(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_unicst(void *arg, const uint8_t *macaddr)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(macaddr, ip->curraddr, 6);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running && !ip->suspended)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_configure(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_t *l = &ip->mcast;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_mcast_t *mc;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (add) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mc = kmem_alloc(sizeof (*mc), KM_NOSLEEP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mc == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (ENOMEM);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(macaddr, mc->addr, 6);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_insert_head(l, mc);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->nmcast++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running && !ip->suspended)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_configure(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (mc = list_head(l); mc != NULL; mc = list_next(l, mc)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (bcmp(macaddr, mc->addr, 6) == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore list_remove(&ip->mcast, mc);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->nmcast--;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running && !ip->suspended)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_configure(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mc)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore kmem_free(mc, sizeof (*mc));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_start(void *arg)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore int rv;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore rv = ip->suspended ? 0 : iprb_start(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (rv == 0)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->running = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->perh = ddi_periodic_add(iprb_periodic, ip, 5000000000, 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (rv == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_start(ip->miih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore else
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* might be a lie. */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_link_update(ip->mach, LINK_STATE_UP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (rv ? EIO : 0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_stop(void *arg)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_stop(ip->miih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore } else {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_link_update(ip->mach, LINK_STATE_DOWN);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
197c9523b8946cf70fab2bc4ee633b18fc5bde68Marcel Telka
197c9523b8946cf70fab2bc4ee633b18fc5bde68Marcel Telka ddi_periodic_delete(ip->perh);
197c9523b8946cf70fab2bc4ee633b18fc5bde68Marcel Telka ip->perh = 0;
197c9523b8946cf70fab2bc4ee633b18fc5bde68Marcel Telka
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (!ip->suspended) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_update_stats(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_stop(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->running = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_stat(void *arg, uint_t stat, uint64_t *val)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih && (mii_m_getstat(ip->miih, stat, val) == 0)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((!ip->suspended) && (ip->running)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_update_stats(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (stat) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_IFSPEED:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = 10000000; /* 10 Mbps */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_LINK_DUPLEX:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih == NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = LINK_DUPLEX_UNKNOWN;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_MULTIRCV:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->multircv;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_BRDCSTRCV:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->brdcstrcv;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_MULTIXMT:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->multixmt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_BRDCSTXMT:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->brdcstxmt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_IPACKETS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * val = ip->ipackets;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_RBYTES:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->rbytes;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_OPACKETS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->opackets;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_OBYTES:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->obytes;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_NORCVBUF:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->norcvbuf;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_COLLISIONS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->collisions;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_IERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->align_errs +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->fcs_errs +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->norcvbuf +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->runt +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->toolong +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->macrcv_errs;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_OERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->ex_coll +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->late_coll +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->uflo +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->macxmt_errs +
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->nocarrier;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_ALIGN_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->align_errs;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_FCS_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->fcs_errs;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_DEFER_XMTS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->defer_xmt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_FIRST_COLLISIONS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->one_coll + ip->multi_coll + ip->ex_coll;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_MULTI_COLLISIONS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->multi_coll;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_TX_LATE_COLLISIONS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->late_coll;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_EX_COLLISIONS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->ex_coll;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_OVERFLOWS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->oflo;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_STAT_UNDERFLOWS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->uflo;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_TOOSHORT_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->runt;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_TOOLONG_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->toolong;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_CARRIER_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->nocarrier; /* reported only for "suspend" */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_MACXMT_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->macxmt_errs;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case ETHER_STAT_MACRCV_ERRORS:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore *val = ip->macrcv_errs;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore default:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (ENOTSUP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_prop_info_handle_t pih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_m_propinfo(ip->miih, name, id, pih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (id) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_PROP_DUPLEX:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_PROP_SPEED:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_prop_info_set_perm(pih, MAC_PROP_PERM_READ);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t sz,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore void *val)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint64_t x;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mii_m_getprop(ip->miih, name, id, sz, val));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (id) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_PROP_SPEED:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore x = 10000000;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(&x, val, sizeof (x));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case MAC_PROP_DUPLEX:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore x = LINK_DUPLEX_UNKNOWN;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore bcopy(&x, val, sizeof (x));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (ENOTSUP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t sz,
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore const void *val)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mii_m_setprop(ip->miih, name, id, sz, val));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (ENOTSUP);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoremblk_t *
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_tx(void *arg, mblk_t *mp)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mblk_t *nmp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore while (mp != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore nmp = mp->b_next;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp->b_next = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->suspended) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore freemsg(mp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->nocarrier++;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp = nmp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore continue;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((mp = iprb_send(ip, mp)) != NULL) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp->b_next = nmp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp = nmp;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((ip->miih != NULL) && (mii_m_loop_ioctl(ip->miih, wq, mp)))
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore miocnak(wq, mp, 0, EINVAL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreuint16_t
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_mii_read(void *arg, uint8_t phy, uint8_t reg)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint32_t mdi;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * NB: we are guaranteed by the MII layer not to be suspended.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * Furthermore, we have an independent MII register.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mdi = MDI_OP_RD |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((uint32_t)phy << MDI_PHYAD_SHIFT) |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((uint32_t)reg << MDI_REGAD_SHIFT);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_MDICTL, mdi);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (int i = 0; i < 100; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mdi = GET32(ip, CSR_MDICTL);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mdi & MDI_R) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (mdi & 0xffff);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(1);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (0xffff);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint32_t mdi;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mdi = MDI_OP_WR |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((uint32_t)phy << MDI_PHYAD_SHIFT) |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((uint32_t)reg << MDI_REGAD_SHIFT) |
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (data);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_MDICTL, mdi);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore for (int i = 0; i < 100; i++) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (GET32(ip, CSR_MDICTL) & MDI_R)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore break;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_mii_notify(void *arg, link_state_t link)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_link_update(ip->mach, link);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreuint_t
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_intr(caddr_t arg1, caddr_t arg2)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = (void *)arg1;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore uint8_t sts;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mblk_t *mp = NULL;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore _NOTE(ARGUNUSED(arg2));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->suspended) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_INTR_UNCLAIMED);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore sts = GET8(ip, CSR_STS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (sts == 0) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* No interrupt status! */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_INTR_UNCLAIMED);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* acknowledge the interrupts */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_STS, sts);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (sts & (STS_RNR | STS_FR)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mp = iprb_rx(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((sts & STS_RNR) &&
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((GET8(ip, CSR_STATE) & STATE_RUS) == STATE_RUS_NORES)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_rx_init(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_GEN_PTR, ip->rxb[0].paddr);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* wait for the SCB */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) iprb_cmd_ready(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_CMD, RUC_START);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) GET8(ip, CSR_CMD); /* flush CSR */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (mp) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_rx(ip->mach, NULL, mp);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if ((sts & (STS_CNA | STS_CX)) && ip->wantw) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->wantw = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mac_tx_update(ip->mach);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_INTR_CLAIMED);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_periodic(void *arg)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = arg;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore boolean_t reset = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->suspended || !ip->running) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /*
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * If we haven't received a packet in a while, and if the link
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * is up, then it might be a hung chip. This problem
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore * reportedly only occurs at 10 Mbps.
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->rxhangbug &&
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ((ip->miih == NULL) || (mii_get_speed(ip->miih) == 10000000)) &&
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek ((gethrtime() - ip->rx_wdog) > ip->rx_timeout)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmn_err(CE_CONT, "?Possible RU hang, resetting.\n");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore reset = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* update the statistics */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
0529d5c654f682ce87e4f74affd1c83c429c50e1Josef 'Jeff' Sipek if (ip->tx_wdog && ((gethrtime() - ip->tx_wdog) > ip->tx_timeout)) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* transmit/CU hang? */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmn_err(CE_CONT, "?CU stalled, resetting.\n");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore reset = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (reset) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* We want to reconfigure */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_stop(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_start(ip) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to restart chip");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_update_stats(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_quiesce(dev_info_t *dip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = ddi_get_driver_private(dip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore /* Reset, but first go into idle state */
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SEL_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(50);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT32(ip, CSR_PORT, PORT_SW_RESET);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore drv_usecwait(10);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore PUT8(ip, CSR_INTCTL, INTCTL_MASK);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_suspend(dev_info_t *dip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = ddi_get_driver_private(dip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_suspend(ip->miih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (!ip->suspended) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->suspended = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_update_stats(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_stop(ip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_resume(dev_info_t *dip)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_t *ip = ddi_get_driver_private(dip);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_enter(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->suspended = B_FALSE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->running) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (iprb_start(ip) != DDI_SUCCESS) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore iprb_error(ip, "unable to restart chip!");
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ip->suspended = B_TRUE;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->culock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mutex_exit(&ip->rulock);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore if (ip->miih)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore mii_resume(ip->miih);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_SUCCESS);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (cmd) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case DDI_ATTACH:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_attach(dip));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case DDI_RESUME:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_resume(dip));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore default:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreint
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore switch (cmd) {
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case DDI_DETACH:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_detach(dip));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore case DDI_SUSPEND:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (iprb_suspend(dip));
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore default:
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore return (DDI_FAILURE);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore }
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amorevoid
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amoreiprb_error(iprb_t *ip, const char *fmt, ...)
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore{
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore va_list ap;
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore char buf[256];
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore va_start(ap, fmt);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore (void) vsnprintf(buf, sizeof (buf), fmt, ap);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore va_end(ap);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore cmn_err(CE_WARN, "%s%d: %s",
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore ddi_driver_name(ip->dip), ddi_get_instance(ip->dip), buf);
82743679557cf8b7a5dd51eaa0015e0ca498ac37Garrett D'Amore}