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 * Redistribution and use in source and binary forms, with or without
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * modification, are permitted provided that the following conditions
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 * 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 ddi_put32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg), val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_put16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg), val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_get32(pcnp->pcn_regshandle, (uint32_t *)(pcnp->pcn_regs + reg))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_get16(pcnp->pcn_regshandle, (uint16_t *)(pcnp->pcn_regs + reg))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) | (x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, reg, pcn_csr_read(pcnp, reg) & ~(x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) | (x))
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, reg, pcn_bcr_read(pcnp, reg) & ~(x))
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_m_unicast(void *, const uint8_t *);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic int pcn_m_multicast(void *, boolean_t, const uint8_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 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 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 uint16_t pcn_csr_read16(pcn_t *, uint32_t);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic void pcn_csr_write(pcn_t *, uint32_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 Kingstatic const pcn_type_t *pcn_match(uint16_t, uint16_t);
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 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason KingDDI_DEFINE_STREAM_OPS(pcn_devops, nulldev, nulldev, pcn_attach, pcn_detach,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "AMD PCnet",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0, /* dma_attr_addr_lo */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0 /* dma_attr_flags */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0, /* dma_attr_addr_lo */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King 0 /* dma_attr_flags */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * DDI entry points
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = ddi_soft_state_init(&pcn_ssp, sizeof (pcn_t), 1)) != 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = mod_install(&pcn_modlinkage)) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((rc = mod_remove(&pcn_modlinkage)) == DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "slot does not support PCI bus-master");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "hilevel interrupts not supported");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "unable to setup PCI config handle");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcn_type = pcn_match(venid, devid)) == NULL) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "Unable to create model property");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_soft_state_zalloc(pcn_ssp, instance) != DDI_SUCCESS) {
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 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 * Enable bus master, IO space, and memory space accesses
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_ME | PCI_COMM_MAE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcnp->pcn_regs, 0, 0,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (pcn_set_chipid(pcnp, (uint32_t)ssid << 16 | (uint32_t)svid) !=
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp->pcn_mii = mii_alloc(pcnp, dip, &pcn_mii_ops)) == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* XXX: need to set based on device */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King mii_set_pauseable(pcnp->pcn_mii, B_FALSE, B_FALSE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(dip, "unable to allocate DMA resources");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_add_intr(dip, 0, NULL, NULL, pcn_intr, (caddr_t)pcnp) !=
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mac_register(macp, &pcnp->pcn_mh) == DDI_SUCCESS) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip))) == NULL)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to resume chip");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if ((pcnp = ddi_get_soft_state(pcn_ssp, ddi_get_instance(dip))) == NULL)
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 (CSR_READ_4(pcnp, PCN_IO32_RDP) & ~(PCN_CSR_INTEN)) |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_remove_intr(pcnp->pcn_dip, 0, pcnp->pcn_icookie);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* These will exit gracefully if not yet allocated */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King ddi_soft_state_free(pcn_ssp, ddi_get_instance(pcnp->pcn_dip));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * Drains any FIFOs in the card, then pauses it
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_error(pcnp->pcn_dip, "Unable to suspend, EXTCTL1 was 0x%b", val,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * PCNet uses the upper 6 bits of the CRC of the macaddr
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * to index into a 64bit mask
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_MAR0 + index, newval);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* set promiscuous mode */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_CLRBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < 3; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* enable tx interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_LTINTEN);
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 if (bcmp(txb->pb_buf, pcn_broadcast, ETHERADDRL) != 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* PCNet wants the 2's complement of the length of the buffer */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King tmd->pcn_txctl |= PCN_TXCTL_STP | PCN_TXCTL_ENP | PCN_TXCTL_ADD_FCS |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txstall_time = gethrtime() + (5 * 1000000000ULL);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* sync before reading */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* check if chip is still working on it */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Disable TX interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic unsigned
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King while ((status = pcn_csr_read(pcnp, PCN_CSR_CSR)) & PCN_CSR_INTR) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* timer interrupt */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* ack it */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (rmd->pcn_rxstat & PCN_RXSTAT_LAFM|PCN_RXSTAT_BAM) {
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 /* Select 32-bit (DWIO) mode */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* The timer is not affected by a reset, so explicitly disable */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable fast suspend */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_csr_write(pcnp, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Select Style 3 descriptors */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Set MAC address */
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 * 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 /* Reenable auto negotiation for external phy */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_BCR_SETBIT(pcnp, PCN_BCR_MIICTL, PCN_MIICTL_XPHYANE);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_MODE, PCN_MODE_PROMISC);
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 /* We're not using the initialization block. */
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 PCN_BCR_SETBIT(pcnp, PCN_BCR_BUSCTL, PCN_BUSCTL_NOUFLOW |
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable graceful recovery from underflow. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_IMR, PCN_IMR_DXSUFLO);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Enable auto-padding of short TX frames. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_TFEAT, PCN_TFEAT_PAD_TX);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Start chip and enable interrupts */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_CSR_SETBIT(pcnp, PCN_CSR_CSR, PCN_CSR_START|PCN_CSR_INTEN);
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 PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SINTEN);
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 PCN_CSR_CLRBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SINTEN);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (mii_m_getstat(pcnp->pcn_mii, stat, val) == 0)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mii_m_getprop(pcnp->pcn_mii, name, num, sz, val));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King const void *val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King return (mii_m_setprop(pcnp->pcn_mii, name, num, sz, val));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
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 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 pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, phy << 5 | reg);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King val = pcn_bcr_read(pcnp, PCN_BCR_MIIDATA) & 0xFFFF;
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 Kingpcn_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_bcr_write(pcnp, PCN_BCR_MIIADDR, reg | (phy << 5));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingstatic const pcn_type_t *
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King bcopy(&addr[0], &pcnp->pcn_addr[0], sizeof (pcnp->pcn_addr));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_csr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason Kingpcn_bcr_write(pcn_t *pcnp, uint32_t reg, uint32_t val)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King uint16_t bufsz = ((~(PCN_BUFSZ) + 1) & PCN_RXLEN_BUFSZ) | PCN_RXLEN_MBO;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* reset rx descriptor values */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_RXRING * sizeof (pcn_rx_desc_t), DDI_DMA_SYNC_FORDEV);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* reset tx descriptor values */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King txd->pcn_txstat = txd->pcn_txctl = txd->pcn_uspace = 0;
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King PCN_TXRING * sizeof (pcn_tx_desc_t), DDI_DMA_SYNC_FORDEV);
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_TXADDR0, pcnp->pcn_txdesc_paddr & 0xFFFF);
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 if (ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
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 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 rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dma_attr, DDI_DMA_SLEEP,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
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 pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
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 pcn_error(pcnp->pcn_dip, "unable to bind DMA for tx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_txbufs = kmem_zalloc(PCN_TXRING * sizeof (pcn_buf_t *),
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King rval = ddi_dma_alloc_handle(pcnp->pcn_dip, &pcn_dmadesc_attr,
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "unable to allocate DMA handle for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
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 pcn_error(pcnp->pcn_dip, "unable to allocate DMA memory for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
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 pcn_error(pcnp->pcn_dip, "unable to bind DMA for rx "
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King "descriptors");
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcnp->pcn_rxbufs = kmem_zalloc(PCN_RXRING * sizeof (pcn_buf_t *),
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++) {
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_TXRING; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(pcnp->pcn_txbufs, PCN_TXRING * sizeof (pcn_buf_t *));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_unbind_handle(pcnp->pcn_txdesc_dmah);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King for (i = 0; i < PCN_RXRING; i++)
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King kmem_free(pcnp->pcn_rxbufs, PCN_RXRING * sizeof (pcn_buf_t *));
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King (void) ddi_dma_unbind_handle(pcnp->pcn_rxdesc_dmah);
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 * The solution is check using 16-bit operations first, and determine
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King * if 32-bit mode operations are supported.
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 chipid = pcn_bcr_read16(pcnp, PCN_BCR_PCISUBSYSID);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King chipid |= pcn_bcr_read16(pcnp, PCN_BCR_PCISUBVENID);
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 /* We're in 16-bit mode. */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King /* Set default value and override as needed */
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unknown chip id 0x%x", chipid);
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King if (ddi_prop_update_string(DDI_DEV_T_NONE, pcnp->pcn_dip, "chipid",
438b5f69eb4f998015cc0835f19f2f80663f2f53Jason King pcn_error(pcnp->pcn_dip, "Unable to set chipid property");