438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King/*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Copyright (c) 2011 Jason King.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Copyright (c) 2000 Berkeley Software Design, Inc.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Copyright (c) 1997, 1998, 1999, 2000
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Redistribution and use in source and binary forms, with or without
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * modification, are permitted provided that the following conditions
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * are met:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * 1. Redistributions of source code must retain the above copyright
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * notice, this list of conditions and the following disclaimer.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * 2. Redistributions in binary form must reproduce the above copyright
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * notice, this list of conditions and the following disclaimer in the
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * documentation and/or other materials provided with the distribution.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * 3. All advertising materials mentioning features or use of this software
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * must display the following acknowledgement:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * This product includes software developed by Bill Paul.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * 4. Neither the name of the author nor the names of any co-contributors
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * may be used to endorse or promote products derived from this software
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * without specific prior written permission.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * THE POSSIBILITY OF SUCH DAMAGE.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/varargs.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/types.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/modctl.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/devops.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/stream.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/strsun.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/cmn_err.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/ethernet.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/kmem.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/crc32.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/mii.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/miiregs.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/mac.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/mac_ether.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/ddi.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/sunddi.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/vlan.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/pci.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include <sys/conf.h>
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include "pcn.h"
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#include "pcnimpl.h"
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define ETHERVLANMTU (ETHERMAX + 4)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define CSR_WRITE_4(pcnp, reg, val) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_put32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg), val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define CSR_WRITE_2(pcnp, reg, val) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_put16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg), val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define CSR_READ_4(pcnp, reg) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_get32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define CSR_READ_2(pcnp, reg) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_get16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define PCN_CSR_SETBIT(pcnp, reg, x) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) | (x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define PCN_CSR_CLRBIT(pcnp, reg, x) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) & ~(x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define PCN_BCR_SETBIT(pncp, reg, x) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) | (x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King#define PCN_BCR_CLRBIT(pcnp, reg, x) \
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) & ~(x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_attach(dev_info_t *, ddi_attach_cmd_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_detach(dev_info_t *, ddi_detach_cmd_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_ddi_resume(dev_info_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_quiesce(dev_info_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_teardown(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_unicast(void *, const uint8_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_multicast(void *, boolean_t, const uint8_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_promisc(void *, boolean_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mblk_t *pcn_m_tx(void *, mblk_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_m_ioctl(void *, queue_t *, mblk_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_stat(void *, uint_t, uint64_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_start(void *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_m_stop(void *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King void *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King const void *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_m_propinfo(void *, const char *, mac_prop_id_t,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_prop_info_handle_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_watchdog(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic unsigned pcn_intr(caddr_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t pcn_mii_read(void *, uint8_t, uint8_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_mii_write(void *, uint8_t, uint8_t, uint16_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_mii_notify(void *, link_state_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint32_t pcn_csr_read(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t pcn_csr_read16(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_csr_write(pcn_t *, uint32_t, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint32_t pcn_bcr_read(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t pcn_bcr_read16(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_bcr_write(pcn_t *, uint32_t, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic boolean_t pcn_send(pcn_t *, mblk_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic pcn_buf_t *pcn_allocbuf(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_destroybuf(pcn_buf_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_allocrxring(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_alloctxring(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_freetxring(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_freerxring(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_resetrings(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_initialize(pcn_t *, boolean_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mblk_t *pcn_receive(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_resetall(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_startall(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_stopall(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_reclaim(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_getfactaddr(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_set_chipid(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic const pcn_type_t *pcn_match(uint16_t, uint16_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_start_timer(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_stop_timer(pcn_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_error(dev_info_t *, char *, ...);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingvoid *pcn_ssp = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uchar_t pcn_broadcast[ETHERADDRL] = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic const pcn_type_t pcn_devs[] = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King { PCN_VENDORID, PCN_DEVICEID_PCNET, "AMD PCnet/PCI 10/100BaseTX" },
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King { PCN_VENDORID, PCN_DEVICEID_HOME, "AMD PCnet/Home HomePNA" },
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King { 0, 0, NULL }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mii_ops_t pcn_mii_ops = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King MII_OPS_VERSION,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_mii_read,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_mii_write,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_mii_notify,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mac_callbacks_t pcn_m_callbacks = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_stat,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_start,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_stop,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_promisc,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_multicast,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_unicast,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_tx,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_ioctl,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL, /* mc_getcapab */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL, /* mc_open */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL, /* mc_close */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_setprop,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_getprop,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_m_propinfo
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason KingDDI_DEFINE_STREAM_OPS(pcn_devops, nulldev, nulldev, pcn_attach, pcn_detach,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King nodev, NULL, D_MP, NULL, pcn_quiesce);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic struct modldrv pcn_modldrv = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &mod_driverops,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "AMD PCnet",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &pcn_devops
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic struct modlinkage pcn_modlinkage = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King MODREV_1,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King { &pcn_modldrv, NULL }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic ddi_device_acc_attr_t pcn_devattr = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DEVICE_ATTR_V0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_STRUCTURE_LE_ACC,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_STRICTORDER_ACC
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic ddi_device_acc_attr_t pcn_bufattr = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DEVICE_ATTR_V0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_NEVERSWAP_ACC,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_STRICTORDER_ACC
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic ddi_dma_attr_t pcn_dma_attr = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DMA_ATTR_V0, /* dm_attr_version */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0, /* dma_attr_addr_lo */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_addr_hi */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0x7FFFFFFFU, /* dma_attr_count_max */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 4, /* dma_attr_align */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0x3F, /* dma_attr_burstsizes */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_minxfer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_maxxfer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_seg */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_sgllen */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_granular */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0 /* dma_attr_flags */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic ddi_dma_attr_t pcn_dmadesc_attr = {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DMA_ATTR_V0, /* dm_attr_version */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0, /* dma_attr_addr_lo */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_addr_hi */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0x7FFFFFFFU, /* dma_attr_count_max */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 16, /* dma_attr_align */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0x3F, /* dma_attr_burstsizes */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_minxfer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_maxxfer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0xFFFFFFFFU, /* dma_attr_seg */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_sgllen */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 1, /* dma_attr_granular */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0 /* dma_attr_flags */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King};
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King/*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * DDI entry points
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King_init(void)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int rc;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = ddi_soft_state_init(&pcn_ssp, sizeof (pcn_t), 1)) != 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (rc);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_init_ops(&pcn_devops, "pcn");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = mod_install(&pcn_modlinkage)) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_fini_ops(&pcn_devops);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_soft_state_fini(&pcn_ssp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (rc);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King_fini(void)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int rc;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = mod_remove(&pcn_modlinkage)) == DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_fini_ops(&pcn_devops);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_soft_state_fini(&pcn_ssp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (rc);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King_info(struct modinfo *modinfop)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mod_info(&pcn_modlinkage, modinfop));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_register_t *macp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King const pcn_type_t *pcn_type;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int instance = ddi_get_instance(dip);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int rc;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_acc_handle_t pci;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t venid;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t devid;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t svid;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t ssid;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King switch (cmd) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case DDI_RESUME:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (pcn_ddi_resume(dip));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case DDI_ATTACH:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King default:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_slaveonly(dip) == DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "slot does not support PCI bus-master");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_intr_hilevel(dip, 0) != 0) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "hilevel interrupts not supported");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "unable to setup PCI config handle");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King venid = pci_config_get16(pci, PCI_CONF_VENID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King devid = pci_config_get16(pci, PCI_CONF_DEVID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King svid = pci_config_get16(pci, PCI_CONF_SUBVENID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ssid = pci_config_get16(pci, PCI_CONF_SUBSYSID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcn_type = pcn_match(venid, devid)) == NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_teardown(&pci);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "Unable to identify PCI card");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_type->pcn_name) != DDI_PROP_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_teardown(&pci);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "Unable to create model property");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_soft_state_zalloc(pcn_ssp, instance) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "Unable to allocate soft state");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_teardown(&pci);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp = ddi_get_soft_state(pcn_ssp, instance);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_dip = dip;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_instance = instance;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_extphyaddr = -1;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_get_iblock_cookie(dip, 0, &pcnp->pcn_icookie) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "ddi_get_iblock_cookie failed");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_soft_state_free(pcn_ssp, instance);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_teardown(&pci);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_init(&pcnp->pcn_xmtlock, NULL, MUTEX_DRIVER, pcnp->pcn_icookie);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_init(&pcnp->pcn_intrlock, NULL, MUTEX_DRIVER, pcnp->pcn_icookie);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_init(&pcnp->pcn_reglock, NULL, MUTEX_DRIVER, pcnp->pcn_icookie);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Enable bus master, IO space, and memory space accesses
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_put16(pci, PCI_CONF_COMM,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_ME | PCI_COMM_MAE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_teardown(&pci);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcnp->pcn_regs, 0, 0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &pcn_devattr, &pcnp->pcn_regshandle)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "ddi_regs_map_setup failed");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcn_set_chipid(pcnp, (uint32_t)ssid << 16 | (uint32_t)svid) !=
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp->pcn_mii = mii_alloc(pcnp, dip, &pcn_mii_ops)) == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* XXX: need to set based on device */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_set_pauseable(pcnp->pcn_mii, B_FALSE, B_FALSE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcn_allocrxring(pcnp) != DDI_SUCCESS) ||
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (pcn_alloctxring(pcnp) != DDI_SUCCESS)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "unable to allocate DMA resources");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_promisc = B_FALSE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rc = pcn_initialize(pcnp, B_TRUE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rc != DDI_SUCCESS)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_add_intr(dip, 0, NULL, NULL, pcn_intr, (caddr_t)pcnp) !=
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "unable to add interrupt");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags |= PCN_INTR_ENABLED;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "mac_alloc failed");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto fail;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_driver = pcnp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_dip = dip;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_src_addr = pcnp->pcn_addr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_callbacks = &pcn_m_callbacks;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_min_sdu = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_max_sdu = ETHERMTU;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King macp->m_margin = VLAN_TAGSZ;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mac_register(macp, &pcnp->pcn_mh) == DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_free(macp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_free(macp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingfail:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_teardown(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp == NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "no soft state in detach!");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King switch (cmd) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case DDI_DETACH:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mac_unregister(pcnp->pcn_mh) != 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags &= ~PCN_RUNNING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stopall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_teardown(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case DDI_SUSPEND:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_suspend(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags |= PCN_SUSPENDED;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stopall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King default:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_ddi_resume(dev_info_t *dip)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip))) == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags &= ~PCN_SUSPENDED;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (!pcn_initialize(pcnp, B_FALSE)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to resume chip");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags |= PCN_SUSPENDED;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_startall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_resume(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingint
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_quiesce(dev_info_t *dip)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip))) == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* don't want to take the chance of blocking */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, PCN_CSR_EXTCTL1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RDP, CSR_READ_4(pcnp, PCN_IO32_RDP) &
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ~(PCN_EXTCTL1_SINTEN));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, PCN_CSR_CSR);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RDP,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (CSR_READ_4(pcnp, PCN_IO32_RDP) & ~(PCN_CSR_INTEN)) |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_STOP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_teardown(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(!(pcnp->pcn_flags & PCN_RUNNING));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_mii != NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_free(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_mii = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_flags & PCN_INTR_ENABLED)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_remove_intr(pcnp->pcn_dip, 0, pcnp->pcn_icookie);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* These will exit gracefully if not yet allocated */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_freerxring(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_freetxring(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_regshandle != NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_regs_map_free(&pcnp->pcn_regshandle);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_destroy(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_destroy(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_destroy(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_soft_state_free(pcn_ssp, ddi_get_instance(pcnp->pcn_dip));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King/*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Drains any FIFOs in the card, then pauses it
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_suspend(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < 5000; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((val = pcn_csr_read(pcnp, PCN_CSR_EXTCTL1)) &
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_EXTCTL1_SPND)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King drv_usecwait(1000);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unable to suspend, EXTCTL1 was 0x%b", val,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_EXTCTL1_STR);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_resume(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int index;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t crc;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t bit;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t newval, oldval;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * PCNet uses the upper 6 bits of the CRC of the macaddr
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * to index into a 64bit mask
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King crc >>= 26;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King index = crc / 16;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bit = (1U << (crc % 16));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King newval = oldval = pcnp->pcn_mctab[index];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (add) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_mccount[crc]++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_mccount[crc] == 1)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King newval |= bit;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_mccount[crc]--;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_mccount[crc] == 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King newval &= ~bit;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (newval != oldval) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_mctab[index] = newval;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_suspend(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_MAR0 + index, newval);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_resume(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_promisc(void *arg, boolean_t on)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_promisc = on;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_suspend(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* set promiscuous mode */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_promisc)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King else
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_resume(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_unicast(void *arg, const uint8_t *macaddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t addr[3];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy(macaddr, addr, sizeof (addr));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_suspend(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < 3; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_PAR0 + i, addr[i]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy(macaddr, pcnp->pcn_addr, ETHERADDRL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_resume(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mblk_t *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_tx(void *arg, mblk_t *mp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mblk_t *nmp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_flags & PCN_SUSPENDED) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while ((nmp = mp) != NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_carrier_errors++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp = mp->b_next;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King freemsg(nmp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while (mp != NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King nmp = mp->b_next;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp->b_next = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (!pcn_send(pcnp, mp)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp->b_next = nmp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp = nmp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic boolean_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_send(pcn_t *pcnp, mblk_t *mp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *txb;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_tx_desc_t *tmd;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int txsend;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mp != NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King len = msgsize(mp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (len > ETHERVLANMTU) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_macxmt_errors++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King freemsg(mp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (B_TRUE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txavail < PCN_TXRECLAIM)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_reclaim(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txavail == 0) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_wantw = B_TRUE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* enable tx interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_LTINTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (B_FALSE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King txsend = pcnp->pcn_txsend;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * We copy the packet to a single buffer. NetBSD sources suggest
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * that if multiple segements are ever used, VMware has a bug that will
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * only allow 8 segments to be used, while the physical chips allow 16
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King txb = pcnp->pcn_txbufs[txsend];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mcopymsg(mp, txb->pb_buf); /* frees mp! */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_opackets++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_obytes += len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (txb->pb_buf[0] & 0x1) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (bcmp(txb->pb_buf, pcn_broadcast, ETHERADDRL) != 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_multixmt++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King else
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_brdcstxmt++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd = &pcnp->pcn_txdescp[txsend];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCBUF(txb, len, DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_txstat = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_tbaddr = txb->pb_paddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* PCNet wants the 2's complement of the length of the buffer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_txctl = (~(len) + 1) & PCN_TXCTL_BUFSZ;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_txctl |= PCN_TXCTL_MBO;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_txctl |= PCN_TXCTL_STP | PCN_TXCTL_ENP | PCN_TXCTL_ADD_FCS |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_TXCTL_OWN | PCN_TXCTL_MORE_LTINT;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCTXDESC(pcnp, txsend, DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txavail--;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txsend = (txsend + 1) % PCN_TXRING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txstall_time = gethrtime() + (5 * 1000000000ULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (B_TRUE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_reclaim(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_tx_desc_t *tmdp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while (pcnp->pcn_txavail != PCN_TXRING) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int index = pcnp->pcn_txreclaim;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmdp = &pcnp->pcn_txdescp[index];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* sync before reading */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCTXDESC(pcnp, index, DDI_DMA_SYNC_FORKERNEL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* check if chip is still working on it */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (tmdp->pcn_txctl & PCN_TXCTL_OWN)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txavail++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txreclaim = (index + 1) % PCN_TXRING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txavail >= PCN_TXRESCHED) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_wantw) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_wantw = B_FALSE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Disable TX interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_EXTCTL1_LTINTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_tx_update(pcnp->pcn_mh);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic unsigned
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_intr(caddr_t arg1)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (void *)arg1;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mblk_t *mp = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t status, status2;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King boolean_t do_reset = B_FALSE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_SUSPENDED(pcnp)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_INTR_UNCLAIMED);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while ((status = pcn_csr_read(pcnp, PCN_CSR_CSR)) & PCN_CSR_INTR) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_CSR, status);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King status2 = pcn_csr_read(pcnp, PCN_CSR_EXTCTL2);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (status & PCN_CSR_TINT) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_reclaim(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (status & PCN_CSR_RINT)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp = pcn_receive(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (status & PCN_CSR_ERR) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King do_reset = B_TRUE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* timer interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (status2 & PCN_EXTCTL2_STINT) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* ack it */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL2,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_EXTCTL2_STINT);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcn_watchdog(pcnp) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King do_reset = B_TRUE;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (do_reset) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_resetall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_reset(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_rx(pcnp->pcn_mh, NULL, mp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_INTR_CLAIMED);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic mblk_t *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_receive(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *rxb;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_rx_desc_t *rmd;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mblk_t *mpchain, **mpp, *mp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int head, cnt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mpchain = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mpp = &mpchain;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King head = pcnp->pcn_rxhead;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (cnt = 0; cnt < PCN_RXRING; cnt++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd = &pcnp->pcn_rxdescp[head];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rxb = pcnp->pcn_rxbufs[head];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCRXDESC(pcnp, head, DDI_DMA_SYNC_FORKERNEL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_OWN)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King len = rmd->pcn_rxlen - ETHERFCSL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_ERR) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_errrcv++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_FRAM)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_align_errors++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_OFLOW)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_overflow++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_CRC)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_fcs_errors++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else if (len > ETHERVLANMTU) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_errrcv++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_toolong_errors++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp = allocb(len + PCN_HEADROOM, 0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mp == NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_errrcv++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_norcvbuf++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King goto skip;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp->b_rptr += PCN_HEADROOM;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mp->b_wptr = mp->b_rptr + len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy((char *)rxb->pb_buf, mp->b_rptr, len);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_ipackets++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rbytes++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_LAFM|PCN_RXSTAT_BAM) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_BAM)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_brdcstrcv++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King else
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_multircv++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *mpp = mp;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mpp = &mp->b_next;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingskip:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd->pcn_rxstat = PCN_RXSTAT_OWN;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King SYNCRXDESC(pcnp, head, DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King head = (head + 1) % PCN_RXRING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxhead = head;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mpchain);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mii_m_loop_ioctl(pcnp->pcn_mii, wq, mp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King miocnak(wq, mp, 0, EINVAL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_start(void *arg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_startall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags |= PCN_RUNNING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_start(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_stop(void *arg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_stop(pcnp->pcn_mii);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stopall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_flags &= ~PCN_RUNNING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_xmtlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_intrlock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_initialize(pcn_t *pcnp, boolean_t getfact)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t addr[3];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy(pcnp->pcn_addr, addr, sizeof (addr));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Issue a reset by reading from the RESET register.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Note that we don't know if the chip is operating in
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * 16-bit or 32-bit mode at this point, so we attempt
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * to reset the chip both ways. If one fails, the other
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * will succeed.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) CSR_READ_2(pcnp, PCN_IO16_RESET);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) CSR_READ_4(pcnp, PCN_IO32_RESET);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King drv_usecwait(1000);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Select 32-bit (DWIO) mode */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RDP, 0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* The timer is not affected by a reset, so explicitly disable */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stop_timer(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable fast suspend */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Select Style 3 descriptors */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Set MAC address */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (getfact)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_getfactaddr(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_PAR0, addr[0]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_PAR1, addr[1]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_PAR2, addr[2]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Clear PCN_MISC_ASEL so we can set the port via PCN_CSR_MODE. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_BCR_CLRBIT(pcnp, PCN_BCR_MISCCFG, PCN_MISC_ASEL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * XXX: need to find a way to determine when 10bt media is
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * selected for non Am79C978, and set to PCN_PORT_10BASET
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * instead of PCN_PORT_MII
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_MODE, PCN_PORT_MII);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Reenable auto negotiation for external phy */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_BCR_SETBIT(pcnp, PCN_BCR_MIICTL, PCN_MIICTL_XPHYANE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_promisc)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Initalize mcast addr filter */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < 4; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_MAR0 + i, pcnp->pcn_mctab[i]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_resetrings(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* We're not using the initialization block. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_IAB1, 0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Enable burst read and write. Also set the no underflow
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * bit. This will avoid transmit underruns in ceratin
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * conditions while still providing decent performance.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_BCR_SETBIT(pcnp, PCN_BCR_BUSCTL, PCN_BUSCTL_NOUFLOW |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_BUSCTL_BREAD | PCN_BUSCTL_BWRITE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable graceful recovery from underflow. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_IMR, PCN_IMR_DXSUFLO);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable auto-padding of short TX frames. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_TFEAT, PCN_TFEAT_PAD_TX);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_type == Am79C978)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_PHYSEL,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_PHYSEL_PCNET|PCN_PHY_HOMEPNA);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_resetall(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stopall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_startall(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_startall(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mutex_owned(&pcnp->pcn_intrlock));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) pcn_initialize(pcnp, B_FALSE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Start chip and enable interrupts */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_START|PCN_CSR_INTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_start_timer(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (IS_RUNNING(pcnp))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_tx_update(pcnp->pcn_mh);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_stopall(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mutex_owned(&pcnp->pcn_intrlock));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_stop_timer(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_STOP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King/*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * The soft timer is not affected by a soft reset (according to the datasheet)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * so it must always be explicitly enabled and disabled
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_start_timer(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SINTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * The frequency this fires varies based on the particular
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * model, this value is largely arbitrary. It just needs to
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * fire often enough to detect a stall
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_TIMER, 0xa000);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_stop_timer(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SINTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_stat(void *arg, uint_t stat, uint64_t *val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mii_m_getstat(pcnp->pcn_mii, stat, val) == 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King switch (stat) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_MULTIRCV:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_multircv;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_BRDCSTRCV:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_brdcstrcv;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_MULTIXMT:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_multixmt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_BRDCSTXMT:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_brdcstxmt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_IPACKETS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_ipackets;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_RBYTES:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_rbytes;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_OPACKETS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_opackets;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_OBYTES:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_obytes;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_NORCVBUF:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_norcvbuf;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_NOXMTBUF:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_COLLISIONS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_collisions;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_IERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_errrcv;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_OERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_errxmt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_ALIGN_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_align_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_FCS_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_fcs_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_SQE_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_sqe_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_DEFER_XMTS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_defer_xmts;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_FIRST_COLLISIONS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_first_collisions;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_MULTI_COLLISIONS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_multi_collisions;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_TX_LATE_COLLISIONS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_tx_late_collisions;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_EX_COLLISIONS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_ex_collisions;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_MACXMT_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_macxmt_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_CARRIER_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_carrier_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_TOOLONG_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_toolong_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_MACRCV_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_macrcv_errors;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_OVERFLOWS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_overflow;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case MAC_STAT_UNDERFLOWS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_underflow;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_TOOSHORT_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_runt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case ETHER_STAT_JABBER_ERRORS:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *val = pcnp->pcn_jabber;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King default:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (ENOTSUP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King void *val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mii_m_getprop(pcnp->pcn_mii, name, num, sz, val));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King const void *val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mii_m_setprop(pcnp->pcn_mii, name, num, sz, val));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_prop_info_handle_t prh)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_m_propinfo(pcnp->pcn_mii, name, num, prh);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_watchdog(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp->pcn_txstall_time != 0) &&
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (gethrtime() > pcnp->pcn_txstall_time) &&
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (pcnp->pcn_txavail != PCN_TXRING)) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txstall_time = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "TX stall detected!");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_mii_read(void *arg, uint8_t phy, uint8_t reg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * At least Am79C971 with DP83840A wedge when isolating the
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * external PHY so we can't allow multiple external PHYs.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * There are cards that use Am79C971 with both the internal
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * and an external PHY though.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * For internal PHYs it doesn't really matter whether we can
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * isolate the remaining internal and the external ones in
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * the PHY drivers as the internal PHYs have to be enabled
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * individually in PCN_BCR_PHYSEL, PCN_CSR_MODE, etc.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * With Am79C97{3,5,8} we don't support switching beetween
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * the internal and external PHYs, yet, so we can't allow
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * multiple PHYs with these either.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Am79C97{2,6} actually only support external PHYs (not
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * connectable internal ones respond at the usual addresses,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * which don't hurt if we let them show up on the bus) and
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * isolating them works.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (((pcnp->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) ||
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_type == Am79C973 || pcnp->pcn_type == Am79C975 ||
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_type == Am79C978) && pcnp->pcn_extphyaddr != -1 &&
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King phy != pcnp->pcn_extphyaddr) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = ((uint16_t)phy << 5) | reg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, phy << 5 | reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = pcn_bcr_read(pcnp, PCN_BCR_MIIDATA) & 0xFFFF;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (val == 0xFFFF) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (((pcnp->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) ||
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_type == Am79C973 || pcnp->pcn_type == Am79C975 ||
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_type == Am79C978) && pcnp->pcn_extphyaddr == -1)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_extphyaddr = phy;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, reg | (phy << 5));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_MIIDATA, val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_mii_notify(void *arg, link_state_t link)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_t *pcnp = (pcn_t *)arg;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mac_link_update(pcnp->pcn_mh, link);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic const pcn_type_t *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_match(uint16_t vid, uint16_t did)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King const pcn_type_t *t;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King t = pcn_devs;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while (t->pcn_name != NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((vid == t->pcn_vid) && (did == t->pcn_did))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King t++;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_getfactaddr(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t addr[2];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King addr[0] = CSR_READ_4(pcnp, PCN_IO32_APROM00);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King addr[1] = CSR_READ_4(pcnp, PCN_IO32_APROM01);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy(&addr[0], &pcnp->pcn_addr[0], sizeof (pcnp->pcn_addr));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint32_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_csr_read(pcn_t *pcnp, uint32_t reg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = CSR_READ_4(pcnp, PCN_IO32_RDP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_csr_read16(pcn_t *pcnp, uint32_t reg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_2(pcnp, PCN_IO16_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = CSR_READ_2(pcnp, PCN_IO16_RDP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_csr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RDP, val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint32_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_bcr_read(pcn_t *pcnp, uint32_t reg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = CSR_READ_4(pcnp, PCN_IO32_BDP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic uint16_t
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_bcr_read16(pcn_t *pcnp, uint32_t reg)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t val;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_2(pcnp, PCN_IO16_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = CSR_READ_2(pcnp, PCN_IO16_BDP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_bcr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_enter(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CSR_WRITE_4(pcnp, PCN_IO32_BDP, val);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mutex_exit(&pcnp->pcn_reglock);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_resetrings(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t bufsz = ((~(PCN_BUFSZ) + 1) & PCN_RXLEN_BUFSZ) | PCN_RXLEN_MBO;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxhead = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txreclaim = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txsend = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txavail = PCN_TXRING;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* reset rx descriptor values */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_rx_desc_t *rmd = &pcnp->pcn_rxdescp[i];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *rxb = pcnp->pcn_rxbufs[i];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd->pcn_rxlen = rmd->pcn_rsvd0 = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd->pcn_rbaddr = rxb->pb_paddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd->pcn_bufsz = bufsz;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rmd->pcn_rxstat = PCN_RXSTAT_OWN;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_sync(pcnp->pcn_rxdesc_dmah, 0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_RXRING * sizeof (pcn_rx_desc_t), DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* reset tx descriptor values */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_tx_desc_t *txd = &pcnp->pcn_txdescp[i];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *txb = pcnp->pcn_txbufs[i];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King txd->pcn_txstat = txd->pcn_txctl = txd->pcn_uspace = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King txd->pcn_tbaddr = txb->pb_paddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_sync(pcnp->pcn_txdesc_dmah, 0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_TXRING * sizeof (pcn_tx_desc_t), DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* set addresses of decriptors */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_RXADDR0, pcnp->pcn_rxdesc_paddr & 0xFFFF);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_RXADDR1,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (pcnp->pcn_rxdesc_paddr >> 16) & 0xFFFF);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_TXADDR0, pcnp->pcn_txdesc_paddr & 0xFFFF);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_TXADDR1,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (pcnp->pcn_txdesc_paddr >> 16) & 0xFFFF);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* set the ring sizes */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_RXRINGLEN, (~PCN_RXRING) + 1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_TXRINGLEN, (~PCN_TXRING) + 1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_destroybuf(pcn_buf_t *buf)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (buf == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (buf->pb_paddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_unbind_handle(buf->pb_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (buf->pb_acch)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_mem_free(&buf->pb_acch);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (buf->pb_dmah)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_free_handle(&buf->pb_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(buf, sizeof (*buf));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic pcn_buf_t *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_allocbuf(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *buf;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King unsigned ccnt;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_cookie_t dmac;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King buf = kmem_zalloc(sizeof (*buf), KM_SLEEP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL, &buf->pb_dmah) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(buf, sizeof (*buf));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_dma_mem_alloc(buf->pb_dmah, PCN_BUFSZ, &pcn_bufattr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &buf->pb_buf, &len,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &buf->pb_acch) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_destroybuf(buf);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_dma_addr_bind_handle(buf->pb_dmah, NULL, buf->pb_buf, len,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &ccnt) != DDI_DMA_MAPPED) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_destroybuf(buf);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (NULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King buf->pb_paddr = dmac.dmac_address;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (buf);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_alloctxring(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int rval;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t size;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_cookie_t dmac;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King unsigned ncookies;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King caddr_t kaddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size = PCN_TXRING * sizeof (pcn_tx_desc_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King NULL, &pcnp->pcn_txdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_mem_alloc(pcnp->pcn_txdesc_dmah, size, &pcn_devattr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &pcnp->pcn_txdesc_acch);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_addr_bind_handle(pcnp->pcn_txdesc_dmah, NULL, kaddr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &dmac,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &ncookies);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_DMA_MAPPED) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to bind DMA for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(ncookies == 1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txdesc_paddr = dmac.dmac_address;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txdescp = (void *)kaddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txbufs = kmem_zalloc(PCN_TXRING * sizeof (pcn_buf_t *),
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King KM_SLEEP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *txb = pcn_allocbuf(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (txb == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txbufs[i] = txb;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_allocrxring(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int rval;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t len;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size_t size;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_cookie_t dmac;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King unsigned ncookies;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King caddr_t kaddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size = PCN_RXRING * sizeof (pcn_rx_desc_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dmadesc_attr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DMA_SLEEP, NULL, &pcnp->pcn_rxdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_mem_alloc(pcnp->pcn_rxdesc_dmah, size, &pcn_devattr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &pcnp->pcn_rxdesc_acch);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_addr_bind_handle(pcnp->pcn_rxdesc_dmah, NULL, kaddr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &dmac,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King &ncookies);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rval != DDI_DMA_MAPPED) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to bind DMA for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ASSERT(ncookies == 1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxdesc_paddr = dmac.dmac_address;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxdescp = (void *)kaddr;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxbufs = kmem_zalloc(PCN_RXRING * sizeof (pcn_buf_t *),
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King KM_SLEEP);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_buf_t *rxb = pcn_allocbuf(pcnp);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rxb == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxbufs[i] = rxb;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_freetxring(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txbufs) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_destroybuf(pcnp->pcn_txbufs[i]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(pcnp->pcn_txbufs, PCN_TXRING * sizeof (pcn_buf_t *));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txdesc_paddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_unbind_handle(pcnp->pcn_txdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txdesc_acch)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_mem_free(&pcnp->pcn_txdesc_acch);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_txdesc_dmah)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_free_handle(&pcnp->pcn_txdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_freerxring(pcn_t *pcnp)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King int i;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_rxbufs) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_destroybuf(pcnp->pcn_rxbufs[i]);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(pcnp->pcn_rxbufs, PCN_RXRING * sizeof (pcn_buf_t *));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_rxdesc_paddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_unbind_handle(pcnp->pcn_rxdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_rxdesc_acch)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_mem_free(&pcnp->pcn_rxdesc_acch);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcnp->pcn_rxdesc_dmah)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_dma_free_handle(&pcnp->pcn_rxdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_set_chipid(pcn_t *pcnp, uint32_t conf_id)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King char *name = NULL;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint32_t chipid;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Note: we can *NOT* put the chip into 32-bit mode yet. If a
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * lance ethernet device is present and pcn tries to attach, it can
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * hang the device (requiring a hardware reset), since they only work
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * in 16-bit mode.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * The solution is check using 16-bit operations first, and determine
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * if 32-bit mode operations are supported.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * The safest way to do this is to read the PCI subsystem ID from
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * BCR23/24 and compare that with the value read from PCI config
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * space.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid = pcn_bcr_read16(pcnp, PCN_BCR_PCISUBSYSID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid <<= 16;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid |= pcn_bcr_read16(pcnp, PCN_BCR_PCISUBVENID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /*
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * The test for 0x10001000 is a hack to pacify VMware, who's
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * pseudo-PCnet interface is broken. Reading the subsystem register
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * from PCI config space yields 0x00000000 while reading the same value
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * from I/O space yields 0x10001000. It's not supposed to be that way.
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (chipid == conf_id || chipid == 0x10001000) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* We're in 16-bit mode. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid = pcn_csr_read16(pcnp, PCN_CSR_CHIPID1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid <<= 16;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid |= pcn_csr_read16(pcnp, PCN_CSR_CHIPID0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King } else {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid = pcn_csr_read(pcnp, PCN_CSR_CHIPID1);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid <<= 16;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid |= pcn_csr_read(pcnp, PCN_CSR_CHIPID0);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid = CHIPID_PARTID(chipid);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Set default value and override as needed */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King switch (chipid) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C970:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C970 PCnet-PCI";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C970A:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C970A PCnet-PCI II";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C971:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C971 PCnet-FAST";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C972:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C972 PCnet-FAST+";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C973:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C973 PCnet-FAST III";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C975:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C975 PCnet-FAST III";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C976:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C976";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King case Am79C978:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Am79C978";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King break;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King default:
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name = "Unknown";
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unknown chip id 0x%x", chipid);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_prop_update_string(DDI_DEV_T_NONE, pcnp->pcn_dip, "chipid",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King name) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unable to set chipid property");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_FAILURE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King }
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (DDI_SUCCESS);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_error(dev_info_t *dip, char *fmt, ...)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King{
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King va_list ap;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King char buf[256];
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King va_start(ap, fmt);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) vsnprintf(buf, sizeof (buf), fmt, ap);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King va_end(ap);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (dip)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King cmn_err(CE_WARN, "%s%d: %s", ddi_driver_name(dip),
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_get_instance(dip), buf);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King else
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King cmn_err(CE_WARN, "pcn: %s", buf);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King}