PageRenderTime 74ms CodeModel.GetById 15ms app.highlight 50ms RepoModel.GetById 0ms app.codeStats 0ms

/pcn/src/pcn.c

https://bitbucket.org/0xffea/driver-gate
C | 1748 lines | 1288 code | 337 blank | 123 comment | 204 complexity | 16530b3e839acff0e00f58e39f0a076f MD5 | raw file
   1/*
   2 * Copyright (c) 2000 Berkeley Software Design, Inc.
   3 * Copyright (c) 1997, 1998, 1999, 2000
   4 *      Bill Paul <wpaul@osd.bsdi.com>.  All rights reserved.
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. All advertising materials mentioning features or use of this software
  15 *    must display the following acknowledgement:
  16 *      This product includes software developed by Bill Paul.
  17 * 4. Neither the name of the author nor the names of any co-contributors
  18 *    may be used to endorse or promote products derived from this software
  19 *    without specific prior written permission.
  20 *
  21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
  22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
  25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  31 * THE POSSIBILITY OF SUCH DAMAGE.
  32 */
  33
  34#include <sys/varargs.h>
  35#include <sys/types.h>
  36#include <sys/modctl.h>
  37#include <sys/devops.h>
  38#include <sys/stream.h>
  39#include <sys/strsun.h>
  40#include <sys/cmn_err.h>
  41#include <sys/ethernet.h>
  42#include <sys/kmem.h>
  43#include <sys/crc32.h>
  44#include <sys/mii.h>
  45#include <sys/miiregs.h>
  46#include <sys/mac.h>
  47#include <sys/mac_ether.h>
  48#include <sys/ddi.h>
  49#include <sys/sunddi.h>
  50#include <sys/vlan.h>
  51#include <sys/pci.h>
  52#include <sys/conf.h>
  53
  54#include "pcn.h"
  55#include "pcnimpl.h"
  56
  57#define	ETHERVLANMTU	(ETHERMAX + 4)
  58
  59#define	CSR_WRITE_4(pcnp, reg, val) \
  60	ddi_put32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg), val)
  61
  62#define	CSR_WRITE_2(pcnp, reg, val) \
  63	ddi_put16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg), val)
  64
  65#define	CSR_READ_4(pcnp, reg) \
  66	ddi_get32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg))
  67
  68#define	CSR_READ_2(pcnp, reg) \
  69	ddi_get16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg))
  70
  71#define	PCN_CSR_SETBIT(pcnp, reg, x) \
  72	pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) | (x))
  73
  74#define	PCN_CSR_CLRBIT(pcnp, reg, x) \
  75	pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) & ~(x))
  76
  77#define	PCN_BCR_SETBIT(pncp, reg, x) \
  78	pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) | (x))
  79
  80#define	PCN_BCR_CLRBIT(pcnp, reg, x) \
  81	pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) & ~(x))
  82
  83static int	pcn_attach(dev_info_t *, ddi_attach_cmd_t);
  84static int	pcn_detach(dev_info_t *, ddi_detach_cmd_t);
  85static int	pcn_resume(dev_info_t *);
  86static int	pcn_quiesce(dev_info_t *);
  87
  88static int	pcn_setup_intr(pcn_t *);
  89static int	pcn_teardown_intr(pcn_t *);
  90
  91static int	pcn_m_unicast(void *, const uint8_t *);
  92static int	pcn_m_multicast(void *, boolean_t, const uint8_t *);
  93static int	pcn_m_promisc(void *, boolean_t);
  94static mblk_t	*pcn_m_tx(void *, mblk_t *);
  95static void	pcn_m_ioctl(void *, queue_t *, mblk_t *);
  96static int	pcn_m_stat(void *, uint_t, uint64_t *);
  97static int	pcn_m_start(void *);
  98static void	pcn_m_stop(void *);
  99static int	pcn_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
 100    uint_t, void *, uint_t *);
 101static int	pcn_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
 102    const void *);
 103
 104static unsigned	pcn_intr(caddr_t, caddr_t);
 105
 106static uint16_t	pcn_mii_read(void *, uint8_t, uint8_t);
 107static void	pcn_mii_write(void *, uint8_t, uint8_t, uint16_t);
 108static void	pcn_mii_notify(void *, link_state_t);
 109
 110static uint32_t	pcn_csr_read(pcn_t *, uint32_t);
 111static uint16_t	pcn_csr_read16(pcn_t *, uint32_t);
 112static void	pcn_csr_write(pcn_t *, uint32_t, uint32_t);
 113
 114static uint32_t	pcn_bcr_read(pcn_t *, uint32_t);
 115static uint16_t pcn_bcr_read16(pcn_t *, uint32_t);
 116static void	pcn_bcr_write(pcn_t *, uint32_t, uint32_t);
 117
 118static boolean_t	pcn_send(pcn_t *, mblk_t *);
 119
 120static int		pcn_allocrxring(pcn_t *);
 121static int		pcn_alloctxring(pcn_t *);
 122static void		pcn_freetxring(pcn_t *);
 123static void		pcn_freerxring(pcn_t *);
 124static void		pcn_resetrings(pcn_t *);
 125static int		pcn_initialize(pcn_t *);
 126static void		pcn_enableinterrupts(pcn_t *);
 127static void		pcn_disableinterrupts(pcn_t *);
 128static mblk_t 		*pcn_receive(pcn_t *);
 129static void		pcn_resetall(pcn_t *);
 130static void		pcn_startall(pcn_t *);
 131static void		pcn_stopall(pcn_t *);
 132static void		pcn_reclaim(pcn_t *);
 133static void		pcn_setrxfilt(pcn_t *);
 134static void		pcn_getfactaddr(pcn_t *);
 135static int		pcn_set_chipid(pcn_t *, uint32_t);
 136static const pcn_type_t *pcn_match(uint16_t, uint16_t);
 137static char		*pcn_chipid_name(uint32_t);
 138
 139static void		pcn_error(dev_info_t *, char *, ...);
 140
 141void *pcn_ssp = NULL;
 142
 143static uchar_t pcn_broadcast[ETHERADDRL] = {
 144	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 145};
 146
 147static const pcn_type_t pcn_devs[] = {
 148	{ PCN_VENDORID, PCN_DEVICEID_PCNET, "AMD PCnet/PCI 10/100BaseTX" },
 149	{ PCN_VENDORID, PCN_DEVICEID_HOME, "AMD PCnet/Home HomePNA" },
 150	{ 0, 0, NULL }
 151};
 152
 153static const struct pcn_chipid {
 154	uint32_t	id;
 155	char		*name;
 156} pcn_chipid[] = {
 157	{ Am79C971,	"Am79C971" },
 158	{ Am79C972,	"Am79C972" },
 159	{ Am79C973,	"Am79C973" },
 160	{ Am79C978,	"Am79C978" },
 161	{ Am79C975,	"Am79C975" },
 162	{ Am79C976,	"Am79C976" },
 163	{ 0, NULL },
 164};
 165
 166static mii_ops_t pcn_mii_ops = {
 167	MII_OPS_VERSION,
 168	pcn_mii_read,
 169	pcn_mii_write,
 170	pcn_mii_notify,
 171	NULL
 172};
 173
 174static mac_callbacks_t pcn_m_callbacks = {
 175	MC_IOCTL | MC_SETPROP | MC_GETPROP,
 176	pcn_m_stat,
 177	pcn_m_start,
 178	pcn_m_stop,
 179	pcn_m_promisc,
 180	pcn_m_multicast,
 181	pcn_m_unicast,
 182	pcn_m_tx,
 183	pcn_m_ioctl,
 184	NULL,		/* mc_getcapab */
 185	NULL,		/* mc_open */
 186	NULL,		/* mc_close */
 187	pcn_m_setprop,
 188	pcn_m_getprop
 189};
 190
 191DDI_DEFINE_STREAM_OPS(pcn_devops, nulldev, nulldev, pcn_attach, pcn_detach,
 192    nodev, NULL, D_MP, NULL, pcn_quiesce);
 193
 194static struct modldrv pcn_modldrv = {
 195	&mod_driverops,
 196	"AMD PCnet",
 197	&pcn_devops
 198};
 199
 200static struct modlinkage pcn_modlinkage = {
 201	MODREV_1,
 202	{ &pcn_modldrv, NULL }
 203};
 204
 205static ddi_device_acc_attr_t pcn_devattr = {
 206	DDI_DEVICE_ATTR_V0,
 207	DDI_STRUCTURE_LE_ACC,
 208	DDI_STRICTORDER_ACC
 209};
 210
 211static ddi_device_acc_attr_t pcn_bufattr = {
 212	DDI_DEVICE_ATTR_V0,
 213	DDI_NEVERSWAP_ACC,
 214	DDI_STRICTORDER_ACC
 215};
 216
 217static ddi_dma_attr_t pcn_dma_attr = {
 218	DMA_ATTR_V0,		/* dm_attr_version */
 219	0,			/* dma_attr_addr_lo */
 220	0xFFFFFFFFU,		/* dma_attr_addr_hi */
 221	0x7FFFFFFFU,		/* dma_attr_count_max */
 222	4,			/* dma_attr_align */
 223	0x3F,			/* dma_attr_burstsizes */
 224	1,			/* dma_attr_minxfer */
 225	0xFFFFFFFFU,		/* dma_attr_maxxfer */
 226	0xFFFFFFFFU,		/* dma_attr_seg */
 227	1,			/* dma_attr_sgllen */
 228	1,			/* dma_attr_granular */
 229	0			/* dma_attr_flags */
 230};
 231
 232static ddi_dma_attr_t pcn_dmadesc_attr = {
 233	DMA_ATTR_V0,		/* dm_attr_version */
 234	0,			/* dma_attr_addr_lo */
 235	0xFFFFFFFFU,		/* dma_attr_addr_hi */
 236	0x7FFFFFFFU,		/* dma_attr_count_max */
 237	16,			/* dma_attr_align */
 238	0x3F,			/* dma_attr_burstsizes */
 239	1,			/* dma_attr_minxfer */
 240	0xFFFFFFFFU,		/* dma_attr_maxxfer */
 241	0xFFFFFFFFU,		/* dma_attr_seg */
 242	1,			/* dma_attr_sgllen */
 243	1,			/* dma_attr_granular */
 244	0			/* dma_attr_flags */
 245};
 246
 247/*
 248 * DDI entry points
 249 */
 250int
 251_init(void)
 252{
 253	int	rc;
 254
 255	if ((rc = ddi_soft_state_init(&pcn_ssp, sizeof (pcn_t), 1)) != 0)
 256		return (rc);
 257
 258	mac_init_ops(&pcn_devops, "pcn");
 259	if ((rc = mod_install(&pcn_modlinkage)) != DDI_SUCCESS) {
 260		mac_fini_ops(&pcn_devops);
 261		ddi_soft_state_fini(&pcn_ssp);
 262	}
 263
 264	return (rc);
 265}
 266
 267int
 268_fini(void)
 269{
 270	int	rc;
 271
 272	if ((rc = mod_remove(&pcn_modlinkage)) == DDI_SUCCESS) {
 273		mac_fini_ops(&pcn_devops);
 274		ddi_soft_state_fini(&pcn_ssp);
 275	}
 276
 277	return (rc);
 278}
 279
 280int
 281_info(struct modinfo *modinfop)
 282{
 283	return (mod_info(&pcn_modlinkage, modinfop));
 284}
 285
 286int
 287pcn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 288{
 289	pcn_t			*pcnp;
 290	mac_register_t		*macp;
 291	const pcn_type_t	*pcn_type;
 292	int			instance = ddi_get_instance(dip);
 293	int			rc;
 294	ddi_acc_handle_t	pci;
 295	uint32_t		chipid;
 296	uint16_t		venid;
 297	uint16_t		devid;
 298	uint16_t		svid;
 299	uint16_t		ssid;
 300	uint16_t		cachesize;
 301
 302	switch (cmd) {
 303	case DDI_RESUME:
 304		return (pcn_resume(dip));
 305
 306	case DDI_ATTACH:
 307		break;
 308
 309	default:
 310		return (DDI_FAILURE);
 311	}
 312
 313	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
 314		pcn_error(dip, "slot does not support PCI bus-master");
 315		return (DDI_FAILURE);
 316	}
 317
 318	if (ddi_intr_hilevel(dip, 0) != 0) {
 319		pcn_error(dip, "hilevel interrupts not supported");
 320		return (DDI_FAILURE);
 321	}
 322
 323	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
 324		pcn_error(dip, "unable to setup PCI config handle");
 325		return (DDI_FAILURE);
 326	}
 327
 328	venid = pci_config_get16(pci, PCI_CONF_VENID);
 329	devid = pci_config_get16(pci, PCI_CONF_DEVID);
 330	svid = pci_config_get16(pci, PCI_CONF_SUBVENID);
 331	ssid = pci_config_get16(pci, PCI_CONF_SUBSYSID);
 332
 333	if ((pcn_type = pcn_match(venid, devid)) == NULL) {
 334		pci_config_teardown(&pci);
 335		pcn_error(dip, "Unable to identify PCI card");
 336		return (DDI_FAILURE);
 337	}
 338
 339	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
 340		pcn_type->pcn_name) != DDI_PROP_SUCCESS) {
 341		pci_config_teardown(&pci);
 342		pcn_error(dip, "Unable to create model property");
 343		return (DDI_FAILURE);
 344	}
 345
 346	cachesize = pci_config_get8(pci, PCI_CONF_CACHE_LINESZ);
 347
 348	if (ddi_soft_state_zalloc(pcn_ssp, instance) != DDI_SUCCESS) {
 349		pcn_error(dip, "Unable to allocate soft state");
 350		pci_config_teardown(&pci);
 351		return (DDI_FAILURE);
 352	}
 353
 354	pcnp = ddi_get_soft_state(pcn_ssp, instance);
 355	pcnp->pcn_dip = dip;
 356	pcnp->pcn_instance = instance;
 357
 358	if (pcn_setup_intr(pcnp) != DDI_SUCCESS) {
 359		ddi_soft_state_free(pcn_ssp, instance);
 360		pci_config_teardown(&pci);
 361		return (DDI_FAILURE);
 362	}
 363
 364	mutex_init(&pcnp->pcn_xmtlock, NULL, MUTEX_DRIVER,
 365	    DDI_INTR_PRI(pcnp->pcn_int_pri));
 366	mutex_init(&pcnp->pcn_intrlock, NULL, MUTEX_DRIVER,
 367	    DDI_INTR_PRI(pcnp->pcn_int_pri));
 368
 369	/*
 370	 * Enable bus master, IO space, and memory space accesses
 371	 */
 372	pci_config_put16(pci, PCI_CONF_COMM,
 373	    pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_ME | PCI_COMM_MAE);
 374
 375	pci_config_teardown(&pci);
 376
 377	if ((pcnp->pcn_mii = mii_alloc(pcnp, dip, &pcn_mii_ops)) == NULL)
 378		goto fail;
 379
 380	mii_set_pauseable(pcnp->pcn_mii, B_TRUE, B_TRUE);
 381
 382	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcnp->pcn_regs, 0, 0,
 383	    &pcn_devattr, &pcnp->pcn_regshandle)) {
 384		pcn_error(dip, "ddi_regs_map_setup failed");
 385		goto fail;
 386	}
 387
 388	if (pcn_set_chipid(pcnp, (uint32_t)ssid << 16 | (uint32_t)svid) !=
 389	    DDI_SUCCESS) {
 390		goto fail;
 391	}
 392
 393	if ((pcn_allocrxring(pcnp) != DDI_SUCCESS) ||
 394	    (pcn_alloctxring(pcnp) != DDI_SUCCESS)) {
 395		pcn_error(dip, "unable to allocate DMA resources");
 396		goto fail;
 397	}
 398
 399	mutex_enter(&pcnp->pcn_intrlock);
 400	mutex_enter(&pcnp->pcn_xmtlock);
 401	rc = pcn_initialize(pcnp);
 402	mutex_exit(&pcnp->pcn_xmtlock);
 403	mutex_exit(&pcnp->pcn_intrlock);
 404	if (rc != DDI_SUCCESS)
 405		goto fail;
 406
 407	pcn_getfactaddr(pcnp);
 408	pcnp->pcn_promisc = B_FALSE;
 409
 410	(void) pcn_m_unicast(pcnp, pcnp->pcn_addr);
 411	/* XXX: do we need to add the broadcast addr to the addr filter? */
 412
 413	if ((rc = ddi_intr_add_handler(pcnp->pcn_htable, pcn_intr,
 414	    (caddr_t)pcnp, NULL)) != DDI_SUCCESS) {
 415		pcn_error(pcnp->pcn_dip, "failed to add interrupt handler");
 416		return (DDI_FAILURE);
 417	}
 418
 419	if (ddi_intr_enable(pcnp->pcn_htable) != DDI_SUCCESS) {
 420		pcn_error(pcnp->pcn_dip, "failed to enable interrupt");
 421		goto fail;
 422	}
 423
 424	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
 425		pcn_error(pcnp->pcn_dip, "mac_alloc failed");
 426		goto fail;
 427	}
 428
 429	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
 430	macp->m_driver = pcnp;
 431	macp->m_dip = dip;
 432	macp->m_src_addr = pcnp->pcn_addr;
 433	macp->m_callbacks = &pcn_m_callbacks;
 434	macp->m_min_sdu = 0;
 435	macp->m_max_sdu = ETHERMTU;
 436	macp->m_margin = VLAN_TAGSZ;
 437
 438	if (mac_register(macp, &pcnp->pcn_mh) == DDI_SUCCESS) {
 439		mac_free(macp);
 440		ddi_report_dev(dip);
 441
 442		return (DDI_SUCCESS);
 443	}
 444
 445	mac_free(macp);
 446
 447fail:
 448	ddi_intr_free(pcnp->pcn_htable);
 449	ddi_soft_state_free(pcn_ssp, instance);
 450
 451	return (DDI_FAILURE);
 452}
 453
 454static int
 455pcn_set_chipid(pcn_t *pcnp, uint32_t conf_id)
 456{
 457	uint32_t chipid;
 458
 459	/*
 460	 * Note: we can *NOT* put the chip into
 461	 * 32-bit mode yet. The le(4) driver will only
 462	 * work in 16-bit mode, and once the chip
 463	 * goes into 32-bit mode, the only way to
 464	 * get it out again is with a hardware reset.
 465	 * So if pcn_probe() is called before the
 466	 * le(4) driver's probe routine, the chip will
 467	 * be locked into 32-bit operation and the
 468	 * le(4) driver will be unable to attach to it.
 469	 * Note II: if the chip happens to already
 470	 * be in 32-bit mode, we still need to check
 471	 * the chip ID, but first we have to detect
 472	 * 32-bit mode using only 16-bit operations.
 473	 * The safest way to do this is to read the
 474	 * PCI subsystem ID from BCR23/24 and compare
 475	 * that with the value read from PCI config
 476	 * space.
 477	 */
 478
 479	chipid = pcn_bcr_read16(pcnp, PCN_BCR_PCISUBSYSID);
 480	chipid <<= 16;
 481	chipid |= pcn_bcr_read16(pcnp, PCN_BCR_PCISUBVENID);
 482	/*
 483	 * Note III: the test for 0x10001000 is a hack to
 484	 * pacify VMware, who's pseudo-PCnet interface is
 485	 * broken. Reading the subsystem register from PCI
 486	 * config space yields 0x00000000 while reading the
 487	 * same value from I/O space yields 0x10001000. It's
 488	 * not supposed to be that way.
 489	 */
 490	if (chipid == conf_id || chipid == 0x10001000) {
 491		/* We're in 16-bit mode. */
 492		chipid = pcn_csr_read16(pcnp, PCN_CSR_CHIPID1);
 493		chipid <<= 16;
 494		chipid |= pcn_csr_read16(pcnp, PCN_CSR_CHIPID0);
 495	} else {
 496		chipid = pcn_csr_read(pcnp, PCN_CSR_CHIPID1);
 497		chipid <<= 16;
 498		chipid |= pcn_csr_read(pcnp, PCN_CSR_CHIPID0);
 499	}
 500
 501	switch ((chipid >> 12) & PART_MASK) {
 502	case Am79C971:
 503	case Am79C972:
 504	case Am79C973:
 505	case Am79C975:
 506	case Am79C976:
 507	case Am79C978:
 508		break;
 509	default:
 510		pcn_error(pcnp->pcn_dip, "Unknown chip id 0x%u",
 511		    (chipid >> 12) & PART_MASK);
 512		return (DDI_FAILURE);
 513	}
 514
 515	if (ddi_prop_update_string(DDI_DEV_T_NONE, pcnp->pcn_dip, "chipid",
 516	    pcn_chipid_name(chipid)) != DDI_SUCCESS) {
 517		pcn_error(pcnp->pcn_dip, "Unable to set chipid property");
 518		return (DDI_FAILURE);
 519	}
 520
 521	return (DDI_SUCCESS);
 522}
 523
 524static int
 525pcn_setup_intr(pcn_t *pcnp)
 526{
 527	int	int_types, int_count, int_actual, int_avail;
 528	int	i, rc;
 529
 530	if ((rc = ddi_intr_get_supported_types(pcnp->pcn_dip, &int_types)) !=
 531	    DDI_SUCCESS) {
 532		pcn_error(pcnp->pcn_dip, "unable to get supported interrupt "
 533		    "types");
 534		return (DDI_FAILURE);
 535	}
 536
 537	if ((int_types & DDI_INTR_TYPE_FIXED) == 0) {
 538		pcn_error(pcnp->pcn_dip, "fixed interrupts are not supported");
 539		return (DDI_FAILURE);
 540	}
 541
 542	if ((rc = ddi_intr_get_nintrs(pcnp->pcn_dip, DDI_INTR_TYPE_FIXED,
 543	    &int_count)) != DDI_SUCCESS) {
 544		pcn_error(pcnp->pcn_dip, "unable to obtain the number of "
 545		    "interrupts");
 546		return (DDI_FAILURE);
 547	}
 548
 549	if (int_count != 1) {
 550		pcn_error(pcnp->pcn_dip, "interrupt count is %d, expected 1",
 551		    int_count);
 552		return (DDI_FAILURE);
 553	}
 554
 555	rc = ddi_intr_get_navail(pcnp->pcn_dip, DDI_INTR_TYPE_FIXED, &int_avail);
 556	if ((rc != DDI_SUCCESS) || (int_avail == 0)) {
 557		pcn_error(pcnp->pcn_dip, "ddi_intr_get_avail failed");
 558		return (DDI_FAILURE);
 559	}
 560
 561	rc = ddi_intr_alloc(pcnp->pcn_dip, &pcnp->pcn_htable, DDI_INTR_TYPE_FIXED, 0,
 562		int_count, &int_actual, DDI_INTR_ALLOC_STRICT);
 563	if ((rc != DDI_SUCCESS) || (int_actual != int_count)) {
 564		pcn_error(pcnp->pcn_dip, "unable to allocate fixed interrupt!");
 565		return (DDI_FAILURE);
 566	}
 567
 568	if ((rc = ddi_intr_get_pri(pcnp->pcn_htable, &pcnp->pcn_int_pri)) !=
 569	    DDI_SUCCESS) {
 570		pcn_error(pcnp->pcn_dip, "unable to obtain interrupt priority");
 571		ddi_intr_free(pcnp->pcn_htable);
 572		return (DDI_FAILURE);
 573	}
 574
 575	return (DDI_SUCCESS);
 576}
 577
 578int
 579pcn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 580{
 581	pcn_t	*pcnp;
 582
 583	pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip));
 584	if (pcnp == NULL) {
 585		pcn_error(dip, "no soft state in detach!");
 586		return (DDI_FAILURE);
 587	}
 588
 589	switch (cmd) {
 590	case DDI_DETACH:
 591		if (mac_unregister(pcnp->pcn_mh) != 0)
 592			return (DDI_FAILURE);
 593
 594		mutex_enter(&pcnp->pcn_intrlock);
 595		mutex_enter(&pcnp->pcn_xmtlock);
 596		pcnp->pcn_flags &= ~PCN_RUNNING;
 597		pcn_stopall(pcnp);
 598		mutex_exit(&pcnp->pcn_xmtlock);
 599		mutex_exit(&pcnp->pcn_intrlock);
 600
 601		ddi_intr_remove_handler(pcnp->pcn_htable);
 602		ddi_intr_free(pcnp->pcn_htable);
 603
 604		mii_free(pcnp->pcn_mii);
 605
 606		ddi_prop_remove_all(dip);
 607
 608		pcn_freerxring(pcnp);
 609		pcn_freetxring(pcnp);
 610
 611		ddi_regs_map_free(&pcnp->pcn_regshandle);
 612		mutex_destroy(&pcnp->pcn_intrlock);
 613		mutex_destroy(&pcnp->pcn_xmtlock);
 614
 615		ddi_soft_state_free(pcn_ssp, ddi_get_instance(dip));
 616		return (DDI_SUCCESS);
 617
 618	case DDI_SUSPEND:
 619		mii_suspend(pcnp->pcn_mii);
 620
 621		mutex_enter(&pcnp->pcn_intrlock);
 622		mutex_enter(&pcnp->pcn_xmtlock);
 623		pcnp->pcn_flags |= PCN_SUSPENDED;
 624		pcn_stopall(pcnp);
 625		mutex_exit(&pcnp->pcn_xmtlock);
 626		mutex_exit(&pcnp->pcn_intrlock);
 627		return (DDI_SUCCESS);
 628
 629	default:
 630		return (DDI_FAILURE);
 631	}
 632}
 633
 634int
 635pcn_resume(dev_info_t *dip)
 636{
 637	pcn_t	*pcnp;
 638
 639	pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip));
 640	if (pcnp == NULL)
 641		return (DDI_FAILURE);
 642
 643	mutex_enter(&pcnp->pcn_intrlock);
 644	mutex_enter(&pcnp->pcn_xmtlock);
 645
 646	pcnp->pcn_flags &= ~PCN_SUSPENDED;
 647
 648	if (!pcn_initialize(pcnp)) {
 649		pcn_error(pcnp->pcn_dip, "unable to resume chip");
 650		pcnp->pcn_flags |= PCN_SUSPENDED;
 651		mutex_exit(&pcnp->pcn_intrlock);
 652		mutex_exit(&pcnp->pcn_xmtlock);
 653		return (DDI_SUCCESS);
 654	}
 655
 656	if (pcnp->pcn_flags & PCN_RUNNING)
 657		pcn_startall(pcnp);
 658
 659	mutex_exit(&pcnp->pcn_xmtlock);
 660	mutex_exit(&pcnp->pcn_intrlock);
 661
 662	mii_resume(pcnp->pcn_mii);
 663
 664	return (DDI_SUCCESS);
 665}
 666
 667int
 668pcn_quiesce(dev_info_t *dip)
 669{
 670	pcn_t	*pcnp;
 671
 672	pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip));
 673	if (pcnp == NULL)
 674		return (DDI_FAILURE);
 675
 676	/*
 677	 * First suspend the chip, this should drain anything in
 678	 * in progress.
 679	 */
 680	PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
 681
 682	/* wait a reasonable amount of time for suspend to finish */
 683	drv_usecwait(RESET_DELAY);
 684
 685	/* abrupt stop */
 686	PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_STOP);
 687
 688	return (DDI_SUCCESS);
 689}
 690
 691static void
 692pcn_setrxfilt(pcn_t *pcnp)
 693{
 694	int	i;
 695
 696	if (pcnp->pcn_flags & PCN_SUSPENDED)
 697		return;
 698
 699	/* temporairly suspend card */
 700	PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
 701
 702	/* set promiscuous mode */
 703	if (pcnp->pcn_promisc)
 704		PCN_CSR_SETBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
 705	else
 706		PCN_CSR_CLRBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
 707
 708	/* program mac address */
 709	pcn_csr_write(pcnp, PCN_CSR_PAR0,
 710	    pcnp->pcn_addr[0] << 8 | pcnp->pcn_addr[1]);
 711	pcn_csr_write(pcnp, PCN_CSR_PAR1,
 712	    pcnp->pcn_addr[2] << 8 | pcnp->pcn_addr[2]);
 713	pcn_csr_write(pcnp, PCN_CSR_PAR2,
 714	    pcnp->pcn_addr[4] << 8 | pcnp->pcn_addr[5]);
 715
 716	/*
 717	 * program multicast filter
 718	 * I'm not sure if this is absolutely necessary, but it appears that
 719	 * the freebsd driver sets the filter to all 1's when in promiscuous
 720	 * mode, so we follow suit.
 721	 */
 722	for (i = 0; i < 4; i++)
 723		pcn_csr_write(pcnp, PCN_CSR_MAR0 + i,
 724		    pcnp->pcn_promisc ? 0xffff : pcnp->pcn_mctab[i]);
 725
 726	/* reenable card */
 727	PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
 728}
 729
 730static int
 731pcn_m_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
 732{
 733	pcn_t		*pcnp = (pcn_t *)arg;
 734	int		index;
 735	uint32_t	crc;
 736	uint32_t	bit;
 737	uint32_t	newval, oldval;
 738
 739	/*
 740	 * PCNet uses the upper 6 bits of the CRC of the macaddr
 741	 * to index into a 64bit mask
 742	 */
 743	CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table);
 744	crc = crc >> 26;
 745	index = crc / 16;
 746	bit = (1 << (crc % 16));
 747
 748	mutex_enter(&pcnp->pcn_intrlock);
 749	mutex_enter(&pcnp->pcn_xmtlock);
 750	newval = oldval = pcnp->pcn_mctab[index];
 751
 752	if (add) {
 753		pcnp->pcn_mccount[crc]++;
 754		if (pcnp->pcn_mccount[crc] == 1)
 755			newval |= bit;
 756	} else {
 757		pcnp->pcn_mccount[crc]--;
 758		if (pcnp->pcn_mccount[crc] == 0)
 759			newval &= ~bit;
 760	}
 761	if (newval != oldval) {
 762		pcnp->pcn_mctab[index] = newval;
 763		pcn_setrxfilt(pcnp);
 764	}
 765
 766	mutex_exit(&pcnp->pcn_xmtlock);
 767	mutex_exit(&pcnp->pcn_intrlock);
 768
 769	return (0);
 770}
 771
 772static int
 773pcn_m_promisc(void *arg, boolean_t on)
 774{
 775	pcn_t		*pcnp = (pcn_t *)arg;
 776
 777	mutex_enter(&pcnp->pcn_intrlock);
 778	mutex_enter(&pcnp->pcn_xmtlock);
 779
 780	pcnp->pcn_promisc = on;
 781	pcn_setrxfilt(pcnp);
 782
 783	mutex_exit(&pcnp->pcn_xmtlock);
 784	mutex_exit(&pcnp->pcn_intrlock);
 785
 786	return (0);
 787}
 788
 789static int
 790pcn_m_unicast(void *arg, const uint8_t *macaddr)
 791{
 792	pcn_t	*pcnp = (pcn_t *)arg;
 793
 794	mutex_enter(&pcnp->pcn_intrlock);
 795	mutex_enter(&pcnp->pcn_xmtlock);
 796
 797	bcopy(macaddr, pcnp->pcn_addr, ETHERADDRL);
 798	pcn_setrxfilt(pcnp);
 799
 800	mutex_exit(&pcnp->pcn_xmtlock);
 801	mutex_exit(&pcnp->pcn_intrlock);
 802
 803	return (0);
 804}
 805
 806static mblk_t *
 807pcn_m_tx(void *arg, mblk_t *mp)
 808{
 809	pcn_t	*pcnp = (pcn_t *)arg;
 810	mblk_t	*nmp;
 811
 812	mutex_enter(&pcnp->pcn_xmtlock);
 813
 814	if (pcnp->pcn_flags & PCN_SUSPENDED) {
 815		while ((nmp = mp) != NULL) {
 816			pcnp->pcn_carrier_errors++;
 817			mp = mp->b_next;
 818			freemsg(nmp);
 819		}
 820		mutex_exit(&pcnp->pcn_xmtlock);
 821		return (NULL);
 822	}
 823
 824	while (mp != NULL) {
 825		nmp = mp->b_next;
 826		mp->b_next = NULL;
 827
 828		if (!pcn_send(pcnp, mp)) {
 829			mp->b_next = nmp;
 830			break;
 831		}
 832		mp = nmp;
 833	}
 834	mutex_exit(&pcnp->pcn_xmtlock);
 835
 836	return (mp);
 837}
 838
 839static boolean_t
 840pcn_send(pcn_t *pcnp, mblk_t *mp)
 841{
 842	size_t		len;
 843	pcn_buf_t	*txb;
 844	pcn_tx_desc_t	*tmd;
 845	int		txsend;
 846
 847	ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
 848	ASSERT(mp != NULL);
 849
 850	len = msgsize(mp);
 851	if (len > ETHERVLANMTU) {
 852		pcnp->pcn_macxmt_errors++;
 853		freemsg(mp);
 854		return (B_TRUE);
 855	}
 856
 857	if (pcnp->pcn_txavail < PCN_TXRECLAIM)
 858		pcn_reclaim(pcnp);
 859
 860	if (pcnp->pcn_txavail == 0) {
 861		pcnp->pcn_wantw = B_TRUE;
 862		pcn_enableinterrupts(pcnp);
 863		return (B_FALSE);
 864	}
 865
 866	txsend = pcnp->pcn_txsend;
 867
 868	txb = pcnp->pcn_txbufs[txsend];
 869	mcopymsg(mp, txb->pb_buf);	/* frees mp! */
 870
 871	pcnp->pcn_opackets++;
 872	pcnp->pcn_obytes += len;
 873	if (txb->pb_buf[0] & 0x1) {
 874		if (bcmp(txb->pb_buf, pcn_broadcast, ETHERADDRL) != 0)
 875			pcnp->pcn_multixmt++;
 876		else
 877			pcnp->pcn_brdcstxmt++;
 878	}
 879
 880	SYNCBUF(txb, len, DDI_DMA_SYNC_FORDEV);
 881
 882	tmd = &pcnp->pcn_txdescp[txsend];
 883	tmd->pcn_tbaddr = txb->pb_paddr;
 884	tmd->pcn_txctl = PCN_TXCTL_STP|PCN_TXCTL_ENP|PCN_TXCTL_ADD_FCS|
 885	    PCN_TXCTL_MORE_LTINT|0xf000;
 886	/* PCNet wants the 2's complement of the length of the buffer */
 887	tmd->pcn_txctl |= (~(len) + 1) & PCN_TXCTL_BUFSZ;
 888
 889	/* Spec suggests this should be set last */
 890	tmd->pcn_txctl |= PCN_TXCTL_OWN;
 891	SYNCTXDESC(pcnp, txsend, DDI_DMA_SYNC_FORDEV);
 892
 893	pcnp->pcn_txavail--;
 894	pcnp->pcn_txsend = (txsend + 1) % PCN_TXRING;
 895
 896	pcnp->pcn_txstall_time = gethrtime() + (5 * 1000000000ULL);
 897
 898	pcn_csr_write(pcnp, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN);
 899
 900        return (B_TRUE);
 901}
 902
 903static void
 904pcn_reclaim(pcn_t *pcnp)
 905{
 906	pcn_tx_desc_t	*tmdp;
 907
 908	while (pcnp->pcn_txavail != PCN_TXRING) {
 909		int index = pcnp->pcn_txreclaim;
 910
 911		tmdp = &pcnp->pcn_txdescp[index];
 912
 913		/* sync before reading */
 914		SYNCTXDESC(pcnp, index, DDI_DMA_SYNC_FORKERNEL);
 915
 916		/* check if chip is still working on it */
 917		if (tmdp->pcn_txctl & PCN_TXCTL_OWN)
 918			break;
 919
 920		pcnp->pcn_txavail++;
 921		pcnp->pcn_txreclaim = (index + 1) % PCN_TXRING;
 922	}
 923
 924	if (pcnp->pcn_txavail >= PCN_TXRESCHED)
 925		if (pcnp->pcn_wantw) {
 926			pcnp->pcn_wantw = B_FALSE;
 927			pcn_enableinterrupts(pcnp);
 928			mac_tx_update(pcnp->pcn_mh);
 929		}
 930}
 931
 932static unsigned
 933pcn_intr(caddr_t arg1, caddr_t arg2)
 934{
 935	pcn_t		*pcnp = (pcn_t *)arg1;
 936	mblk_t		*mp = NULL;
 937	uint32_t	status;
 938	boolean_t	do_reset = B_FALSE;
 939
 940	mutex_enter(&pcnp->pcn_intrlock);
 941
 942	if (pcnp->pcn_flags & PCN_SUSPENDED) {
 943		mutex_exit(&pcnp->pcn_intrlock);
 944		return (DDI_INTR_UNCLAIMED);
 945	}
 946
 947	CSR_WRITE_4(pcnp, PCN_IO32_RAP, PCN_CSR_CSR);
 948
 949	while ((status = CSR_READ_4(pcnp, PCN_IO32_RDP)) & PCN_CSR_INTR) {
 950		CSR_WRITE_4(pcnp, PCN_IO32_RDP, status);
 951
 952		if (status & PCN_CSR_TINT) {
 953			mutex_enter(&pcnp->pcn_xmtlock);
 954			pcn_reclaim(pcnp);
 955			mutex_exit(&pcnp->pcn_xmtlock);
 956		}
 957
 958		if (status & PCN_CSR_RINT)
 959			mp = pcn_receive(pcnp);
 960
 961		if (status & PCN_CSR_ERR) {
 962			do_reset = B_TRUE;
 963			break;
 964		}
 965	}
 966
 967	if (do_reset) {
 968		mutex_enter(&pcnp->pcn_xmtlock);
 969		pcn_resetall(pcnp);
 970		mutex_exit(&pcnp->pcn_xmtlock);
 971		mutex_exit(&pcnp->pcn_intrlock);
 972
 973		mii_reset(pcnp->pcn_mii);
 974	} else {
 975		mutex_exit(&pcnp->pcn_intrlock);
 976	}
 977
 978	if (mp)
 979		mac_rx(pcnp->pcn_mh, NULL, mp);
 980
 981	return (DDI_INTR_CLAIMED);
 982}
 983
 984static mblk_t *
 985pcn_receive(pcn_t *pcnp)
 986{
 987	uint32_t	len;
 988	pcn_buf_t	*rxb;
 989	pcn_rx_desc_t	*rmd;
 990	mblk_t		*mpchain, **mpp, *mp;
 991	int		head, cnt;
 992
 993	mpchain = NULL;
 994	mpp = &mpchain;
 995	head = pcnp->pcn_rxhead;
 996
 997	for (cnt = 0; cnt < PCN_RXRING; cnt++) {
 998		rmd = &pcnp->pcn_rxdescp[head];
 999		rxb = pcnp->pcn_rxbufs[head];
1000
1001		SYNCRXDESC(pcnp, head, DDI_DMA_SYNC_FORKERNEL);
1002		if (rmd->pcn_rxstat & PCN_RXSTAT_OWN)
1003			break;
1004
1005		len = rmd->pcn_rxlen - ETHERFCSL;
1006		if (rmd->pcn_rxstat & PCN_RXSTAT_ERR) {
1007			pcnp->pcn_errrcv++;
1008
1009			if (rmd->pcn_rxstat & PCN_RXSTAT_FRAM)
1010				pcnp->pcn_align_errors++;
1011			if (rmd->pcn_rxstat & PCN_RXSTAT_OFLOW)
1012				pcnp->pcn_overflow++;
1013			if (rmd->pcn_rxstat & PCN_RXSTAT_CRC)
1014				pcnp->pcn_fcs_errors++;
1015		} else if (len > ETHERVLANMTU) {
1016			pcnp->pcn_errrcv++;
1017			pcnp->pcn_toolong_errors++;
1018		} else {
1019			mp = allocb(len + PCN_HEADROOM, 0);
1020			if (mp == NULL) {
1021				pcnp->pcn_errrcv++;
1022				pcnp->pcn_norcvbuf++;
1023				goto skip;
1024			}
1025
1026			SYNCBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
1027			mp->b_rptr += PCN_HEADROOM;
1028			mp->b_wptr = mp->b_rptr + len;
1029			bcopy((char *)rxb->pb_buf, mp->b_rptr, len);
1030
1031			pcnp->pcn_ipackets++;
1032			pcnp->pcn_rbytes++;
1033
1034			if (rmd->pcn_rxstat & PCN_RXSTAT_LAFM|PCN_RXSTAT_BAM) {
1035				if (rmd->pcn_rxstat & PCN_RXSTAT_BAM)
1036					pcnp->pcn_brdcstrcv++;
1037				else
1038					pcnp->pcn_multircv++;
1039			}
1040			*mpp = mp;
1041			mpp = &mp->b_next;
1042		}
1043
1044skip:
1045		rmd->pcn_rxstat &= ~(PCN_RXSTAT_OWN);
1046		SYNCRXDESC(pcnp, head, DDI_DMA_SYNC_FORDEV);
1047
1048		head = (head + 1) % PCN_RXRING;
1049	}
1050
1051	pcnp->pcn_rxhead = head;
1052
1053	return (mpchain);
1054}
1055
1056static void
1057pcn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1058{
1059	pcn_t *pcnp = (pcn_t *)arg;
1060
1061	if (mii_m_loop_ioctl(pcnp->pcn_mii, wq, mp))
1062		return;
1063
1064	miocnak(wq, mp, 0, EINVAL);
1065}
1066
1067static int
1068pcn_m_start(void *arg)
1069{
1070	pcn_t	*pcnp = (pcn_t *)arg;
1071
1072	mutex_enter(&pcnp->pcn_intrlock);
1073	mutex_enter(&pcnp->pcn_xmtlock);
1074
1075	pcn_startall(pcnp);
1076	pcnp->pcn_flags |= PCN_RUNNING;
1077
1078	mutex_exit(&pcnp->pcn_xmtlock);
1079	mutex_exit(&pcnp->pcn_intrlock);
1080
1081	mii_start(pcnp->pcn_mii);
1082
1083	return (0);
1084}
1085
1086static void
1087pcn_m_stop(void *arg)
1088{
1089	pcn_t	*pcnp = (pcn_t *)arg;
1090
1091	mii_stop(pcnp->pcn_mii);
1092
1093	mutex_enter(&pcnp->pcn_intrlock);
1094	mutex_enter(&pcnp->pcn_xmtlock);
1095
1096	pcn_stopall(pcnp);
1097	pcnp->pcn_flags &= ~PCN_RUNNING;
1098
1099	mutex_exit(&pcnp->pcn_xmtlock);
1100	mutex_exit(&pcnp->pcn_intrlock);
1101}
1102
1103static int
1104pcn_initialize(pcn_t *pcnp)
1105{
1106	uint32_t	par;
1107
1108	/*
1109	 * Issue a reset by reading from the RESET register.
1110	 * Note that we don't know if the chip is operating in
1111	 * 16-bit or 32-bit mode at this point, so we attempt
1112	 * to reset the chip both ways.  If one fails, the other
1113	 * will succeed.
1114	 */
1115	CSR_READ_2(pcnp, PCN_IO16_RESET);
1116	CSR_READ_4(pcnp, PCN_IO32_RESET);
1117
1118	drv_usecwait(1000);
1119
1120	/* Select 32-bit (DWIO) mode */
1121	CSR_WRITE_4(pcnp, PCN_IO32_RDP, 0);
1122
1123	/* Select software style 3. */
1124	pcn_bcr_write(pcnp, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI_BURST);
1125
1126	par = 0;
1127	
1128	pcn_resetrings(pcnp);
1129
1130	pcn_setrxfilt(pcnp);
1131
1132	/* Enable fast suspend mode. */
1133	PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE);
1134
1135	return (DDI_SUCCESS);
1136}
1137
1138static void
1139pcn_resetall(pcn_t *pcnp)
1140{
1141	pcn_stopall(pcnp);
1142	pcn_startall(pcnp);
1143}
1144
1145static void
1146pcn_startmac(pcn_t *pcnp)
1147{
1148	ASSERT(mutex_owned(&pcnp->pcn_intrlock));
1149	ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
1150
1151	PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_START);
1152
1153	if (pcnp->pcn_flags & PCN_RUNNING)
1154		mac_tx_update(pcnp->pcn_mh);
1155}
1156
1157static void
1158pcn_stopmac(pcn_t *pcnp)
1159{
1160	ASSERT(mutex_owned(&pcnp->pcn_intrlock));
1161	ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
1162
1163	PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_STOP);
1164}
1165
1166static void
1167pcn_startall(pcn_t *pcnp)
1168{
1169	ASSERT(mutex_owned(&pcnp->pcn_intrlock));
1170	ASSERT(mutex_owned(&pcnp->pcn_xmtlock));
1171
1172	pcn_disableinterrupts(pcnp);
1173	(void) pcn_initialize(pcnp);
1174
1175	pcn_enableinterrupts(pcnp);
1176	pcn_startmac(pcnp);
1177}
1178
1179static void
1180pcn_stopall(pcn_t *pcnp)
1181{
1182	pcn_disableinterrupts(pcnp);
1183	pcn_stopmac(pcnp);
1184}
1185
1186static int
1187pcn_m_stat(void *arg, uint_t stat, uint64_t *val)
1188{
1189	pcn_t	*pcnp = (pcn_t *)arg;
1190
1191	if (mii_m_getstat(pcnp->pcn_mii, stat, val) == 0)
1192		return (0);
1193
1194	switch (stat) {
1195	case MAC_STAT_MULTIRCV:
1196		*val = pcnp->pcn_multircv;
1197		break;
1198
1199	case MAC_STAT_BRDCSTRCV:
1200		*val = pcnp->pcn_brdcstrcv;
1201		break;
1202
1203	case MAC_STAT_MULTIXMT:
1204		*val = pcnp->pcn_multixmt;
1205		break;
1206
1207	case MAC_STAT_BRDCSTXMT:
1208		*val = pcnp->pcn_brdcstxmt;
1209		break;
1210
1211	case MAC_STAT_IPACKETS:
1212		*val = pcnp->pcn_ipackets;
1213		break;
1214
1215	case MAC_STAT_RBYTES:
1216		*val = pcnp->pcn_rbytes;
1217		break;
1218
1219	case MAC_STAT_OPACKETS:
1220		*val = pcnp->pcn_opackets;
1221		break;
1222
1223	case MAC_STAT_OBYTES:
1224		*val = pcnp->pcn_obytes;
1225		break;
1226
1227	case MAC_STAT_NORCVBUF:
1228		*val = pcnp->pcn_norcvbuf;
1229		break;
1230
1231	case MAC_STAT_NOXMTBUF:
1232		*val = 0;
1233		break;
1234
1235	case MAC_STAT_COLLISIONS:
1236		*val = pcnp->pcn_collisions;
1237		break;
1238
1239	case MAC_STAT_IERRORS:
1240		*val = pcnp->pcn_errrcv;
1241		break;
1242
1243	case MAC_STAT_OERRORS:
1244		*val = pcnp->pcn_errxmt;
1245		break;
1246
1247	case ETHER_STAT_ALIGN_ERRORS:
1248		*val = pcnp->pcn_align_errors;
1249		break;
1250
1251	case ETHER_STAT_FCS_ERRORS:
1252		*val = pcnp->pcn_fcs_errors;
1253		break;
1254
1255	case ETHER_STAT_SQE_ERRORS:
1256		*val = pcnp->pcn_sqe_errors;
1257		break;
1258
1259	case ETHER_STAT_DEFER_XMTS:
1260		*val = pcnp->pcn_defer_xmts;
1261		break;
1262
1263	case ETHER_STAT_FIRST_COLLISIONS:
1264		*val = pcnp->pcn_first_collisions;
1265		break;
1266
1267	case ETHER_STAT_MULTI_COLLISIONS:
1268		*val = pcnp->pcn_multi_collisions;
1269		break;
1270
1271	case ETHER_STAT_TX_LATE_COLLISIONS:
1272		*val = pcnp->pcn_tx_late_collisions;
1273		break;
1274
1275	case ETHER_STAT_EX_COLLISIONS:
1276		*val = pcnp->pcn_ex_collisions;
1277		break;
1278
1279	case ETHER_STAT_MACXMT_ERRORS:
1280		*val = pcnp->pcn_macxmt_errors;
1281		break;
1282
1283	case ETHER_STAT_CARRIER_ERRORS:
1284		*val = pcnp->pcn_carrier_errors;
1285		break;
1286
1287	case ETHER_STAT_TOOLONG_ERRORS:
1288		*val = pcnp->pcn_toolong_errors;
1289		break;
1290
1291	case ETHER_STAT_MACRCV_ERRORS:
1292		*val = pcnp->pcn_macrcv_errors;
1293		break;
1294
1295	case MAC_STAT_OVERFLOWS:
1296		*val = pcnp->pcn_overflow;
1297		break;
1298
1299	case MAC_STAT_UNDERFLOWS:
1300		*val = pcnp->pcn_underflow;
1301		break;
1302
1303	case ETHER_STAT_TOOSHORT_ERRORS:
1304		*val = pcnp->pcn_runt;
1305		break;
1306
1307	case ETHER_STAT_JABBER_ERRORS:
1308		*val = pcnp->pcn_jabber;
1309		break;
1310
1311	default:
1312		return (ENOTSUP);
1313	}
1314	return (0);
1315}
1316
1317static int
1318pcn_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags,
1319    uint_t sz, void *val, uint_t *perm)
1320{
1321	pcn_t	*pcnp = (pcn_t *)arg;
1322
1323	return (mii_m_getprop(pcnp->pcn_mii, name, num, flags, sz, val, perm));
1324}
1325
1326static int
1327pcn_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1328    const void *val)
1329{
1330	pcn_t	*pcnp = (pcn_t *)arg;
1331
1332	return (mii_m_setprop(pcnp->pcn_mii, name, num, sz, val));
1333}
1334
1335static uint16_t
1336pcn_mii_read(void *arg, uint8_t phy, uint8_t reg)
1337{
1338	pcn_t		*pcnp = (pcn_t *)arg;
1339	uint16_t	val;
1340
1341	/*
1342	 * At least Am79C971 with DP83840A wedge when isolating the
1343	 * external PHY so we can't allow multiple external PHYs.
1344	 * There are cards that use Am79C971 with both the internal
1345	 * and an external PHY though.
1346	 * For internal PHYs it doesn't really matter whether we can
1347	 * isolate the remaining internal and the external ones in
1348	 * the PHY drivers as the internal PHYs have to be enabled
1349	 * individually in PCN_BCR_PHYSEL, PCN_CSR_MODE, etc.
1350	 * With Am79C97{3,5,8} we don't support switching beetween
1351	 * the internal and external PHYs, yet, so we can't allow
1352	 * multiple PHYs with these either.
1353	 * Am79C97{2,6} actually only support external PHYs (not
1354	 * connectable internal ones respond at the usual addresses,
1355	 * which don't hurt if we let them show up on the bus) and
1356	 * isolating them works.
1357	 */
1358	if (((pcnp->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) ||
1359	    pcnp->pcn_type == Am79C973 || pcnp->pcn_type == Am79C975 ||
1360	    pcnp->pcn_type == Am79C978) && pcnp->pcn_extphyaddr != 0xff &&
1361	    phy != pcnp->pcn_extphyaddr)
1362		return (0xffff);
1363
1364	pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, reg | (phy << 5));
1365	val = pcn_bcr_read(pcnp, PCN_BCR_MIIDATA) & 0xFFFF;
1366	if (val == 0xFFFF)
1367		return (val);
1368
1369	if (((pcnp->pcn_type == Am79C971 && phy != PCN_PHYAD_10BT) ||
1370	    pcnp->pcn_type == Am79C973 || pcnp->pcn_type == Am79C975 ||
1371	    pcnp->pcn_type == Am79C978) && pcnp->pcn_extphyaddr == 0xff)
1372		pcnp->pcn_extphyaddr = phy;
1373
1374	return (val);
1375}
1376
1377static void
1378pcn_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
1379{
1380	pcn_t		*pcnp = (pcn_t *)arg;
1381
1382	pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, reg | (phy << 5));
1383	pcn_bcr_write(pcnp, PCN_BCR_MIIDATA, val);
1384}
1385
1386static void
1387pcn_mii_notify(void *arg, link_state_t link)
1388{
1389	pcn_t		*pcnp = (pcn_t *)arg;
1390
1391	mac_link_update(pcnp->pcn_mh, link);
1392}
1393
1394static const pcn_type_t *
1395pcn_match(uint16_t vid, uint16_t did)
1396{
1397	const pcn_type_t	*t;
1398
1399	t = pcn_devs;
1400	while (t->pcn_name != NULL) {
1401		if ((vid == t->pcn_vid) && (did == t->pcn_did))
1402			return (t);
1403		t++;
1404	}
1405	return (NULL);
1406}
1407
1408static char *
1409pcn_chipid_name(uint32_t id)
1410{
1411	const struct pcn_chipid *p;
1412
1413	p = pcn_chipid;
1414	while (p->name) {
1415		if (id == p->id)
1416			return (p->name);
1417		p++;
1418	}
1419	return ("Unknown");
1420}
1421
1422static void
1423pcn_getfactaddr(pcn_t *pcnp)
1424{
1425	uint32_t addr[2];
1426
1427	addr[0] = CSR_READ_4(pcnp, PCN_IO32_APROM00);
1428	addr[1] = CSR_READ_4(pcnp, PCN_IO32_APROM01);
1429
1430	pcnp->pcn_addr[5] = addr[1] >> 8 & 0x000000ffL;
1431	pcnp->pcn_addr[4] = addr[1] & 0x000000ffL;
1432	pcnp->pcn_addr[3] = addr[0] >> 24;
1433	pcnp->pcn_addr[2] = addr[0] >> 16 & 0x000000ffL;
1434	pcnp->pcn_addr[1] = addr[0] >> 8 & 0x000000ffL;
1435	pcnp->pcn_addr[0] = addr[0] & 0x000000ffL;
1436}
1437
1438static void
1439pcn_enableinterrupts(pcn_t *pcnp)
1440{
1441	pcn_csr_write(pcnp, PCN_CSR_CSR, PCN_CSR_INTEN);
1442}
1443
1444static void
1445pcn_disableinterrupts(pcn_t *pcnp)
1446{
1447	PCN_CSR_CLRBIT(pcnp, PCN_CSR_CSR, PCN_CSR_INTEN);
1448}
1449
1450static uint32_t
1451pcn_csr_read(pcn_t *pcnp, uint32_t reg)
1452{
1453	CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
1454	return (CSR_READ_4(pcnp, PCN_IO32_RDP));
1455}
1456
1457static uint16_t
1458pcn_csr_read16(pcn_t *pcnp, uint32_t reg)
1459{
1460	CSR_WRITE_2(pcnp, PCN_IO16_RAP, reg);
1461	return (CSR_READ_2(pcnp, PCN_IO16_RDP));
1462}
1463
1464static void
1465pcn_csr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
1466{
1467	CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
1468	CSR_WRITE_4(pcnp, PCN_IO32_RDP, val);
1469}
1470
1471static uint32_t
1472pcn_bcr_read(pcn_t *pcnp, uint32_t reg)
1473{
1474	CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
1475	return (CSR_READ_4(pcnp, PCN_IO32_BDP));
1476}
1477
1478static uint16_t
1479pcn_bcr_read16(pcn_t *pcnp, uint32_t reg)
1480{
1481	CSR_WRITE_2(pcnp, PCN_IO16_RAP, reg);
1482	return (CSR_READ_2(pcnp, PCN_IO16_BDP));
1483}
1484
1485static void
1486pcn_bcr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
1487{
1488	CSR_WRITE_4(pcnp, PCN_IO32_RAP, reg);
1489	CSR_WRITE_4(pcnp, PCN_IO32_BDP, val);
1490}
1491
1492static void
1493pcn_resetrings(pcn_t *pcnp)
1494{
1495	int	i;
1496
1497	pcnp->pcn_rxhead = 0;
1498	pcnp->pcn_txreclaim = 0;
1499	pcnp->pcn_txsend = 0;
1500	pcnp->pcn_txavail = PCN_TXRING;
1501
1502	/* set addresses of decriptors */
1503	pcn_csr_write(pcnp, PCN_CSR_RXADDR0, pcnp->pcn_rxdesc_paddr & 0xFFFF);
1504	pcn_csr_write(pcnp, PCN_CSR_RXADDR1,
1505	    (pcnp->pcn_rxdesc_paddr >> 16) & 0xFFFF);
1506
1507	pcn_csr_write(pcnp, PCN_CSR_TXADDR0, pcnp->pcn_txdesc_paddr & 0xFFFF);
1508	pcn_csr_write(pcnp, PCN_CSR_TXADDR1,
1509	    (pcnp->pcn_txdesc_paddr >> 16) & 0xFFFF);
1510
1511	/* set the ring sizes */
1512	pcn_csr_write(pcnp, PCN_CSR_RXRINGLEN, (~PCN_RXRING) + 1);
1513	pcn_csr_write(pcnp, PCN_CSR_TXRINGLEN, (~PCN_TXRING) + 1);
1514
1515	/* don't use the initializtation block */
1516	pcn_csr_write(pcnp, PCN_CSR_IAB1, 0);
1517
1518	/* reset rx descriptor values */
1519	for (i = 0; i < PCN_RXRING; i++) {
1520		pcn_rx_desc_t	*rmd = &pcnp->pcn_rxdescp[i];
1521		pcn_buf_t	*rxb = pcnp->pcn_rxbufs[i];
1522
1523		rmd->pcn_rbaddr = rxb->pb_paddr;
1524		rmd->pcn_bufsz = (~(PCN_BUFSZ) + 1) & PCN_RXLEN_BUFSZ;
1525		rmd->pcn_bufsz |= PCN_RXLEN_MBO;
1526		rmd->pcn_rxstat = PCN_RXSTAT_STP|PCN_RXSTAT_ENP|PCN_RXSTAT_OWN;
1527	}
1528
1529	/* tx descriptors get set on each tx, so no need to do it again */
1530}
1531
1532static void
1533pcn_destroybuf(pcn_buf_t *buf)
1534{
1535	if (buf == NULL)
1536		return;
1537
1538	if (buf->pb_paddr)
1539		(void) ddi_dma_unbind_handle(buf->pb_dmah);
1540	if (buf->pb_acch)
1541		ddi_dma_mem_free(&buf->pb_acch);
1542	if (buf->pb_dmah)
1543		ddi_dma_free_handle(&buf->pb_dmah);
1544	kmem_free(buf, sizeof (*buf));
1545}
1546
1547static pcn_buf_t *
1548pcn_allocbuf(pcn_t *pcnp)
1549{
1550	pcn_buf_t		*buf;
1551	size_t			len;
1552	unsigned		ccnt;
1553	ddi_dma_cookie_t	dmac;
1554
1555	buf = kmem_zalloc(sizeof (*buf), KM_SLEEP);
1556
1557	if (ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
1558	    NULL, &buf->pb_dmah) != DDI_SUCCESS) {
1559		kmem_free(buf, sizeof (*buf));
1560		return (NULL);
1561	}
1562
1563	if (ddi_dma_mem_alloc(buf->pb_dmah, PCN_BUFSZ, &pcn_bufattr,
1564	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &buf->pb_buf, &len,
1565	    &buf->pb_acch) != DDI_SUCCESS) {
1566		pcn_destroybuf(buf);
1567		return (NULL);
1568	}
1569
1570	if (ddi_dma_addr_bind_handle(buf->pb_dmah, NULL, buf->pb_buf, len,
1571	    DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
1572	    &ccnt) != DDI_DMA_MAPPED) {
1573		pcn_destroybuf(buf);
1574		return (NULL);
1575	}
1576	buf->pb_paddr = dmac.dmac_address;
1577
1578	return (buf);
1579}
1580
1581static int
1582pcn_alloctxring(pcn_t *pcnp)
1583{
1584	int			rval;
1585	int			i;
1586	size_t			size;
1587	size_t			len;
1588	ddi_dma_cookie_t	dmac;
1589	unsigned		ncookies;
1590	caddr_t			kaddr;
1591
1592	size = PCN_TXRING * sizeof (pcn_tx_desc_t);
1593
1594	rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
1595	    NULL, &pcnp->pcn_txdesc_dmah);
1596	if (rval != DDI_SUCCESS) {
1597		pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for tx "
1598		    "descriptors");
1599		return (DDI_FAILURE);
1600	}
1601
1602	rval = ddi_dma_mem_alloc(pcnp->pcn_txdesc_dmah, size, &pcn_devattr,
1603	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
1604	    &pcnp->pcn_txdesc_acch);
1605	if (rval != DDI_SUCCESS) {
1606		pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for tx "
1607		    "descriptors");
1608		return (DDI_FAILURE);
1609	}
1610
1611	rval = ddi_dma_addr_bind_handle(pcnp->pcn_txdesc_dmah, NULL, kaddr,
1612	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &dmac,
1613	    &ncookies);
1614	if (rval != DDI_DMA_MAPPED) {
1615		pcn_error(pcnp->pcn_dip, "unable to bind DMA for tx "
1616		    "descriptors");
1617		return (DDI_FAILURE);
1618	}
1619
1620	ASSERT(ncookies == 1);
1621
1622	pcnp->pcn_txdesc_paddr = dmac.dmac_address;
1623	pcnp->pcn_txdescp = (void *)kaddr;
1624
1625	pcnp->pcn_txbufs = kmem_zalloc(PCN_TXRING * sizeof (pcn_buf_t *),
1626	    KM_SLEEP);
1627
1628	for (i = 0; i < PCN_TXRING; i++) {
1629		pcn_buf_t *txb = pcn_allocbuf(pcnp);
1630		if (txb == NULL)
1631			return (DDI_FAILURE);
1632		pcnp->pcn_txbufs[i] = txb;
1633	}
1634
1635	return (DDI_SUCCESS);
1636}
1637
1638static int
1639pcn_allocrxring(pcn_t *pcnp)
1640{
1641	int			rval;
1642	int			i;
1643	size_t			len;
1644	size_t			size;
1645	ddi_dma_cookie_t	dmac;
1646	unsigned		ncookies;
1647	caddr_t			kaddr;
1648
1649	size = PCN_RXRING * sizeof (pcn_rx_desc_t);
1650
1651	rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dmadesc_attr,
1652	    DDI_DMA_SLEEP, NULL, &pcnp->pcn_rxdesc_dmah);
1653	if (rval != DDI_SUCCESS) {
1654		pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for rx "
1655		    "descriptors");
1656		return (DDI_FAILURE);
1657	}
1658
1659	rval = ddi_dma_mem_alloc(pcnp->pcn_rxdesc_dmah, size, &pcn_devattr,
1660	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
1661	    &pcnp->pcn_rxdesc_acch);
1662	if (rval != DDI_SUCCESS) {
1663		pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for rx "
1664		    "descriptors");
1665		return (DDI_FAILURE);
1666	}
1667
1668	rval = ddi_dma_addr_bind_handle(pcnp->pcn_rxdesc_dmah, NULL, kaddr,
1669	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &dmac,
1670	    &ncookies);
1671	if (rval != DDI_DMA_MAPPED) {
1672		pcn_error(pcnp->pcn_dip, "unable to bind DMA for rx "
1673		    "descriptors");
1674		return (DDI_FAILURE);
1675	}
1676
1677	ASSERT(ncookies == 1);
1678
1679	pcnp->pcn_rxdesc_paddr = dmac.dmac_address;
1680	pcnp->pcn_rxdescp = (void *)kaddr;
1681
1682	pcnp->pcn_rxbufs = kmem_zalloc(PCN_RXRING * sizeof (pcn_buf_t *),
1683	    KM_SLEEP);
1684
1685	for (i = 0; i < PCN_RXRING; i++) {
1686		pcn_buf_t *rxb = pcn_allocbuf(pcnp);
1687		if (rxb == NULL)
1688			return (DDI_FAILURE);
1689		pcnp->pcn_rxbufs[i] = rxb;
1690	}
1691
1692	return (DDI_SUCCESS);
1693}
1694
1695static void
1696pcn_freetxring(pcn_t *pcnp)
1697{
1698	int	i;
1699
1700	for (i = 0; i < PCN_TXRING; i++)
1701		pcn_destroybuf(pcnp->pcn_txbufs[i]);
1702
1703	if (pcnp->pcn_txbufs)
1704		kmem_free(pcnp->pcn_txbufs, PCN_TXRING * sizeof (pcn_buf_t *));
1705
1706	if (pcnp->pcn_txdesc_paddr)
1707		(void) ddi_dma_unbind_handle(pcnp->pcn_txdesc_dmah);
1708	if (pcnp->pcn_txdesc_acch)
1709		ddi_dma_mem_free(&pcnp->pcn_txdesc_acch);
1710	if (pcnp->pcn_txdesc_dmah)
1711		ddi_dma_free_handle(&pcnp->pcn_txdesc_dmah);
1712}
1713
1714static void
1715pcn_freerxring(pcn_t *pcnp)
1716{
1717	int	i;
1718
1719	for (i = 0; i < PCN_RXRING; i++)
1720		pcn_destroybuf(pcnp->pcn_rxbufs[i]);
1721
1722	if (pcnp->pcn_rxbufs)
1723		kmem_free(pcnp->pcn_rxbufs, PCN_RXRING * sizeof (pcn_buf_t *));
1724
1725	if (pcnp->pcn_rxdesc_paddr)
1726		(void) ddi_dma_unbind_handle(pcnp->pcn_rxdesc_dmah);
1727	if (pcnp->pcn_rxdesc_acch)
1728		ddi_dma_mem_free(&pcnp->pcn_rxdesc_acch);
1729	if (pcnp->pcn_rxdesc_dmah)
1730		ddi_dma_free_handle(&pcnp->pcn_rxdesc_dmah);
1731}
1732
1733static void
1734pcn_error(dev_info_t *dip, char *fmt, ...)
1735{
1736	va_list	ap;
1737	char	buf[256];
1738
1739	va_start(ap, fmt);
1740	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
1741	va_end(ap);
1742
1743	if (dip)
1744		cmn_err(CE_WARN, "%s%d: %s", ddi_driver_name(dip),
1745		    ddi_get_instance(dip), buf);
1746	else
1747		cmn_err(CE_WARN, "pcn: %s", buf);
1748}