1959748cbddf37d4734c107dadfa449e076045e3gd * Solaris driver for ethernet cards based on the ADMtek Centaur
1959748cbddf37d4734c107dadfa449e076045e3gd * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
1959748cbddf37d4734c107dadfa449e076045e3gd * All rights reserved.
1959748cbddf37d4734c107dadfa449e076045e3gd * Redistribution and use in source and binary forms, with or without
1959748cbddf37d4734c107dadfa449e076045e3gd * modification, are permitted provided that the following conditions
1959748cbddf37d4734c107dadfa449e076045e3gd * are met:
1959748cbddf37d4734c107dadfa449e076045e3gd * 1. Redistributions of source code must retain the above copyright
1959748cbddf37d4734c107dadfa449e076045e3gd * notice, this list of conditions and the following disclaimer.
1959748cbddf37d4734c107dadfa449e076045e3gd * 2. Redistributions in binary form must reproduce the above copyright
1959748cbddf37d4734c107dadfa449e076045e3gd * notice, this list of conditions and the following disclaimer in the
1959748cbddf37d4734c107dadfa449e076045e3gd * documentation and/or other materials provided with the distribution.
1959748cbddf37d4734c107dadfa449e076045e3gd * 3. Neither the name of the author nor the names of any co-contributors
1959748cbddf37d4734c107dadfa449e076045e3gd * may be used to endorse or promote products derived from this software
1959748cbddf37d4734c107dadfa449e076045e3gd * without specific prior written permission.
1959748cbddf37d4734c107dadfa449e076045e3gd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
1959748cbddf37d4734c107dadfa449e076045e3gd * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1959748cbddf37d4734c107dadfa449e076045e3gd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1959748cbddf37d4734c107dadfa449e076045e3gd * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
1959748cbddf37d4734c107dadfa449e076045e3gd * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1959748cbddf37d4734c107dadfa449e076045e3gd * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1959748cbddf37d4734c107dadfa449e076045e3gd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1959748cbddf37d4734c107dadfa449e076045e3gd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1959748cbddf37d4734c107dadfa449e076045e3gd * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1959748cbddf37d4734c107dadfa449e076045e3gd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1959748cbddf37d4734c107dadfa449e076045e3gd * POSSIBILITY OF SUCH DAMAGE.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
96fb08b94cc33de779f46f36c30d77230f1a8c2fgd * Use is subject to license terms.
1959748cbddf37d4734c107dadfa449e076045e3gd * Driver globals.
1959748cbddf37d4734c107dadfa449e076045e3gd/* table of supported devices */
1959748cbddf37d4734c107dadfa449e076045e3gd * ADMtek Centaur and Comet
1959748cbddf37d4734c107dadfa449e076045e3gd * Accton just relabels other companies' controllers
1959748cbddf37d4734c107dadfa449e076045e3gd * Models listed here.
1959748cbddf37d4734c107dadfa449e076045e3gd { 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR },
1959748cbddf37d4734c107dadfa449e076045e3gd { 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR },
1959748cbddf37d4734c107dadfa449e076045e3gd { 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR },
1959748cbddf37d4734c107dadfa449e076045e3gd * Function prototypes
1959748cbddf37d4734c107dadfa449e076045e3gdstatic int afe_m_multicst(void *, boolean_t, const uint8_t *);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_m_ioctl(void *, queue_t *, mblk_t *);
1959748cbddf37d4734c107dadfa449e076045e3gdstatic int afe_m_start(void *);
1959748cbddf37d4734c107dadfa449e076045e3gdstatic void afe_m_stop(void *);
96fb08b94cc33de779f46f36c30d77230f1a8c2fgdstatic int afe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
96fb08b94cc33de779f46f36c30d77230f1a8c2fgdstatic int afe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
96fb08b94cc33de779f46f36c30d77230f1a8c2fgd const void *);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void afe_m_propinfo(void *, const char *, mac_prop_id_t,
1959748cbddf37d4734c107dadfa449e076045e3gdstatic void afe_readsrom(afe_t *, unsigned, unsigned, char *);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic uint16_t afe_miireadgeneral(afe_t *, uint8_t, uint8_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_miiwritegeneral(afe_t *, uint8_t, uint8_t, uint16_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic uint16_t afe_miireadcomet(afe_t *, uint8_t, uint8_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_miiwritecomet(afe_t *, uint8_t, uint8_t, uint16_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic uint16_t afe_mii_read(void *, uint8_t, uint8_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_mii_write(void *, uint8_t, uint8_t, uint16_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_mii_notify(void *, link_state_t);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amorestatic void afe_mii_reset(void *);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1959748cbddf37d4734c107dadfa449e076045e3gd * Stream information
1959748cbddf37d4734c107dadfa449e076045e3gdDDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach,
1959748cbddf37d4734c107dadfa449e076045e3gd * Module linkage information.
1959748cbddf37d4734c107dadfa449e076045e3gd * Device attributes.
1959748cbddf37d4734c107dadfa449e076045e3gd 0, /* dma_attr_addr_lo */
1959748cbddf37d4734c107dadfa449e076045e3gd 0 /* dma_attr_flags */
1959748cbddf37d4734c107dadfa449e076045e3gd * Tx buffers can be arbitrarily aligned. Additionally, they can
1959748cbddf37d4734c107dadfa449e076045e3gd * cross a page boundary, so we use the two buffer addresses of the
1959748cbddf37d4734c107dadfa449e076045e3gd * chip to provide a two-entry scatter-gather list.
1959748cbddf37d4734c107dadfa449e076045e3gd 0, /* dma_attr_addr_lo */
1959748cbddf37d4734c107dadfa449e076045e3gd 0 /* dma_attr_flags */
1959748cbddf37d4734c107dadfa449e076045e3gd * Ethernet addresses.
1959748cbddf37d4734c107dadfa449e076045e3gd * DDI entry points.
1959748cbddf37d4734c107dadfa449e076045e3gd if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) {
1959748cbddf37d4734c107dadfa449e076045e3gd return (rv);
1959748cbddf37d4734c107dadfa449e076045e3gd return (rv);
1959748cbddf37d4734c107dadfa449e076045e3gd switch (cmd) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* this card is a bus master, reject any slave-only slot */
1959748cbddf37d4734c107dadfa449e076045e3gd /* PCI devices shouldn't generate hilevel interrupts */
1959748cbddf37d4734c107dadfa449e076045e3gd * Note: ADMtek boards seem to misprogram themselves with bogus
1959748cbddf37d4734c107dadfa449e076045e3gd * timings, which do not seem to work properly on SPARC. We
1959748cbddf37d4734c107dadfa449e076045e3gd * reprogram them zero (but only if they appear to be broken),
1959748cbddf37d4734c107dadfa449e076045e3gd * which seems to at least work. Its unclear that this is a
1959748cbddf37d4734c107dadfa449e076045e3gd * legal or wise practice to me, but it certainly works better
1959748cbddf37d4734c107dadfa449e076045e3gd * than the original values. (I would love to hear
1959748cbddf37d4734c107dadfa449e076045e3gd * suggestions for better values, or a better strategy.)
1959748cbddf37d4734c107dadfa449e076045e3gd * the last entry in the card table matches every possible
1959748cbddf37d4734c107dadfa449e076045e3gd * card, so the for-loop always terminates properly.
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd * Grab the PCI cachesize -- we use this to program the
1959748cbddf37d4734c107dadfa449e076045e3gd * cache-optimization bus access bits.
1959748cbddf37d4734c107dadfa449e076045e3gd /* this cannot fail */
1959748cbddf37d4734c107dadfa449e076045e3gd /* get the interrupt block cookie */
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) {
1959748cbddf37d4734c107dadfa449e076045e3gd afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
1959748cbddf37d4734c107dadfa449e076045e3gd "fiber", 0);
1959748cbddf37d4734c107dadfa449e076045e3gd mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
1959748cbddf37d4734c107dadfa449e076045e3gd mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
1959748cbddf37d4734c107dadfa449e076045e3gd * Enable bus master, IO space, and memory space accesses.
1959748cbddf37d4734c107dadfa449e076045e3gd pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE);
1959748cbddf37d4734c107dadfa449e076045e3gd /* we're done with this now, drop it */
1959748cbddf37d4734c107dadfa449e076045e3gd * Initialize interrupt kstat. This should not normally fail, since
1959748cbddf37d4734c107dadfa449e076045e3gd * we don't use a persistent stat. We do it this way to avoid having
1959748cbddf37d4734c107dadfa449e076045e3gd * to test for it at run time on the hot path.
1959748cbddf37d4734c107dadfa449e076045e3gd afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller",
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * Set up the MII.
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if ((afep->afe_mii = mii_alloc(afep, dip, &afe_mii_ops)) == NULL) {
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * Centaur can support PAUSE, but Comet can't.
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore mii_set_pauseable(afep->afe_mii, B_TRUE, B_FALSE);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore mii_set_pauseable(afep->afe_mii, B_FALSE, B_FALSE);
1959748cbddf37d4734c107dadfa449e076045e3gd * Map in the device registers.
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs,
1959748cbddf37d4734c107dadfa449e076045e3gd * Allocate DMA resources (descriptor rings and buffers).
1959748cbddf37d4734c107dadfa449e076045e3gd /* Initialize the chip. */
1959748cbddf37d4734c107dadfa449e076045e3gd /* Determine the number of address bits to our EEPROM. */
1959748cbddf37d4734c107dadfa449e076045e3gd * Get the factory ethernet address. This becomes the current
1959748cbddf37d4734c107dadfa449e076045e3gd * ethernet address (it can be overridden later via ifconfig).
1959748cbddf37d4734c107dadfa449e076045e3gd /* make sure we add configure the initial filter */
1959748cbddf37d4734c107dadfa449e076045e3gd * Establish interrupt handler.
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) !=
1959748cbddf37d4734c107dadfa449e076045e3gd /* TODO: do the power management stuff */
1959748cbddf37d4734c107dadfa449e076045e3gd /* failed to register with MAC */
1959748cbddf37d4734c107dadfa449e076045e3gd switch (cmd) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* make sure hardware is quiesced */
1959748cbddf37d4734c107dadfa449e076045e3gd /* clean up and shut down device */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* clean up MII layer */
1959748cbddf37d4734c107dadfa449e076045e3gd /* clean up kstats */
1959748cbddf37d4734c107dadfa449e076045e3gd /* free up any left over buffers or DMA resources */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* stop MII monitoring */
1959748cbddf37d4734c107dadfa449e076045e3gd /* quiesce the hardware */
1959748cbddf37d4734c107dadfa449e076045e3gd /* re-initialize chip */
1959748cbddf37d4734c107dadfa449e076045e3gd /* start the chip */
1959748cbddf37d4734c107dadfa449e076045e3gd /* drop locks */
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore if ((afep = ddi_get_driver_private(dip)) == NULL) {
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore * At 66 MHz it is 16 nsec per access or more (always more)
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore * So we need 3,333 times to retry for 50 usec. We just
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore * round up to 5000 times. Unless the hardware is horked,
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore * it will always terminate *well* before that anyway.
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore for (int i = 0; i < 5000; i++) {
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore if ((GETCSR(afep, CSR_PAR) & PAR_RESET) == 0) {
38415b019e7f06a9abdc4c863acc6ee8263c68a1Garrett D'Amore /* hardware didn't quiesce - force a full reboot (PCI reset) */
1959748cbddf37d4734c107dadfa449e076045e3gd /* don't touch a suspended interface */
1959748cbddf37d4734c107dadfa449e076045e3gd /* stop receiver */
1959748cbddf37d4734c107dadfa449e076045e3gd /* program promiscuous mode */
1959748cbddf37d4734c107dadfa449e076045e3gd /* program mac address */
1959748cbddf37d4734c107dadfa449e076045e3gd pa0 = (afep->afe_curraddr[3] << 24) | (afep->afe_curraddr[2] << 16) |
1959748cbddf37d4734c107dadfa449e076045e3gd pa1 = (afep->afe_curraddr[5] << 8) | afep->afe_curraddr[4];
1959748cbddf37d4734c107dadfa449e076045e3gd /* program multicast filter */
1959748cbddf37d4734c107dadfa449e076045e3gd /* restart receiver */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore afe_error(afep->afe_dip, "TX stall detected!");
1959748cbddf37d4734c107dadfa449e076045e3gdafe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
1959748cbddf37d4734c107dadfa449e076045e3gd /* bit within a 32-bit word */
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
1959748cbddf37d4734c107dadfa449e076045e3gd /* exclusive access to the card while we reprogram it */
1959748cbddf37d4734c107dadfa449e076045e3gd /* save current promiscuous mode state for replay in resume */
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
1959748cbddf37d4734c107dadfa449e076045e3gd /* exclusive access to the card while we reprogram it */
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
1959748cbddf37d4734c107dadfa449e076045e3gd return (mp);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if (mii_m_loop_ioctl(afep->afe_mii, wq, mp))
1959748cbddf37d4734c107dadfa449e076045e3gd * Hardware management.
1959748cbddf37d4734c107dadfa449e076045e3gd if (i == 10) {
1959748cbddf37d4734c107dadfa449e076045e3gd afe_error(afep->afe_dip, "timed out waiting for reset!");
1959748cbddf37d4734c107dadfa449e076045e3gd * Updated Centaur data sheets show that the Comet and Centaur are
1959748cbddf37d4734c107dadfa449e076045e3gd * alike here (contrary to earlier versions of the data sheet).
1959748cbddf37d4734c107dadfa449e076045e3gd /* XXX:? chip problems */
1959748cbddf37d4734c107dadfa449e076045e3gd /* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */
1959748cbddf37d4734c107dadfa449e076045e3gd /* enable transmit underrun auto-recovery */
1959748cbddf37d4734c107dadfa449e076045e3gd /* clear the lost packet counter (cleared on read) */
1959748cbddf37d4734c107dadfa449e076045e3gd * Serial EEPROM access - inspired by the FreeBSD implementation.
1959748cbddf37d4734c107dadfa449e076045e3gd /* command bits first */
1959748cbddf37d4734c107dadfa449e076045e3gd /* turn off accesses to the EEPROM */
1959748cbddf37d4734c107dadfa449e076045e3gd * The words in EEPROM are stored in little endian order. We
1959748cbddf37d4734c107dadfa449e076045e3gd * shift bits out in big endian order, though. This requires
1959748cbddf37d4734c107dadfa449e076045e3gd * a byte swap on some platforms.
1959748cbddf37d4734c107dadfa449e076045e3gd /* too big to fit! */
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
1959748cbddf37d4734c107dadfa449e076045e3gd /* command and address bits */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < 16; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* turn off accesses to the EEPROM */
1959748cbddf37d4734c107dadfa449e076045e3gd * Fix up the endianness thing. Note that the values
1959748cbddf37d4734c107dadfa449e076045e3gd * are stored in little endian format on the SROM.
1959748cbddf37d4734c107dadfa449e076045e3gdafe_readsrom(afe_t *afep, unsigned romaddr, unsigned len, char *dest)
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < len; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd afe_readsrom(afep, SROM_ENADDR, ETHERADDRL / 2, (char *)eaddr);
1959748cbddf37d4734c107dadfa449e076045e3gd * MII management.
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * Its entirely possible that this belongs as a PHY specific
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if ((mii_get_id(afep->afe_mii) & 0xfffffff0) != 0x225410) {
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* if its not an AN983B, we don't care */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* UTP Port */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* Fiber Port */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * work around for errata 983B_0416 -- duplex light flashes
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * in 10 HDX. we just disable SQE testing on the device.
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore pilr = afe_mii_read(afep, phyaddr, PHY_PILR);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore afe_mii_write(afep, phyaddr, PHY_PILR, pilr);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if (mii_get_flowctrl(afep->afe_mii) == LINK_FLOWCTRL_BI) {
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_mii_read(void *arg, uint8_t phy, uint8_t reg)
1959748cbddf37d4734c107dadfa449e076045e3gd * ADMtek bugs ignore address decode bits -- they only
1959748cbddf37d4734c107dadfa449e076045e3gd * support PHY at 1.
1959748cbddf37d4734c107dadfa449e076045e3gd return (0xffff);
1959748cbddf37d4734c107dadfa449e076045e3gd return (0xffff);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_miireadgeneral(afe_t *afep, uint8_t phy, uint8_t reg)
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the 32 bit preamble */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < 32; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the start code - 01b */
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the opcode for read, - 10b */
1959748cbddf37d4734c107dadfa449e076045e3gd /* next we send the 5 bit phy address */
1959748cbddf37d4734c107dadfa449e076045e3gd /* the 5 bit register address goes next */
1959748cbddf37d4734c107dadfa449e076045e3gd /* turnaround - tristate followed by logic 0 */
1959748cbddf37d4734c107dadfa449e076045e3gd /* read the 16 bit register value */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_miireadcomet(afe_t *afep, uint8_t phy, uint8_t reg)
1959748cbddf37d4734c107dadfa449e076045e3gd return (0xffff);
1959748cbddf37d4734c107dadfa449e076045e3gd switch (reg) {
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
1959748cbddf37d4734c107dadfa449e076045e3gd * ADMtek bugs ignore address decode bits -- they only
1959748cbddf37d4734c107dadfa449e076045e3gd * support PHY at 1.
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_miiwritegeneral(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val)
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the 32 bit preamble */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < 32; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the start code - 01b */
1959748cbddf37d4734c107dadfa449e076045e3gd /* send the opcode for write, - 01b */
1959748cbddf37d4734c107dadfa449e076045e3gd /* next we send the 5 bit phy address */
1959748cbddf37d4734c107dadfa449e076045e3gd /* the 5 bit register address goes next */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* turnaround - 1 bit followed by logic 0 */
1959748cbddf37d4734c107dadfa449e076045e3gd /* now write out our data (16 bits) */
1959748cbddf37d4734c107dadfa449e076045e3gd /* idle mode */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amoreafe_miiwritecomet(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val)
1959748cbddf37d4734c107dadfa449e076045e3gd switch (reg) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* grab exclusive access to the card */
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
1959748cbddf37d4734c107dadfa449e076045e3gd /* exclusive access to the hardware! */
1959748cbddf37d4734c107dadfa449e076045e3gd /* verify exclusive access to the card */
1959748cbddf37d4734c107dadfa449e076045e3gd /* start the card */
1959748cbddf37d4734c107dadfa449e076045e3gd /* tell the mac that we are ready to go! */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* start watchdog timer */
1959748cbddf37d4734c107dadfa449e076045e3gd /* exclusive access to the hardware! */
1959748cbddf37d4734c107dadfa449e076045e3gd * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
1959748cbddf37d4734c107dadfa449e076045e3gd * We just add up to the nearest msec (2), which should be
1959748cbddf37d4734c107dadfa449e076045e3gd * plenty to complete.
1959748cbddf37d4734c107dadfa449e076045e3gd * Note that some chips never seem to indicate the transition to
1959748cbddf37d4734c107dadfa449e076045e3gd * the stopped state properly. Experience shows that we can safely
1959748cbddf37d4734c107dadfa449e076045e3gd * proceed anyway, after waiting the requisite timeout.
1959748cbddf37d4734c107dadfa449e076045e3gd if ((GETCSR(afep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
1959748cbddf37d4734c107dadfa449e076045e3gd /* prevent an interrupt */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore /* stop the watchdog timer */
1959748cbddf37d4734c107dadfa449e076045e3gd /* now we need to reset the pointers... */
1959748cbddf37d4734c107dadfa449e076045e3gd /* reset the descriptor ring pointers */
1959748cbddf37d4734c107dadfa449e076045e3gd /* set up transmit descriptor ring */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_TXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* make the receive buffers available */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_RXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* make sure interrupts are disabled to begin */
1959748cbddf37d4734c107dadfa449e076045e3gd /* initialize the chip */
1959748cbddf37d4734c107dadfa449e076045e3gd /* now we can enable interrupts */
1959748cbddf37d4734c107dadfa449e076045e3gd /* start up the mac */
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_dma_mem_alloc(txb->txb_dmah, AFE_BUFSZ, &afe_bufattr,
1959748cbddf37d4734c107dadfa449e076045e3gd DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, &len,
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
1959748cbddf37d4734c107dadfa449e076045e3gd len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_dma_mem_alloc(rxb->rxb_dmah, AFE_BUFSZ, &afe_bufattr,
1959748cbddf37d4734c107dadfa449e076045e3gd DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &rxb->rxb_buf, &len,
1959748cbddf37d4734c107dadfa449e076045e3gd if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
1959748cbddf37d4734c107dadfa449e076045e3gd DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
1959748cbddf37d4734c107dadfa449e076045e3gd * Allocate receive resources.
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to allocate DMA handle for rx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_mem_alloc(afep->afe_rxdesc_dmah, size, &afe_devattr,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to allocate DMA memory for rx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_addr_bind_handle(afep->afe_rxdesc_dmah, NULL, kaddr,
1959748cbddf37d4734c107dadfa449e076045e3gd size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to bind DMA for rx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd /* because of afe_dma_attr */
1959748cbddf37d4734c107dadfa449e076045e3gd /* we take the 32-bit physical address out of the cookie */
1959748cbddf37d4734c107dadfa449e076045e3gd /* allocate buffer pointers (not the buffers themselves, yet) */
1959748cbddf37d4734c107dadfa449e076045e3gd afep->afe_rxbufs = kmem_zalloc(AFE_RXRING * sizeof (afe_rxbuf_t *),
1959748cbddf37d4734c107dadfa449e076045e3gd /* now allocate rx buffers */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_RXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd * Allocate transmit resources.
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to allocate DMA handle for tx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_mem_alloc(afep->afe_txdesc_dmah, size, &afe_devattr,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to allocate DMA memory for tx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd rval = ddi_dma_addr_bind_handle(afep->afe_txdesc_dmah, NULL, kaddr,
1959748cbddf37d4734c107dadfa449e076045e3gd size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
1959748cbddf37d4734c107dadfa449e076045e3gd "unable to bind DMA for tx descriptors");
1959748cbddf37d4734c107dadfa449e076045e3gd /* because of afe_dma_attr */
1959748cbddf37d4734c107dadfa449e076045e3gd /* we take the 32-bit physical address out of the cookie */
1959748cbddf37d4734c107dadfa449e076045e3gd /* allocate buffer pointers (not the buffers themselves, yet) */
1959748cbddf37d4734c107dadfa449e076045e3gd afep->afe_txbufs = kmem_zalloc(AFE_TXRING * sizeof (afe_txbuf_t *),
1959748cbddf37d4734c107dadfa449e076045e3gd /* now allocate tx buffers */
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_TXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_RXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd for (i = 0; i < AFE_TXRING; i++) {
1959748cbddf37d4734c107dadfa449e076045e3gd * Interrupt service routine.
1959748cbddf37d4734c107dadfa449e076045e3gd /* we cannot receive interrupts! */
1959748cbddf37d4734c107dadfa449e076045e3gd /* check interrupt status bits, did we interrupt? */
1959748cbddf37d4734c107dadfa449e076045e3gd if (status == 0) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* ack the interrupt */
1959748cbddf37d4734c107dadfa449e076045e3gd /* not running, don't touch anything */
1959748cbddf37d4734c107dadfa449e076045e3gd /* receive packets */
1959748cbddf37d4734c107dadfa449e076045e3gd /* transmit completed */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if ((status & INT_TIMER) && (afe_watchdog(afep) != DDI_SUCCESS)) {
1959748cbddf37d4734c107dadfa449e076045e3gd /* reset the chip in an attempt to fix things */
1959748cbddf37d4734c107dadfa449e076045e3gd * Send up packets. We do this outside of the intrlock.
1959748cbddf37d4734c107dadfa449e076045e3gd * On the Comet, this is the internal transceiver
1959748cbddf37d4734c107dadfa449e076045e3gd * interrupt. We program the Comet's built-in PHY to
1959748cbddf37d4734c107dadfa449e076045e3gd * enable certain interrupts.
1959748cbddf37d4734c107dadfa449e076045e3gd /* disable further interrupts */
1959748cbddf37d4734c107dadfa449e076045e3gd /* clear any pending interrupts */
1959748cbddf37d4734c107dadfa449e076045e3gd /* no more tmds */
1959748cbddf37d4734c107dadfa449e076045e3gd /* enable TX interrupt */
1959748cbddf37d4734c107dadfa449e076045e3gd * For simplicity, we just do a copy into a preallocated
1959748cbddf37d4734c107dadfa449e076045e3gd * DMA buffer.
1959748cbddf37d4734c107dadfa449e076045e3gd * Statistics.
1959748cbddf37d4734c107dadfa449e076045e3gd /* note len is already known to be a small unsigned */
1959748cbddf37d4734c107dadfa449e076045e3gd control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
1959748cbddf37d4734c107dadfa449e076045e3gd /* sync the descriptor out to the device */
1959748cbddf37d4734c107dadfa449e076045e3gd * Note the new values of txavail and txsend.
1959748cbddf37d4734c107dadfa449e076045e3gd * It should never, ever take more than 5 seconds to drain
1959748cbddf37d4734c107dadfa449e076045e3gd * the ring. If it happens, then we are stuck!
1959748cbddf37d4734c107dadfa449e076045e3gd afep->afe_txstall_time = gethrtime() + (5 * 1000000000ULL);
1959748cbddf37d4734c107dadfa449e076045e3gd * wake up the chip ... inside the lock to protect against DR suspend,
1959748cbddf37d4734c107dadfa449e076045e3gd * Reclaim buffers that have completed transmission.
1959748cbddf37d4734c107dadfa449e076045e3gd /* sync it before we read it */
1959748cbddf37d4734c107dadfa449e076045e3gd /* chip is still working on it, we're done */
1959748cbddf37d4734c107dadfa449e076045e3gd /* in the most common successful case, all bits are clear */
1959748cbddf37d4734c107dadfa449e076045e3gd /* transmit jabber timeout */
1959748cbddf37d4734c107dadfa449e076045e3gd /* collision counting */
1959748cbddf37d4734c107dadfa449e076045e3gd * we were able to reclaim some packets, so
1959748cbddf37d4734c107dadfa449e076045e3gd * disable tx interrupts
1959748cbddf37d4734c107dadfa449e076045e3gd /* limit the number of packets we process to a half ring size */
1959748cbddf37d4734c107dadfa449e076045e3gd /* chip is still chewing on it */
1959748cbddf37d4734c107dadfa449e076045e3gd /* discard the ethernet frame checksum */
1959748cbddf37d4734c107dadfa449e076045e3gd if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
1959748cbddf37d4734c107dadfa449e076045e3gd * Abnormal status bits detected, analyze further.
1959748cbddf37d4734c107dadfa449e076045e3gd /* this should really be rx_late_collisions */
1959748cbddf37d4734c107dadfa449e076045e3gd * At this point, the chip thinks the packet is OK.
1959748cbddf37d4734c107dadfa449e076045e3gd /* sync the buffer before we look at it */
1959748cbddf37d4734c107dadfa449e076045e3gd /* return ring entry to the hardware */
1959748cbddf37d4734c107dadfa449e076045e3gd /* advance to next RMD */
1959748cbddf37d4734c107dadfa449e076045e3gd if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == AFE_RUNNING)
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if (mii_m_getstat(afep->afe_mii, stat, val) == 0) {
1959748cbddf37d4734c107dadfa449e076045e3gd switch (stat) {
1959748cbddf37d4734c107dadfa449e076045e3gd return (0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerafe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (mii_m_getprop(afep->afe_mii, name, num, sz, val));
96fb08b94cc33de779f46f36c30d77230f1a8c2fgdafe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
96fb08b94cc33de779f46f36c30d77230f1a8c2fgd const void *val)
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore return (mii_m_setprop(afep->afe_mii, name, num, sz, val));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerafe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mii_m_propinfo(afep->afe_mii, name, num, prh);
1959748cbddf37d4734c107dadfa449e076045e3gd * Debugging and error reporting.