14978Sgd78059 /*
24978Sgd78059 * Solaris driver for ethernet cards based on the Macronix 98715
34978Sgd78059 *
44978Sgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
54978Sgd78059 * All rights reserved.
64978Sgd78059 *
74978Sgd78059 * Redistribution and use in source and binary forms, with or without
84978Sgd78059 * modification, are permitted provided that the following conditions
94978Sgd78059 * are met:
104978Sgd78059 * 1. Redistributions of source code must retain the above copyright
114978Sgd78059 * notice, this list of conditions and the following disclaimer.
124978Sgd78059 * 2. Redistributions in binary form must reproduce the above copyright
134978Sgd78059 * notice, this list of conditions and the following disclaimer in the
144978Sgd78059 * documentation and/or other materials provided with the distribution.
154978Sgd78059 * 3. Neither the name of the author nor the names of any co-contributors
164978Sgd78059 * may be used to endorse or promote products derived from this software
174978Sgd78059 * without specific prior written permission.
184978Sgd78059 *
194978Sgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
204978Sgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214978Sgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224978Sgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
234978Sgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244978Sgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254978Sgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264978Sgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274978Sgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284978Sgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294978Sgd78059 * POSSIBILITY OF SUCH DAMAGE.
304978Sgd78059 */
316684Sgd78059 /*
32*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
336684Sgd78059 * Use is subject to license terms.
346684Sgd78059 */
354978Sgd78059
364978Sgd78059
374978Sgd78059 #include <sys/varargs.h>
384978Sgd78059 #include <sys/types.h>
394978Sgd78059 #include <sys/modctl.h>
404978Sgd78059 #include <sys/conf.h>
414978Sgd78059 #include <sys/devops.h>
424978Sgd78059 #include <sys/stream.h>
434978Sgd78059 #include <sys/strsun.h>
444978Sgd78059 #include <sys/cmn_err.h>
454978Sgd78059 #include <sys/dlpi.h>
464978Sgd78059 #include <sys/ethernet.h>
474978Sgd78059 #include <sys/kmem.h>
484978Sgd78059 #include <sys/time.h>
494978Sgd78059 #include <sys/miiregs.h>
504978Sgd78059 #include <sys/strsun.h>
514978Sgd78059 #include <sys/mac.h>
524978Sgd78059 #include <sys/mac_ether.h>
534978Sgd78059 #include <sys/ddi.h>
544978Sgd78059 #include <sys/sunddi.h>
555895Syz147064 #include <sys/vlan.h>
564978Sgd78059
574978Sgd78059 #include "mxfe.h"
584978Sgd78059 #include "mxfeimpl.h"
594978Sgd78059
604978Sgd78059 /*
614978Sgd78059 * Driver globals.
624978Sgd78059 */
634978Sgd78059
644978Sgd78059 /* patchable debug flag ... must not be static! */
654978Sgd78059 #ifdef DEBUG
664978Sgd78059 unsigned mxfe_debug = DWARN;
674978Sgd78059 #endif
684978Sgd78059
694978Sgd78059 /* table of supported devices */
704978Sgd78059 static mxfe_card_t mxfe_cards[] = {
714978Sgd78059
724978Sgd78059 /*
734978Sgd78059 * Lite-On products
744978Sgd78059 */
754978Sgd78059 { 0x11ad, 0xc115, 0, 0, "Lite-On LC82C115", MXFE_PNICII },
764978Sgd78059
774978Sgd78059 /*
784978Sgd78059 * Macronix chips
794978Sgd78059 */
804978Sgd78059 { 0x10d9, 0x0531, 0x25, 0xff, "Macronix MX98715AEC", MXFE_98715AEC },
814978Sgd78059 { 0x10d9, 0x0531, 0x20, 0xff, "Macronix MX98715A", MXFE_98715A },
824978Sgd78059 { 0x10d9, 0x0531, 0x60, 0xff, "Macronix MX98715B", MXFE_98715B },
834978Sgd78059 { 0x10d9, 0x0531, 0x30, 0xff, "Macronix MX98725", MXFE_98725 },
844978Sgd78059 { 0x10d9, 0x0531, 0x00, 0xff, "Macronix MX98715", MXFE_98715 },
854978Sgd78059 { 0x10d9, 0x0512, 0, 0, "Macronix MX98713", MXFE_98713 },
864978Sgd78059
874978Sgd78059 /*
884978Sgd78059 * Compex (relabeled Macronix products)
894978Sgd78059 */
904978Sgd78059 { 0x11fc, 0x9881, 0x00, 0x00, "Compex 9881", MXFE_98713 },
914978Sgd78059 { 0x11fc, 0x9881, 0x10, 0xff, "Compex 9881A", MXFE_98713A },
924978Sgd78059 /*
934978Sgd78059 * Models listed here
944978Sgd78059 */
954978Sgd78059 { 0x11ad, 0xc001, 0, 0, "Linksys LNE100TX", MXFE_PNICII },
964978Sgd78059 { 0x2646, 0x000b, 0, 0, "Kingston KNE111TX", MXFE_PNICII },
974978Sgd78059 { 0x1154, 0x0308, 0, 0, "Buffalo LGY-PCI-TXL", MXFE_98715AEC },
984978Sgd78059 };
994978Sgd78059
1004978Sgd78059 #define ETHERVLANMTU (ETHERMAX + 4)
1014978Sgd78059
1024978Sgd78059 /*
1034978Sgd78059 * Function prototypes
1044978Sgd78059 */
1054978Sgd78059 static int mxfe_attach(dev_info_t *, ddi_attach_cmd_t);
1064978Sgd78059 static int mxfe_detach(dev_info_t *, ddi_detach_cmd_t);
1074978Sgd78059 static int mxfe_resume(dev_info_t *);
1089199Sgdamore@opensolaris.org static int mxfe_quiesce(dev_info_t *);
1094978Sgd78059 static int mxfe_m_unicst(void *, const uint8_t *);
1104978Sgd78059 static int mxfe_m_multicst(void *, boolean_t, const uint8_t *);
1114978Sgd78059 static int mxfe_m_promisc(void *, boolean_t);
1124978Sgd78059 static mblk_t *mxfe_m_tx(void *, mblk_t *);
1134978Sgd78059 static int mxfe_m_stat(void *, uint_t, uint64_t *);
1144978Sgd78059 static int mxfe_m_start(void *);
1154978Sgd78059 static void mxfe_m_stop(void *);
1166684Sgd78059 static int mxfe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
117*11878SVenu.Iyer@Sun.COM void *);
1186684Sgd78059 static int mxfe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
1196684Sgd78059 const void *);
120*11878SVenu.Iyer@Sun.COM static void mxfe_m_propinfo(void *, const char *, mac_prop_id_t,
121*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t);
1224978Sgd78059 static unsigned mxfe_intr(caddr_t);
1234978Sgd78059 static void mxfe_startmac(mxfe_t *);
1244978Sgd78059 static void mxfe_stopmac(mxfe_t *);
1254978Sgd78059 static void mxfe_resetrings(mxfe_t *);
1264978Sgd78059 static boolean_t mxfe_initialize(mxfe_t *);
1274978Sgd78059 static void mxfe_startall(mxfe_t *);
1284978Sgd78059 static void mxfe_stopall(mxfe_t *);
1294978Sgd78059 static void mxfe_resetall(mxfe_t *);
1304978Sgd78059 static mxfe_txbuf_t *mxfe_alloctxbuf(mxfe_t *);
1314978Sgd78059 static void mxfe_destroytxbuf(mxfe_txbuf_t *);
1324978Sgd78059 static mxfe_rxbuf_t *mxfe_allocrxbuf(mxfe_t *);
1334978Sgd78059 static void mxfe_destroyrxbuf(mxfe_rxbuf_t *);
1344978Sgd78059 static void mxfe_send_setup(mxfe_t *);
1354978Sgd78059 static boolean_t mxfe_send(mxfe_t *, mblk_t *);
1364978Sgd78059 static int mxfe_allocrxring(mxfe_t *);
1374978Sgd78059 static void mxfe_freerxring(mxfe_t *);
1384978Sgd78059 static int mxfe_alloctxring(mxfe_t *);
1394978Sgd78059 static void mxfe_freetxring(mxfe_t *);
1404978Sgd78059 static void mxfe_error(dev_info_t *, char *, ...);
1414978Sgd78059 static uint8_t mxfe_sromwidth(mxfe_t *);
1424978Sgd78059 static uint16_t mxfe_readsromword(mxfe_t *, unsigned);
1434978Sgd78059 static void mxfe_readsrom(mxfe_t *, unsigned, unsigned, void *);
1444978Sgd78059 static void mxfe_getfactaddr(mxfe_t *, uchar_t *);
1456684Sgd78059 static uint8_t mxfe_miireadbit(mxfe_t *);
1466684Sgd78059 static void mxfe_miiwritebit(mxfe_t *, uint8_t);
1474978Sgd78059 static void mxfe_miitristate(mxfe_t *);
1486684Sgd78059 static uint16_t mxfe_miiread(mxfe_t *, int, int);
1494978Sgd78059 static void mxfe_miiwrite(mxfe_t *, int, int, uint16_t);
1506684Sgd78059 static uint16_t mxfe_miireadgeneral(mxfe_t *, int, int);
1514978Sgd78059 static void mxfe_miiwritegeneral(mxfe_t *, int, int, uint16_t);
1526684Sgd78059 static uint16_t mxfe_miiread98713(mxfe_t *, int, int);
1534978Sgd78059 static void mxfe_miiwrite98713(mxfe_t *, int, int, uint16_t);
1544978Sgd78059 static void mxfe_startphy(mxfe_t *);
1554978Sgd78059 static void mxfe_stopphy(mxfe_t *);
1564978Sgd78059 static void mxfe_startphymii(mxfe_t *);
1574978Sgd78059 static void mxfe_startphynway(mxfe_t *);
1584978Sgd78059 static void mxfe_startnway(mxfe_t *);
1594978Sgd78059 static void mxfe_reportlink(mxfe_t *);
1604978Sgd78059 static void mxfe_checklink(mxfe_t *);
1614978Sgd78059 static void mxfe_checklinkmii(mxfe_t *);
1624978Sgd78059 static void mxfe_checklinknway(mxfe_t *);
1634978Sgd78059 static void mxfe_disableinterrupts(mxfe_t *);
1644978Sgd78059 static void mxfe_enableinterrupts(mxfe_t *);
1654978Sgd78059 static void mxfe_reclaim(mxfe_t *);
1669199Sgdamore@opensolaris.org static boolean_t mxfe_receive(mxfe_t *, mblk_t **);
1674978Sgd78059
1684978Sgd78059 #ifdef DEBUG
1694978Sgd78059 static void mxfe_dprintf(mxfe_t *, const char *, int, char *, ...);
1704978Sgd78059 #endif
1714978Sgd78059
1724978Sgd78059 #define KIOIP KSTAT_INTR_PTR(mxfep->mxfe_intrstat)
1734978Sgd78059
1744978Sgd78059 static mac_callbacks_t mxfe_m_callbacks = {
175*11878SVenu.Iyer@Sun.COM MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1764978Sgd78059 mxfe_m_stat,
1774978Sgd78059 mxfe_m_start,
1784978Sgd78059 mxfe_m_stop,
1794978Sgd78059 mxfe_m_promisc,
1804978Sgd78059 mxfe_m_multicst,
1814978Sgd78059 mxfe_m_unicst,
1824978Sgd78059 mxfe_m_tx,
183*11878SVenu.Iyer@Sun.COM NULL,
1846684Sgd78059 NULL, /* mc_ioctl */
1856684Sgd78059 NULL, /* mc_getcapab */
1866684Sgd78059 NULL, /* mc_open */
1876684Sgd78059 NULL, /* mc_close */
1886684Sgd78059 mxfe_m_setprop,
189*11878SVenu.Iyer@Sun.COM mxfe_m_getprop,
190*11878SVenu.Iyer@Sun.COM mxfe_m_propinfo
1914978Sgd78059 };
1924978Sgd78059
1934978Sgd78059 /*
1944978Sgd78059 * Stream information
1954978Sgd78059 */
1964978Sgd78059 DDI_DEFINE_STREAM_OPS(mxfe_devops, nulldev, nulldev, mxfe_attach, mxfe_detach,
1979199Sgdamore@opensolaris.org nodev, NULL, D_MP, NULL, mxfe_quiesce);
1984978Sgd78059
1994978Sgd78059 /*
2004978Sgd78059 * Module linkage information.
2014978Sgd78059 */
2024978Sgd78059
2034978Sgd78059 static struct modldrv mxfe_modldrv = {
2044978Sgd78059 &mod_driverops, /* drv_modops */
2054978Sgd78059 "Macronix Fast Ethernet", /* drv_linkinfo */
2064978Sgd78059 &mxfe_devops /* drv_dev_ops */
2074978Sgd78059 };
2084978Sgd78059
2094978Sgd78059 static struct modlinkage mxfe_modlinkage = {
2104978Sgd78059 MODREV_1, /* ml_rev */
2114978Sgd78059 { &mxfe_modldrv, NULL } /* ml_linkage */
2124978Sgd78059 };
2134978Sgd78059
2144978Sgd78059 /*
2154978Sgd78059 * Device attributes.
2164978Sgd78059 */
2174978Sgd78059 static ddi_device_acc_attr_t mxfe_devattr = {
2184978Sgd78059 DDI_DEVICE_ATTR_V0,
2194978Sgd78059 DDI_STRUCTURE_LE_ACC,
2204978Sgd78059 DDI_STRICTORDER_ACC
2214978Sgd78059 };
2224978Sgd78059
2234978Sgd78059 static ddi_device_acc_attr_t mxfe_bufattr = {
2244978Sgd78059 DDI_DEVICE_ATTR_V0,
2254978Sgd78059 DDI_NEVERSWAP_ACC,
2264978Sgd78059 DDI_STRICTORDER_ACC
2274978Sgd78059 };
2284978Sgd78059
2294978Sgd78059 static ddi_dma_attr_t mxfe_dma_attr = {
2304978Sgd78059 DMA_ATTR_V0, /* dma_attr_version */
2314978Sgd78059 0, /* dma_attr_addr_lo */
2324978Sgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */
2334978Sgd78059 0x7FFFFFFFU, /* dma_attr_count_max */
2344978Sgd78059 4, /* dma_attr_align */
2354978Sgd78059 0x3F, /* dma_attr_burstsizes */
2364978Sgd78059 1, /* dma_attr_minxfer */
2374978Sgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */
2384978Sgd78059 0xFFFFFFFFU, /* dma_attr_seg */
2394978Sgd78059 1, /* dma_attr_sgllen */
2404978Sgd78059 1, /* dma_attr_granular */
2414978Sgd78059 0 /* dma_attr_flags */
2424978Sgd78059 };
2434978Sgd78059
2444978Sgd78059 /*
2454978Sgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can
2464978Sgd78059 * cross a page boundary, so we use the two buffer addresses of the
2474978Sgd78059 * chip to provide a two-entry scatter-gather list.
2484978Sgd78059 */
2494978Sgd78059 static ddi_dma_attr_t mxfe_dma_txattr = {
2504978Sgd78059 DMA_ATTR_V0, /* dma_attr_version */
2514978Sgd78059 0, /* dma_attr_addr_lo */
2524978Sgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */
2534978Sgd78059 0x7FFFFFFFU, /* dma_attr_count_max */
2544978Sgd78059 1, /* dma_attr_align */
2554978Sgd78059 0x3F, /* dma_attr_burstsizes */
2564978Sgd78059 1, /* dma_attr_minxfer */
2574978Sgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */
2584978Sgd78059 0xFFFFFFFFU, /* dma_attr_seg */
2594978Sgd78059 2, /* dma_attr_sgllen */
2604978Sgd78059 1, /* dma_attr_granular */
2614978Sgd78059 0 /* dma_attr_flags */
2624978Sgd78059 };
2634978Sgd78059
2644978Sgd78059 /*
2654978Sgd78059 * Ethernet addresses.
2664978Sgd78059 */
2674978Sgd78059 static uchar_t mxfe_broadcast[ETHERADDRL] = {
2684978Sgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2694978Sgd78059 };
2704978Sgd78059
2714978Sgd78059 /*
2724978Sgd78059 * DDI entry points.
2734978Sgd78059 */
2744978Sgd78059 int
_init(void)2754978Sgd78059 _init(void)
2764978Sgd78059 {
2774978Sgd78059 int rv;
2784978Sgd78059 mac_init_ops(&mxfe_devops, "mxfe");
2794978Sgd78059 if ((rv = mod_install(&mxfe_modlinkage)) != DDI_SUCCESS) {
2804978Sgd78059 mac_fini_ops(&mxfe_devops);
2814978Sgd78059 }
2824978Sgd78059 return (rv);
2834978Sgd78059 }
2844978Sgd78059
2854978Sgd78059 int
_fini(void)2864978Sgd78059 _fini(void)
2874978Sgd78059 {
2884978Sgd78059 int rv;
2894978Sgd78059 if ((rv = mod_remove(&mxfe_modlinkage)) == DDI_SUCCESS) {
2904978Sgd78059 mac_fini_ops(&mxfe_devops);
2914978Sgd78059 }
2924978Sgd78059 return (rv);
2934978Sgd78059 }
2944978Sgd78059
2954978Sgd78059 int
_info(struct modinfo * modinfop)2964978Sgd78059 _info(struct modinfo *modinfop)
2974978Sgd78059 {
2984978Sgd78059 return (mod_info(&mxfe_modlinkage, modinfop));
2994978Sgd78059 }
3004978Sgd78059
3014978Sgd78059 int
mxfe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3024978Sgd78059 mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3034978Sgd78059 {
3044978Sgd78059 mxfe_t *mxfep;
3054978Sgd78059 mac_register_t *macp;
3064978Sgd78059 int inst = ddi_get_instance(dip);
3074978Sgd78059 ddi_acc_handle_t pci;
3084978Sgd78059 uint16_t venid;
3094978Sgd78059 uint16_t devid;
3104978Sgd78059 uint16_t revid;
3114978Sgd78059 uint16_t svid;
3124978Sgd78059 uint16_t ssid;
3134978Sgd78059 uint16_t cachesize;
3144978Sgd78059 mxfe_card_t *cardp;
3154978Sgd78059 int i;
3164978Sgd78059
3174978Sgd78059 switch (cmd) {
3184978Sgd78059 case DDI_RESUME:
3194978Sgd78059 return (mxfe_resume(dip));
3204978Sgd78059
3214978Sgd78059 case DDI_ATTACH:
3224978Sgd78059 break;
3234978Sgd78059
3244978Sgd78059 default:
3254978Sgd78059 return (DDI_FAILURE);
3264978Sgd78059 }
3274978Sgd78059
3284978Sgd78059 /* this card is a bus master, reject any slave-only slot */
3294978Sgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) {
3304978Sgd78059 mxfe_error(dip, "slot does not support PCI bus-master");
3314978Sgd78059 return (DDI_FAILURE);
3324978Sgd78059 }
3334978Sgd78059 /* PCI devices shouldn't generate hilevel interrupts */
3344978Sgd78059 if (ddi_intr_hilevel(dip, 0) != 0) {
3354978Sgd78059 mxfe_error(dip, "hilevel interrupts not supported");
3364978Sgd78059 return (DDI_FAILURE);
3374978Sgd78059 }
3384978Sgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
3394978Sgd78059 mxfe_error(dip, "unable to setup PCI config handle");
3404978Sgd78059 return (DDI_FAILURE);
3414978Sgd78059 }
3424978Sgd78059
3434978Sgd78059 venid = pci_config_get16(pci, PCI_VID);
3444978Sgd78059 devid = pci_config_get16(pci, PCI_DID);
3454978Sgd78059 revid = pci_config_get16(pci, PCI_RID);
3464978Sgd78059 svid = pci_config_get16(pci, PCI_SVID);
3474978Sgd78059 ssid = pci_config_get16(pci, PCI_SSID);
3484978Sgd78059
3494978Sgd78059 /*
3504978Sgd78059 * the last entry in the card table matches every possible
3514978Sgd78059 * card, so the for-loop always terminates properly.
3524978Sgd78059 */
3534978Sgd78059 cardp = NULL;
3544978Sgd78059 for (i = 0; i < (sizeof (mxfe_cards) / sizeof (mxfe_card_t)); i++) {
3554978Sgd78059 if ((venid == mxfe_cards[i].card_venid) &&
3564978Sgd78059 (devid == mxfe_cards[i].card_devid) &&
3574978Sgd78059 ((revid & mxfe_cards[i].card_revmask) ==
3584978Sgd78059 mxfe_cards[i].card_revid)) {
3594978Sgd78059 cardp = &mxfe_cards[i];
3604978Sgd78059 }
3614978Sgd78059 if ((svid == mxfe_cards[i].card_venid) &&
3624978Sgd78059 (ssid == mxfe_cards[i].card_devid) &&
3634978Sgd78059 ((revid & mxfe_cards[i].card_revmask) ==
3644978Sgd78059 mxfe_cards[i].card_revid)) {
3654978Sgd78059 cardp = &mxfe_cards[i];
3664978Sgd78059 break;
3674978Sgd78059 }
3684978Sgd78059 }
3694978Sgd78059
3704978Sgd78059 if (cardp == NULL) {
3714978Sgd78059 pci_config_teardown(&pci);
3724978Sgd78059 mxfe_error(dip, "Unable to identify PCI card");
3734978Sgd78059 return (DDI_FAILURE);
3744978Sgd78059 }
3754978Sgd78059
3764978Sgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
3774978Sgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) {
3784978Sgd78059 pci_config_teardown(&pci);
3794978Sgd78059 mxfe_error(dip, "Unable to create model property");
3804978Sgd78059 return (DDI_FAILURE);
3814978Sgd78059 }
3824978Sgd78059
3834978Sgd78059 /*
3844978Sgd78059 * Grab the PCI cachesize -- we use this to program the
3854978Sgd78059 * cache-optimization bus access bits.
3864978Sgd78059 */
3874978Sgd78059 cachesize = pci_config_get8(pci, PCI_CLS);
3884978Sgd78059
3894978Sgd78059 /* this cannot fail */
3904978Sgd78059 mxfep = kmem_zalloc(sizeof (mxfe_t), KM_SLEEP);
3914978Sgd78059 ddi_set_driver_private(dip, mxfep);
3924978Sgd78059
3934978Sgd78059 /* get the interrupt block cookie */
3944978Sgd78059 if (ddi_get_iblock_cookie(dip, 0, &mxfep->mxfe_icookie)
3954978Sgd78059 != DDI_SUCCESS) {
3964978Sgd78059 mxfe_error(dip, "ddi_get_iblock_cookie failed");
3974978Sgd78059 pci_config_teardown(&pci);
3984978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t));
3994978Sgd78059 return (DDI_FAILURE);
4004978Sgd78059 }
4014978Sgd78059
4024978Sgd78059 mxfep->mxfe_dip = dip;
4034978Sgd78059 mxfep->mxfe_cardp = cardp;
4044978Sgd78059 mxfep->mxfe_phyaddr = -1;
4054978Sgd78059 mxfep->mxfe_cachesize = cachesize;
4064978Sgd78059
4074978Sgd78059 /* default properties */
4084978Sgd78059 mxfep->mxfe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4094978Sgd78059 "adv_autoneg_cap", 1);
4104978Sgd78059 mxfep->mxfe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4114978Sgd78059 "adv_100T4_cap", 1);
4124978Sgd78059 mxfep->mxfe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4134978Sgd78059 "adv_100fdx_cap", 1);
4144978Sgd78059 mxfep->mxfe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4154978Sgd78059 "adv_100hdx_cap", 1);
4164978Sgd78059 mxfep->mxfe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4174978Sgd78059 "adv_10fdx_cap", 1);
4184978Sgd78059 mxfep->mxfe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4194978Sgd78059 "adv_10hdx_cap", 1);
4204978Sgd78059
4214978Sgd78059 DBG(DPCI, "PCI vendor id = %x", venid);
4224978Sgd78059 DBG(DPCI, "PCI device id = %x", devid);
4234978Sgd78059 DBG(DPCI, "PCI revision id = %x", revid);
4244978Sgd78059 DBG(DPCI, "PCI cachesize = %d", cachesize);
4254978Sgd78059 DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD));
4264978Sgd78059 DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT));
4274978Sgd78059
4284978Sgd78059 mutex_init(&mxfep->mxfe_xmtlock, NULL, MUTEX_DRIVER,
4294978Sgd78059 mxfep->mxfe_icookie);
4304978Sgd78059 mutex_init(&mxfep->mxfe_intrlock, NULL, MUTEX_DRIVER,
4314978Sgd78059 mxfep->mxfe_icookie);
4324978Sgd78059
4334978Sgd78059 /*
4344978Sgd78059 * Enable bus master, IO space, and memory space accesses.
4354978Sgd78059 */
4364978Sgd78059 pci_config_put16(pci, PCI_CMD,
4374978Sgd78059 pci_config_get16(pci, PCI_CMD) |
4384978Sgd78059 PCI_CMD_BME | PCI_CMD_MAE | PCI_CMD_MWIE);
4394978Sgd78059
4404978Sgd78059 /* we're done with this now, drop it */
4414978Sgd78059 pci_config_teardown(&pci);
4424978Sgd78059
4434978Sgd78059 /*
4444978Sgd78059 * Initialize interrupt kstat. This should not normally fail, since
4454978Sgd78059 * we don't use a persistent stat. We do it this way to avoid having
4464978Sgd78059 * to test for it at run time on the hot path.
4474978Sgd78059 */
4484978Sgd78059 mxfep->mxfe_intrstat = kstat_create("mxfe", inst, "intr", "controller",
4494978Sgd78059 KSTAT_TYPE_INTR, 1, 0);
4504978Sgd78059 if (mxfep->mxfe_intrstat == NULL) {
4514978Sgd78059 mxfe_error(dip, "kstat_create failed");
4524978Sgd78059 goto failed;
4534978Sgd78059 }
4544978Sgd78059 kstat_install(mxfep->mxfe_intrstat);
4554978Sgd78059
4564978Sgd78059 /*
4574978Sgd78059 * Map in the device registers.
4584978Sgd78059 */
4594978Sgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mxfep->mxfe_regs,
4604978Sgd78059 0, 0, &mxfe_devattr, &mxfep->mxfe_regshandle)) {
4614978Sgd78059 mxfe_error(dip, "ddi_regs_map_setup failed");
4624978Sgd78059 goto failed;
4634978Sgd78059 }
4644978Sgd78059
4654978Sgd78059 /*
4664978Sgd78059 * Allocate DMA resources (descriptor rings and buffers).
4674978Sgd78059 */
4684978Sgd78059 if ((mxfe_allocrxring(mxfep) != DDI_SUCCESS) ||
4694978Sgd78059 (mxfe_alloctxring(mxfep) != DDI_SUCCESS)) {
4704978Sgd78059 mxfe_error(dip, "unable to allocate DMA resources");
4714978Sgd78059 goto failed;
4724978Sgd78059 }
4734978Sgd78059
4744978Sgd78059 /* Initialize the chip. */
4754978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
4764978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
4774978Sgd78059 if (!mxfe_initialize(mxfep)) {
4784978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
4794978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
4804978Sgd78059 goto failed;
4814978Sgd78059 }
4824978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
4834978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
4844978Sgd78059
4854978Sgd78059 /* Determine the number of address bits to our EEPROM. */
4864978Sgd78059 mxfep->mxfe_sromwidth = mxfe_sromwidth(mxfep);
4874978Sgd78059
4884978Sgd78059 /*
4894978Sgd78059 * Get the factory ethernet address. This becomes the current
4904978Sgd78059 * ethernet address (it can be overridden later via ifconfig).
4914978Sgd78059 */
4924978Sgd78059 mxfe_getfactaddr(mxfep, mxfep->mxfe_curraddr);
4934978Sgd78059 mxfep->mxfe_promisc = B_FALSE;
4944978Sgd78059
4954978Sgd78059 /*
4964978Sgd78059 * Establish interrupt handler.
4974978Sgd78059 */
4984978Sgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, mxfe_intr, (caddr_t)mxfep) !=
4994978Sgd78059 DDI_SUCCESS) {
5004978Sgd78059 mxfe_error(dip, "unable to add interrupt");
5014978Sgd78059 goto failed;
5024978Sgd78059 }
5034978Sgd78059
5044978Sgd78059 /* TODO: do the power management stuff */
5054978Sgd78059
5064978Sgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5074978Sgd78059 mxfe_error(dip, "mac_alloc failed");
5084978Sgd78059 goto failed;
5094978Sgd78059 }
5104978Sgd78059
5114978Sgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
5124978Sgd78059 macp->m_driver = mxfep;
5134978Sgd78059 macp->m_dip = dip;
5144978Sgd78059 macp->m_src_addr = mxfep->mxfe_curraddr;
5154978Sgd78059 macp->m_callbacks = &mxfe_m_callbacks;
5164978Sgd78059 macp->m_min_sdu = 0;
5174978Sgd78059 macp->m_max_sdu = ETHERMTU;
5185895Syz147064 macp->m_margin = VLAN_TAGSZ;
5194978Sgd78059
5204978Sgd78059 if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) {
5214978Sgd78059 mac_free(macp);
5224978Sgd78059 return (DDI_SUCCESS);
5234978Sgd78059 }
5244978Sgd78059
5254978Sgd78059 /* failed to register with MAC */
5264978Sgd78059 mac_free(macp);
5274978Sgd78059 failed:
5284978Sgd78059 if (mxfep->mxfe_icookie != NULL) {
5294978Sgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
5304978Sgd78059 }
5314978Sgd78059 if (mxfep->mxfe_intrstat) {
5324978Sgd78059 kstat_delete(mxfep->mxfe_intrstat);
5334978Sgd78059 }
5344978Sgd78059 mutex_destroy(&mxfep->mxfe_intrlock);
5354978Sgd78059 mutex_destroy(&mxfep->mxfe_xmtlock);
5364978Sgd78059
5374978Sgd78059 mxfe_freerxring(mxfep);
5384978Sgd78059 mxfe_freetxring(mxfep);
5394978Sgd78059
5404978Sgd78059 if (mxfep->mxfe_regshandle != NULL) {
5414978Sgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle);
5424978Sgd78059 }
5434978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t));
5444978Sgd78059 return (DDI_FAILURE);
5454978Sgd78059 }
5464978Sgd78059
5474978Sgd78059 int
mxfe_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5484978Sgd78059 mxfe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5494978Sgd78059 {
5504978Sgd78059 mxfe_t *mxfep;
5514978Sgd78059
5524978Sgd78059 mxfep = ddi_get_driver_private(dip);
5534978Sgd78059 if (mxfep == NULL) {
5544978Sgd78059 mxfe_error(dip, "no soft state in detach!");
5554978Sgd78059 return (DDI_FAILURE);
5564978Sgd78059 }
5574978Sgd78059
5584978Sgd78059 switch (cmd) {
5594978Sgd78059 case DDI_DETACH:
5604978Sgd78059
5614978Sgd78059 if (mac_unregister(mxfep->mxfe_mh) != 0) {
5624978Sgd78059 return (DDI_FAILURE);
5634978Sgd78059 }
5644978Sgd78059
5654978Sgd78059 /* make sure hardware is quiesced */
5664978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
5674978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
5684978Sgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING;
5694978Sgd78059 mxfe_stopall(mxfep);
5704978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
5714978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
5724978Sgd78059
5734978Sgd78059 /* clean up and shut down device */
5744978Sgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
5754978Sgd78059
5764978Sgd78059 /* clean up kstats */
5774978Sgd78059 kstat_delete(mxfep->mxfe_intrstat);
5784978Sgd78059
5794978Sgd78059 ddi_prop_remove_all(dip);
5804978Sgd78059
5814978Sgd78059 /* free up any left over buffers or DMA resources */
5824978Sgd78059 mxfe_freerxring(mxfep);
5834978Sgd78059 mxfe_freetxring(mxfep);
5844978Sgd78059
5854978Sgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle);
5864978Sgd78059 mutex_destroy(&mxfep->mxfe_intrlock);
5874978Sgd78059 mutex_destroy(&mxfep->mxfe_xmtlock);
5884978Sgd78059
5894978Sgd78059 kmem_free(mxfep, sizeof (mxfe_t));
5904978Sgd78059 return (DDI_SUCCESS);
5914978Sgd78059
5924978Sgd78059 case DDI_SUSPEND:
5934978Sgd78059 /* quiesce the hardware */
5944978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
5954978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
5964978Sgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED;
5974978Sgd78059 mxfe_stopall(mxfep);
5984978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
5994978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
6004978Sgd78059 return (DDI_SUCCESS);
6014978Sgd78059 default:
6024978Sgd78059 return (DDI_FAILURE);
6034978Sgd78059 }
6044978Sgd78059 }
6054978Sgd78059
6064978Sgd78059 int
mxfe_resume(dev_info_t * dip)6074978Sgd78059 mxfe_resume(dev_info_t *dip)
6084978Sgd78059 {
6094978Sgd78059 mxfe_t *mxfep;
6104978Sgd78059
6114978Sgd78059 if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
6124978Sgd78059 return (DDI_FAILURE);
6134978Sgd78059 }
6144978Sgd78059
6154978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
6164978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
6174978Sgd78059
6184978Sgd78059 mxfep->mxfe_flags &= ~MXFE_SUSPENDED;
6194978Sgd78059
6204978Sgd78059 /* re-initialize chip */
6214978Sgd78059 if (!mxfe_initialize(mxfep)) {
6224978Sgd78059 mxfe_error(mxfep->mxfe_dip, "unable to resume chip!");
6234978Sgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED;
6244978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
6254978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
6264978Sgd78059 return (DDI_SUCCESS);
6274978Sgd78059 }
6284978Sgd78059
6294978Sgd78059 /* start the chip */
6304978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) {
6314978Sgd78059 mxfe_startall(mxfep);
6324978Sgd78059 }
6334978Sgd78059
6344978Sgd78059 /* drop locks */
6354978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
6364978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
6374978Sgd78059
6384978Sgd78059 return (DDI_SUCCESS);
6394978Sgd78059 }
6404978Sgd78059
6419199Sgdamore@opensolaris.org int
mxfe_quiesce(dev_info_t * dip)6429199Sgdamore@opensolaris.org mxfe_quiesce(dev_info_t *dip)
6439199Sgdamore@opensolaris.org {
6449199Sgdamore@opensolaris.org mxfe_t *mxfep;
6459199Sgdamore@opensolaris.org
6469199Sgdamore@opensolaris.org if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
6479199Sgdamore@opensolaris.org return (DDI_FAILURE);
6489199Sgdamore@opensolaris.org }
6499199Sgdamore@opensolaris.org
6509199Sgdamore@opensolaris.org /* just do a hard reset of everything */
6519199Sgdamore@opensolaris.org SETBIT(mxfep, CSR_PAR, PAR_RESET);
6529199Sgdamore@opensolaris.org
6539199Sgdamore@opensolaris.org return (DDI_SUCCESS);
6549199Sgdamore@opensolaris.org }
6559199Sgdamore@opensolaris.org
6564978Sgd78059 /*ARGSUSED*/
6574978Sgd78059 int
mxfe_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)6584978Sgd78059 mxfe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
6594978Sgd78059 {
6604978Sgd78059 /* we already receive all multicast frames */
6614978Sgd78059 return (0);
6624978Sgd78059 }
6634978Sgd78059
6644978Sgd78059 int
mxfe_m_promisc(void * arg,boolean_t on)6654978Sgd78059 mxfe_m_promisc(void *arg, boolean_t on)
6664978Sgd78059 {
6674978Sgd78059 mxfe_t *mxfep = arg;
6684978Sgd78059
6694978Sgd78059 /* exclusive access to the card while we reprogram it */
6704978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
6714978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
6724978Sgd78059 /* save current promiscuous mode state for replay in resume */
6734978Sgd78059 mxfep->mxfe_promisc = on;
6744978Sgd78059
6754978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
6764978Sgd78059 MXFE_RUNNING) {
6774978Sgd78059 if (on)
6784978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
6794978Sgd78059 else
6804978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
6814978Sgd78059 }
6824978Sgd78059
6834978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
6844978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
6854978Sgd78059
6864978Sgd78059 return (0);
6874978Sgd78059 }
6884978Sgd78059
6894978Sgd78059 int
mxfe_m_unicst(void * arg,const uint8_t * macaddr)6904978Sgd78059 mxfe_m_unicst(void *arg, const uint8_t *macaddr)
6914978Sgd78059 {
6924978Sgd78059 mxfe_t *mxfep = arg;
6934978Sgd78059
6944978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
6954978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
6964978Sgd78059 bcopy(macaddr, mxfep->mxfe_curraddr, ETHERADDRL);
6974978Sgd78059
6984978Sgd78059 mxfe_resetall(mxfep);
6994978Sgd78059
7004978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
7014978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
7024978Sgd78059
7034978Sgd78059 return (0);
7044978Sgd78059 }
7054978Sgd78059
7064978Sgd78059 mblk_t *
mxfe_m_tx(void * arg,mblk_t * mp)7074978Sgd78059 mxfe_m_tx(void *arg, mblk_t *mp)
7084978Sgd78059 {
7094978Sgd78059 mxfe_t *mxfep = arg;
7104978Sgd78059 mblk_t *nmp;
7114978Sgd78059
7124978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
7134978Sgd78059
7144978Sgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
7154978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
7164978Sgd78059 return (mp);
7174978Sgd78059 }
7184978Sgd78059
7194978Sgd78059 while (mp != NULL) {
7204978Sgd78059 nmp = mp->b_next;
7214978Sgd78059 mp->b_next = NULL;
7224978Sgd78059
7234978Sgd78059 if (!mxfe_send(mxfep, mp)) {
7244978Sgd78059 mp->b_next = nmp;
7254978Sgd78059 break;
7264978Sgd78059 }
7274978Sgd78059 mp = nmp;
7284978Sgd78059 }
7294978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
7304978Sgd78059
7314978Sgd78059 return (mp);
7324978Sgd78059 }
7334978Sgd78059
7344978Sgd78059 /*
7354978Sgd78059 * Hardware management.
7364978Sgd78059 */
7374978Sgd78059 boolean_t
mxfe_initialize(mxfe_t * mxfep)7384978Sgd78059 mxfe_initialize(mxfe_t *mxfep)
7394978Sgd78059 {
7404978Sgd78059 int i;
7414978Sgd78059 unsigned val;
7424978Sgd78059 uint32_t par, nar;
7434978Sgd78059
7444978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
7454978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
7464978Sgd78059
7474978Sgd78059 DBG(DCHATTY, "resetting!");
7484978Sgd78059 SETBIT(mxfep, CSR_PAR, PAR_RESET);
7494978Sgd78059 for (i = 1; i < 10; i++) {
7504978Sgd78059 drv_usecwait(5);
7514978Sgd78059 val = GETCSR(mxfep, CSR_PAR);
7524978Sgd78059 if (!(val & PAR_RESET)) {
7534978Sgd78059 break;
7544978Sgd78059 }
7554978Sgd78059 }
7564978Sgd78059 if (i == 10) {
7574978Sgd78059 mxfe_error(mxfep->mxfe_dip, "timed out waiting for reset!");
7584978Sgd78059 return (B_FALSE);
7594978Sgd78059 }
7604978Sgd78059
7614978Sgd78059 /* initialize busctl register */
7624978Sgd78059 par = PAR_BAR | PAR_MRME | PAR_MRLE | PAR_MWIE;
7634978Sgd78059
7644978Sgd78059 /* set the cache alignment if its supported */
7654978Sgd78059 switch (mxfep->mxfe_cachesize) {
7664978Sgd78059 case 8:
7674978Sgd78059 par |= PAR_CALIGN_8;
7684978Sgd78059 break;
7694978Sgd78059 case 16:
7704978Sgd78059 par |= PAR_CALIGN_16;
7714978Sgd78059 break;
7724978Sgd78059 case 32:
7734978Sgd78059 par |= PAR_CALIGN_32;
7744978Sgd78059 break;
7754978Sgd78059 default:
7764978Sgd78059 par &= ~(PAR_MWIE | PAR_MRME | PAR_MRLE);
7774978Sgd78059 }
7784978Sgd78059
7794978Sgd78059 /* leave the burst length at zero, indicating infinite burst */
7804978Sgd78059 PUTCSR(mxfep, CSR_PAR, par);
7814978Sgd78059
7824978Sgd78059 mxfe_resetrings(mxfep);
7834978Sgd78059
7844978Sgd78059 /* clear the lost packet counter (cleared on read) */
7854978Sgd78059 (void) GETCSR(mxfep, CSR_LPC);
7864978Sgd78059
7874978Sgd78059 /* a few other NAR bits */
7884978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
7894978Sgd78059 nar &= ~NAR_RX_HO; /* disable hash only filtering */
7904978Sgd78059 nar |= NAR_RX_HP; /* hash perfect forwarding */
7914978Sgd78059 nar |= NAR_RX_MULTI; /* receive all multicast */
7924978Sgd78059 nar |= NAR_SF; /* store-and-forward */
7934978Sgd78059
7944978Sgd78059 if (mxfep->mxfe_promisc) {
7954978Sgd78059 nar |= NAR_RX_PROMISC;
7964978Sgd78059 } else {
7974978Sgd78059 nar &= ~NAR_RX_PROMISC;
7984978Sgd78059 }
7994978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
8004978Sgd78059
8014978Sgd78059 mxfe_send_setup(mxfep);
8024978Sgd78059
8034978Sgd78059 return (B_TRUE);
8044978Sgd78059 }
8054978Sgd78059
8064978Sgd78059 /*
8074978Sgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation.
8084978Sgd78059 */
8094978Sgd78059
8104978Sgd78059 uint8_t
mxfe_sromwidth(mxfe_t * mxfep)8114978Sgd78059 mxfe_sromwidth(mxfe_t *mxfep)
8124978Sgd78059 {
8134978Sgd78059 int i;
8144978Sgd78059 int eeread;
8154978Sgd78059 uint8_t addrlen = 8;
8164978Sgd78059
8174978Sgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
8184978Sgd78059
8194978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
8204978Sgd78059 drv_usecwait(1);
8214978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8224978Sgd78059
8234978Sgd78059 /* command bits first */
8244978Sgd78059 for (i = 4; i != 0; i >>= 1) {
8254978Sgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0;
8264978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val);
8274978Sgd78059 drv_usecwait(1);
8284978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
8294978Sgd78059 drv_usecwait(1);
8304978Sgd78059 }
8314978Sgd78059
8324978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8334978Sgd78059
8344978Sgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) {
8354978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
8364978Sgd78059 drv_usecwait(1);
8374978Sgd78059 if (!(GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT)) {
8384978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8394978Sgd78059 drv_usecwait(1);
8404978Sgd78059 break;
8414978Sgd78059 }
8424978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8434978Sgd78059 drv_usecwait(1);
8444978Sgd78059 }
8454978Sgd78059
8464978Sgd78059 /* turn off accesses to the EEPROM */
8474978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
8484978Sgd78059
8494978Sgd78059 DBG(DSROM, "detected srom width = %d bits", addrlen);
8504978Sgd78059
8514978Sgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen);
8524978Sgd78059 }
8534978Sgd78059
8544978Sgd78059 /*
8554978Sgd78059 * The words in EEPROM are stored in little endian order. We
8564978Sgd78059 * shift bits out in big endian order, though. This requires
8574978Sgd78059 * a byte swap on some platforms.
8584978Sgd78059 */
8594978Sgd78059 uint16_t
mxfe_readsromword(mxfe_t * mxfep,unsigned romaddr)8604978Sgd78059 mxfe_readsromword(mxfe_t *mxfep, unsigned romaddr)
8614978Sgd78059 {
8624978Sgd78059 int i;
8634978Sgd78059 uint16_t word = 0;
8644978Sgd78059 uint16_t retval;
8654978Sgd78059 int eeread;
8664978Sgd78059 uint8_t addrlen;
8674978Sgd78059 int readcmd;
8684978Sgd78059 uchar_t *ptr;
8694978Sgd78059
8704978Sgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
8714978Sgd78059 addrlen = mxfep->mxfe_sromwidth;
8724978Sgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr;
8734978Sgd78059
8744978Sgd78059 if (romaddr >= (1 << addrlen)) {
8754978Sgd78059 /* too big to fit! */
8764978Sgd78059 return (0);
8774978Sgd78059 }
8784978Sgd78059
8794978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
8804978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8814978Sgd78059
8824978Sgd78059 /* command and address bits */
8834978Sgd78059 for (i = 4 + addrlen; i >= 0; i--) {
8844978Sgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0;
8854978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val);
8864978Sgd78059 drv_usecwait(1);
8874978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
8884978Sgd78059 drv_usecwait(1);
8894978Sgd78059 }
8904978Sgd78059
8914978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
8924978Sgd78059
8934978Sgd78059 for (i = 0; i < 16; i++) {
8944978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
8954978Sgd78059 drv_usecwait(1);
8964978Sgd78059 word <<= 1;
8974978Sgd78059 if (GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT) {
8984978Sgd78059 word |= 1;
8994978Sgd78059 }
9004978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
9014978Sgd78059 drv_usecwait(1);
9024978Sgd78059 }
9034978Sgd78059
9044978Sgd78059 /* turn off accesses to the EEPROM */
9054978Sgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
9064978Sgd78059
9074978Sgd78059 /*
9084978Sgd78059 * Fix up the endianness thing. Note that the values
9094978Sgd78059 * are stored in little endian format on the SROM.
9104978Sgd78059 */
9114978Sgd78059 DBG(DSROM, "got value %d from SROM (before swap)", word);
9124978Sgd78059 ptr = (uchar_t *)&word;
9134978Sgd78059 retval = (ptr[1] << 8) | ptr[0];
9144978Sgd78059 return (retval);
9154978Sgd78059 }
9164978Sgd78059
9174978Sgd78059 void
mxfe_readsrom(mxfe_t * mxfep,unsigned romaddr,unsigned len,void * dest)9184978Sgd78059 mxfe_readsrom(mxfe_t *mxfep, unsigned romaddr, unsigned len, void *dest)
9194978Sgd78059 {
9204978Sgd78059 char *ptr = dest;
9214978Sgd78059 int i;
9224978Sgd78059 uint16_t word;
9234978Sgd78059
9244978Sgd78059 for (i = 0; i < len; i++) {
9254978Sgd78059 word = mxfe_readsromword(mxfep, romaddr + i);
9264978Sgd78059 bcopy(&word, ptr, 2);
9274978Sgd78059 ptr += 2;
9284978Sgd78059 DBG(DSROM, "word at %d is 0x%x", romaddr + i, word);
9294978Sgd78059 }
9304978Sgd78059 }
9314978Sgd78059
9324978Sgd78059 void
mxfe_getfactaddr(mxfe_t * mxfep,uchar_t * eaddr)9334978Sgd78059 mxfe_getfactaddr(mxfe_t *mxfep, uchar_t *eaddr)
9344978Sgd78059 {
9354978Sgd78059 uint16_t word;
9364978Sgd78059 uchar_t *ptr;
9374978Sgd78059
9384978Sgd78059 /* first read to get the location of mac address in srom */
9394978Sgd78059 word = mxfe_readsromword(mxfep, SROM_ENADDR / 2);
9404978Sgd78059 ptr = (uchar_t *)&word;
9414978Sgd78059 word = (ptr[1] << 8) | ptr[0];
9424978Sgd78059
9434978Sgd78059 /* then read the actual mac address */
9444978Sgd78059 mxfe_readsrom(mxfep, word / 2, ETHERADDRL / 2, eaddr);
9454978Sgd78059 DBG(DMACID,
9464978Sgd78059 "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x",
9474978Sgd78059 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
9484978Sgd78059 }
9494978Sgd78059
9504978Sgd78059 void
mxfe_startphy(mxfe_t * mxfep)9514978Sgd78059 mxfe_startphy(mxfe_t *mxfep)
9524978Sgd78059 {
9534978Sgd78059 switch (MXFE_MODEL(mxfep)) {
9544978Sgd78059 case MXFE_98713A:
9554978Sgd78059 mxfe_startphymii(mxfep);
9564978Sgd78059 break;
9574978Sgd78059 default:
9584978Sgd78059 mxfe_startphynway(mxfep);
9594978Sgd78059 break;
9604978Sgd78059 }
9614978Sgd78059 }
9624978Sgd78059
9634978Sgd78059 void
mxfe_stopphy(mxfe_t * mxfep)9644978Sgd78059 mxfe_stopphy(mxfe_t *mxfep)
9654978Sgd78059 {
9664978Sgd78059 uint32_t nar;
9674978Sgd78059 int i;
9684978Sgd78059
9694978Sgd78059 /* stop the phy timer */
9704978Sgd78059 PUTCSR(mxfep, CSR_TIMER, 0);
9714978Sgd78059
9724978Sgd78059 switch (MXFE_MODEL(mxfep)) {
9734978Sgd78059 case MXFE_98713A:
9744978Sgd78059 for (i = 0; i < 32; i++) {
9754978Sgd78059 mxfe_miiwrite(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL,
9764978Sgd78059 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
9774978Sgd78059 }
9784978Sgd78059 break;
9794978Sgd78059 default:
9804978Sgd78059 DBG(DPHY, "resetting SIA");
9814978Sgd78059 PUTCSR(mxfep, CSR_SIA, SIA_RESET);
9824978Sgd78059 drv_usecwait(500);
9834978Sgd78059 CLRBIT(mxfep, CSR_TCTL, TCTL_PWR | TCTL_ANE);
9844978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
9854978Sgd78059 nar &= ~(NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX);
9864978Sgd78059 nar |= NAR_SPEED;
9874978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
9884978Sgd78059 break;
9894978Sgd78059 }
9904978Sgd78059
9914978Sgd78059 /*
9924978Sgd78059 * mark the link state unknown
9934978Sgd78059 */
9944978Sgd78059 if (!mxfep->mxfe_resetting) {
9954978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UNKNOWN;
9964978Sgd78059 mxfep->mxfe_ifspeed = 0;
9974978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
9984978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
9994978Sgd78059 mxfe_reportlink(mxfep);
10004978Sgd78059 }
10014978Sgd78059 }
10024978Sgd78059
10034978Sgd78059 /*
10044978Sgd78059 * NWay support.
10054978Sgd78059 */
10064978Sgd78059 void
mxfe_startnway(mxfe_t * mxfep)10074978Sgd78059 mxfe_startnway(mxfe_t *mxfep)
10084978Sgd78059 {
10094978Sgd78059 unsigned nar;
10104978Sgd78059 unsigned tctl;
10114978Sgd78059 unsigned restart;
10124978Sgd78059
10134978Sgd78059 /* this should not happen in a healthy system */
10146684Sgd78059 if (mxfep->mxfe_nwaystate != MXFE_NOLINK) {
10154978Sgd78059 DBG(DWARN, "link start called out of state (%x)",
10166684Sgd78059 mxfep->mxfe_nwaystate);
10174978Sgd78059 return;
10184978Sgd78059 }
10194978Sgd78059
10204978Sgd78059 if (mxfep->mxfe_adv_aneg == 0) {
10214978Sgd78059 /* not done for forced mode */
10224978Sgd78059 return;
10234978Sgd78059 }
10244978Sgd78059
10254978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
10264978Sgd78059 restart = nar & (NAR_TX_ENABLE | NAR_RX_ENABLE);
10274978Sgd78059 nar &= ~restart;
10284978Sgd78059
10294978Sgd78059 if (restart != 0)
10304978Sgd78059 mxfe_stopmac(mxfep);
10314978Sgd78059
10324978Sgd78059 nar |= NAR_SCR | NAR_PCS | NAR_HBD;
10334978Sgd78059 nar &= ~(NAR_FDX);
10344978Sgd78059
10354978Sgd78059 tctl = GETCSR(mxfep, CSR_TCTL);
10364978Sgd78059 tctl &= ~(TCTL_100FDX | TCTL_100HDX | TCTL_HDX);
10374978Sgd78059
10384978Sgd78059 if (mxfep->mxfe_adv_100fdx) {
10394978Sgd78059 tctl |= TCTL_100FDX;
10404978Sgd78059 }
10414978Sgd78059 if (mxfep->mxfe_adv_100hdx) {
10424978Sgd78059 tctl |= TCTL_100HDX;
10434978Sgd78059 }
10444978Sgd78059 if (mxfep->mxfe_adv_10fdx) {
10454978Sgd78059 nar |= NAR_FDX;
10464978Sgd78059 }
10474978Sgd78059 if (mxfep->mxfe_adv_10hdx) {
10484978Sgd78059 tctl |= TCTL_HDX;
10494978Sgd78059 }
10504978Sgd78059 tctl |= TCTL_PWR | TCTL_ANE | TCTL_LTE | TCTL_RSQ;
10514978Sgd78059
10524978Sgd78059 /* possibly we should add in support for PAUSE frames */
10534978Sgd78059 DBG(DPHY, "writing nar = 0x%x", nar);
10544978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
10554978Sgd78059
10564978Sgd78059 DBG(DPHY, "writing tctl = 0x%x", tctl);
10574978Sgd78059 PUTCSR(mxfep, CSR_TCTL, tctl);
10584978Sgd78059
10594978Sgd78059 /* restart autonegotation */
10604978Sgd78059 DBG(DPHY, "writing tstat = 0x%x", TSTAT_ANS_START);
10614978Sgd78059 PUTCSR(mxfep, CSR_TSTAT, TSTAT_ANS_START);
10624978Sgd78059
10634978Sgd78059 /* restart tx/rx processes... */
10644978Sgd78059 if (restart != 0)
10654978Sgd78059 mxfe_startmac(mxfep);
10664978Sgd78059
10674978Sgd78059 /* Macronix initializations from Bolo Tsai */
10684978Sgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
10694978Sgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000);
10704978Sgd78059
10716684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NWAYCHECK;
10724978Sgd78059 }
10734978Sgd78059
10744978Sgd78059 void
mxfe_checklinknway(mxfe_t * mxfep)10754978Sgd78059 mxfe_checklinknway(mxfe_t *mxfep)
10764978Sgd78059 {
10776684Sgd78059 unsigned tstat;
10786684Sgd78059 uint16_t lpar;
10796684Sgd78059
10806684Sgd78059 DBG(DPHY, "NWay check, state %x", mxfep->mxfe_nwaystate);
10814978Sgd78059 tstat = GETCSR(mxfep, CSR_TSTAT);
10824978Sgd78059 lpar = TSTAT_LPAR(tstat);
10834978Sgd78059
10844978Sgd78059 mxfep->mxfe_anlpar = lpar;
10854978Sgd78059 if (tstat & TSTAT_LPN) {
10864978Sgd78059 mxfep->mxfe_aner |= MII_AN_EXP_LPCANAN;
10874978Sgd78059 } else {
10884978Sgd78059 mxfep->mxfe_aner &= ~(MII_AN_EXP_LPCANAN);
10894978Sgd78059 }
10904978Sgd78059
10914978Sgd78059 DBG(DPHY, "tstat(CSR12) = 0x%x", tstat);
10924978Sgd78059 DBG(DPHY, "ANEG state = 0x%x", (tstat & TSTAT_ANS) >> 12);
10934978Sgd78059
10944978Sgd78059 if ((tstat & TSTAT_ANS) != TSTAT_ANS_OK) {
10954978Sgd78059 /* autoneg did not complete */
10964978Sgd78059 mxfep->mxfe_bmsr &= ~MII_STATUS_ANDONE;
10974978Sgd78059 } else {
10984978Sgd78059 mxfep->mxfe_bmsr |= ~MII_STATUS_ANDONE;
10994978Sgd78059 }
11004978Sgd78059
11014978Sgd78059 if ((tstat & TSTAT_100F) && (tstat & TSTAT_10F)) {
11024978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
11034978Sgd78059 mxfep->mxfe_ifspeed = 0;
11044978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
11056684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK;
11064978Sgd78059 mxfe_reportlink(mxfep);
11074978Sgd78059 mxfe_startnway(mxfep);
11084978Sgd78059 return;
11094978Sgd78059 }
11104978Sgd78059
11114978Sgd78059 /*
11124978Sgd78059 * if the link is newly up, then we might need to set various
11134978Sgd78059 * mode bits, or negotiate for parameters, etc.
11144978Sgd78059 */
11154978Sgd78059 if (mxfep->mxfe_adv_aneg) {
11164978Sgd78059
11174978Sgd78059 uint16_t anlpar;
11184978Sgd78059
11194978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
11204978Sgd78059 anlpar = mxfep->mxfe_anlpar;
11214978Sgd78059
11224978Sgd78059 if (tstat & TSTAT_LPN) {
11234978Sgd78059 /* partner has NWay */
11244978Sgd78059
11254978Sgd78059 if ((anlpar & MII_ABILITY_100BASE_TX_FD) &&
11264978Sgd78059 mxfep->mxfe_adv_100fdx) {
11274978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
11284978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11294978Sgd78059 } else if ((anlpar & MII_ABILITY_100BASE_TX) &&
11304978Sgd78059 mxfep->mxfe_adv_100hdx) {
11314978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
11324978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11334978Sgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T_FD) &&
11344978Sgd78059 mxfep->mxfe_adv_10fdx) {
11354978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
11364978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11374978Sgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T) &&
11384978Sgd78059 mxfep->mxfe_adv_10hdx) {
11394978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
11404978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11414978Sgd78059 } else {
11424978Sgd78059 mxfep->mxfe_ifspeed = 0;
11434978Sgd78059 }
11444978Sgd78059 } else {
11454978Sgd78059 /* link partner does not have NWay */
11464978Sgd78059 /* just assume half duplex, since we can't detect */
11474978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11484978Sgd78059 if (!(tstat & TSTAT_100F)) {
11494978Sgd78059 DBG(DPHY, "Partner doesn't have NWAY");
11504978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
11514978Sgd78059 } else {
11524978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
11534978Sgd78059 }
11544978Sgd78059 }
11554978Sgd78059 } else {
11564978Sgd78059 /* forced modes */
11574978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
11584978Sgd78059 if (mxfep->mxfe_adv_100fdx) {
11594978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
11604978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11614978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) {
11624978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
11634978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11644978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) {
11654978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
11664978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11674978Sgd78059 } else if (mxfep->mxfe_adv_10hdx) {
11684978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
11694978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11704978Sgd78059 } else {
11714978Sgd78059 mxfep->mxfe_ifspeed = 0;
11724978Sgd78059 }
11734978Sgd78059 }
11744978Sgd78059 mxfe_reportlink(mxfep);
11756684Sgd78059 mxfep->mxfe_nwaystate = MXFE_GOODLINK;
11764978Sgd78059 }
11774978Sgd78059
11784978Sgd78059 void
mxfe_startphynway(mxfe_t * mxfep)11794978Sgd78059 mxfe_startphynway(mxfe_t *mxfep)
11804978Sgd78059 {
11814978Sgd78059 /* take NWay and PHY out of reset */
11824978Sgd78059 PUTCSR(mxfep, CSR_SIA, SIA_NRESET);
11834978Sgd78059 drv_usecwait(500);
11844978Sgd78059
11856684Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK;
11864978Sgd78059 mxfep->mxfe_bmsr = MII_STATUS_CANAUTONEG |
11874978Sgd78059 MII_STATUS_100_BASEX_FD | MII_STATUS_100_BASEX |
11884978Sgd78059 MII_STATUS_10_FD | MII_STATUS_10;
11896684Sgd78059 mxfep->mxfe_cap_aneg =
11906684Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
11916684Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
11924978Sgd78059
11934978Sgd78059 /* lie about the transceiver... its not really 802.3u compliant */
11944978Sgd78059 mxfep->mxfe_phyaddr = 0;
11954978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100X;
11964978Sgd78059 mxfep->mxfe_phyid = 0;
11974978Sgd78059
11984978Sgd78059 /* 100-T4 not supported with NWay */
11994978Sgd78059 mxfep->mxfe_adv_100T4 = 0;
12006684Sgd78059 mxfep->mxfe_cap_100T4 = 0;
12014978Sgd78059
12024978Sgd78059 /* make sure at least one valid mode is selected */
12034978Sgd78059 if ((!mxfep->mxfe_adv_100fdx) &&
12044978Sgd78059 (!mxfep->mxfe_adv_100hdx) &&
12054978Sgd78059 (!mxfep->mxfe_adv_10fdx) &&
12064978Sgd78059 (!mxfep->mxfe_adv_10hdx)) {
12074978Sgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
12084978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
12094978Sgd78059 mxfe_stopphy(mxfep);
12104978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
12114978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
12124978Sgd78059 mxfe_reportlink(mxfep);
12134978Sgd78059 return;
12144978Sgd78059 }
12154978Sgd78059
12164978Sgd78059 if (mxfep->mxfe_adv_aneg == 0) {
12174978Sgd78059 /* forced mode */
12184978Sgd78059 unsigned nar;
12194978Sgd78059 unsigned tctl;
12204978Sgd78059
12214978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
12224978Sgd78059 tctl = GETCSR(mxfep, CSR_TCTL);
12234978Sgd78059
12244978Sgd78059 ASSERT((nar & (NAR_TX_ENABLE | NAR_RX_ENABLE)) == 0);
12254978Sgd78059
12264978Sgd78059 nar &= ~(NAR_FDX | NAR_PORTSEL | NAR_SCR | NAR_SPEED);
12274978Sgd78059 tctl &= ~TCTL_ANE;
12284978Sgd78059 if (mxfep->mxfe_adv_100fdx) {
12294978Sgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX;
12304978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) {
12314978Sgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR;
12324978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) {
12334978Sgd78059 nar |= NAR_FDX | NAR_SPEED;
12344978Sgd78059 } else { /* mxfep->mxfe_adv_10hdx */
12354978Sgd78059 nar |= NAR_SPEED;
12364978Sgd78059 }
12374978Sgd78059
12384978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
12394978Sgd78059 PUTCSR(mxfep, CSR_TCTL, tctl);
12404978Sgd78059
12414978Sgd78059 /* Macronix initializations from Bolo Tsai */
12424978Sgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
12434978Sgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000);
12444978Sgd78059 } else {
12454978Sgd78059 mxfe_startnway(mxfep);
12464978Sgd78059 }
12474978Sgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
12484978Sgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC));
12494978Sgd78059 }
12504978Sgd78059
12514978Sgd78059 /*
12524978Sgd78059 * MII management.
12534978Sgd78059 */
12544978Sgd78059 void
mxfe_startphymii(mxfe_t * mxfep)12554978Sgd78059 mxfe_startphymii(mxfe_t *mxfep)
12564978Sgd78059 {
12574978Sgd78059 unsigned phyaddr;
12584978Sgd78059 unsigned bmcr;
12594978Sgd78059 unsigned bmsr;
12604978Sgd78059 unsigned anar;
12614978Sgd78059 unsigned phyidr1;
12624978Sgd78059 unsigned phyidr2;
12634978Sgd78059 int retries;
12644978Sgd78059 int cnt;
12654978Sgd78059
12664978Sgd78059 mxfep->mxfe_phyaddr = -1;
12674978Sgd78059
12684978Sgd78059 /* search for first PHY we can find */
12694978Sgd78059 for (phyaddr = 0; phyaddr < 32; phyaddr++) {
12704978Sgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
12714978Sgd78059 if ((bmsr != 0) && (bmsr != 0xffff)) {
12724978Sgd78059 mxfep->mxfe_phyaddr = phyaddr;
12734978Sgd78059 break;
12744978Sgd78059 }
12754978Sgd78059 }
12764978Sgd78059
12774978Sgd78059 phyidr1 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDH);
12784978Sgd78059 phyidr2 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDL);
12794978Sgd78059 mxfep->mxfe_phyid = (phyidr1 << 16) | (phyidr2);
12804978Sgd78059
12814978Sgd78059 /*
12824978Sgd78059 * Generally, all Macronix based devices use an internal
12834978Sgd78059 * 100BASE-TX internal transceiver. If we ever run into a
12844978Sgd78059 * variation on this, then the following logic will need to be
12854978Sgd78059 * enhanced.
12864978Sgd78059 *
12874978Sgd78059 * One could question the value of the XCVR_INUSE field in the
12884978Sgd78059 * MII statistics.
12894978Sgd78059 */
12904978Sgd78059 if (bmsr & MII_STATUS_100_BASE_T4) {
12914978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100T4;
12924978Sgd78059 } else {
12934978Sgd78059 mxfep->mxfe_phyinuse = XCVR_100X;
12944978Sgd78059 }
12954978Sgd78059
12966684Sgd78059 /* assume we support everything to start */
12976684Sgd78059 mxfep->mxfe_cap_aneg = mxfep->mxfe_cap_100T4 =
12986684Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
12996684Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
13006684Sgd78059
13014978Sgd78059 DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2);
13024978Sgd78059 DBG(DPHY, "bmsr = %x", mxfe_miiread(mxfep,
13034978Sgd78059 mxfep->mxfe_phyaddr, MII_STATUS));
13044978Sgd78059 DBG(DPHY, "anar = %x", mxfe_miiread(mxfep,
13054978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_ADVERT));
13064978Sgd78059 DBG(DPHY, "anlpar = %x", mxfe_miiread(mxfep,
13074978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_LPABLE));
13084978Sgd78059 DBG(DPHY, "aner = %x", mxfe_miiread(mxfep,
13094978Sgd78059 mxfep->mxfe_phyaddr, MII_AN_EXPANSION));
13104978Sgd78059
13114978Sgd78059 DBG(DPHY, "resetting phy");
13124978Sgd78059
13134978Sgd78059 /* we reset the phy block */
13144978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
13154978Sgd78059 /*
13164978Sgd78059 * wait for it to complete -- 500usec is still to short to
13174978Sgd78059 * bother getting the system clock involved.
13184978Sgd78059 */
13194978Sgd78059 drv_usecwait(500);
13204978Sgd78059 for (retries = 0; retries < 10; retries++) {
13214978Sgd78059 if (mxfe_miiread(mxfep, phyaddr, MII_CONTROL) &
13224978Sgd78059 MII_CONTROL_RESET) {
13234978Sgd78059 drv_usecwait(500);
13244978Sgd78059 continue;
13254978Sgd78059 }
13264978Sgd78059 break;
13274978Sgd78059 }
13284978Sgd78059 if (retries == 100) {
13294978Sgd78059 mxfe_error(mxfep->mxfe_dip, "timeout waiting on phy to reset");
13304978Sgd78059 return;
13314978Sgd78059 }
13324978Sgd78059
13334978Sgd78059 DBG(DPHY, "phy reset complete");
13344978Sgd78059
13354978Sgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
13364978Sgd78059 bmcr = mxfe_miiread(mxfep, phyaddr, MII_CONTROL);
13374978Sgd78059 anar = mxfe_miiread(mxfep, phyaddr, MII_AN_ADVERT);
13384978Sgd78059
13394978Sgd78059 anar &= ~(MII_ABILITY_100BASE_T4 |
13404978Sgd78059 MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
13414978Sgd78059 MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
13424978Sgd78059
13434978Sgd78059 /* disable modes not supported in hardware */
13444978Sgd78059 if (!(bmsr & MII_STATUS_100_BASE_T4)) {
13454978Sgd78059 mxfep->mxfe_adv_100T4 = 0;
13466684Sgd78059 mxfep->mxfe_cap_100T4 = 0;
13474978Sgd78059 }
13484978Sgd78059 if (!(bmsr & MII_STATUS_100_BASEX_FD)) {
13494978Sgd78059 mxfep->mxfe_adv_100fdx = 0;
13506684Sgd78059 mxfep->mxfe_cap_100fdx = 0;
13514978Sgd78059 }
13524978Sgd78059 if (!(bmsr & MII_STATUS_100_BASEX)) {
13534978Sgd78059 mxfep->mxfe_adv_100hdx = 0;
13546684Sgd78059 mxfep->mxfe_cap_100hdx = 0;
13554978Sgd78059 }
13564978Sgd78059 if (!(bmsr & MII_STATUS_10_FD)) {
13574978Sgd78059 mxfep->mxfe_adv_10fdx = 0;
13586684Sgd78059 mxfep->mxfe_cap_10fdx = 0;
13594978Sgd78059 }
13604978Sgd78059 if (!(bmsr & MII_STATUS_10)) {
13614978Sgd78059 mxfep->mxfe_adv_10hdx = 0;
13626684Sgd78059 mxfep->mxfe_cap_10hdx = 0;
13634978Sgd78059 }
13644978Sgd78059 if (!(bmsr & MII_STATUS_CANAUTONEG)) {
13654978Sgd78059 mxfep->mxfe_adv_aneg = 0;
13666684Sgd78059 mxfep->mxfe_cap_aneg = 0;
13674978Sgd78059 }
13684978Sgd78059
13694978Sgd78059 cnt = 0;
13704978Sgd78059 if (mxfep->mxfe_adv_100T4) {
13714978Sgd78059 anar |= MII_ABILITY_100BASE_T4;
13724978Sgd78059 cnt++;
13734978Sgd78059 }
13744978Sgd78059 if (mxfep->mxfe_adv_100fdx) {
13754978Sgd78059 anar |= MII_ABILITY_100BASE_TX_FD;
13764978Sgd78059 cnt++;
13774978Sgd78059 }
13784978Sgd78059 if (mxfep->mxfe_adv_100hdx) {
13794978Sgd78059 anar |= MII_ABILITY_100BASE_TX;
13804978Sgd78059 cnt++;
13814978Sgd78059 }
13824978Sgd78059 if (mxfep->mxfe_adv_10fdx) {
13834978Sgd78059 anar |= MII_ABILITY_10BASE_T_FD;
13844978Sgd78059 cnt++;
13854978Sgd78059 }
13864978Sgd78059 if (mxfep->mxfe_adv_10hdx) {
13874978Sgd78059 anar |= MII_ABILITY_10BASE_T;
13884978Sgd78059 cnt++;
13894978Sgd78059 }
13904978Sgd78059
13914978Sgd78059 /*
13924978Sgd78059 * Make certain at least one valid link mode is selected.
13934978Sgd78059 */
13944978Sgd78059 if (!cnt) {
13954978Sgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
13964978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
13974978Sgd78059 mxfe_stopphy(mxfep);
13984978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
13994978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
14004978Sgd78059 mxfe_reportlink(mxfep);
14014978Sgd78059 return;
14024978Sgd78059 }
14034978Sgd78059
14044978Sgd78059 if ((mxfep->mxfe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) {
14054978Sgd78059 DBG(DPHY, "using autoneg mode");
14064978Sgd78059 bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
14074978Sgd78059 } else {
14084978Sgd78059 DBG(DPHY, "using forced mode");
14094978Sgd78059 if (mxfep->mxfe_adv_100fdx) {
14104978Sgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
14114978Sgd78059 } else if (mxfep->mxfe_adv_100hdx) {
14124978Sgd78059 bmcr = MII_CONTROL_100MB;
14134978Sgd78059 } else if (mxfep->mxfe_adv_10fdx) {
14144978Sgd78059 bmcr = MII_CONTROL_FDUPLEX;
14154978Sgd78059 } else {
14164978Sgd78059 /* 10HDX */
14174978Sgd78059 bmcr = 0;
14184978Sgd78059 }
14194978Sgd78059 }
14204978Sgd78059
14214978Sgd78059 DBG(DPHY, "programming anar to 0x%x", anar);
14224978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_AN_ADVERT, anar);
14234978Sgd78059 DBG(DPHY, "programming bmcr to 0x%x", bmcr);
14244978Sgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, bmcr);
14254978Sgd78059
14264978Sgd78059 /*
14274978Sgd78059 * schedule a query of the link status
14284978Sgd78059 */
14294978Sgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
14304978Sgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC));
14314978Sgd78059 }
14324978Sgd78059
14334978Sgd78059 void
mxfe_reportlink(mxfe_t * mxfep)14344978Sgd78059 mxfe_reportlink(mxfe_t *mxfep)
14354978Sgd78059 {
14364978Sgd78059 int changed = 0;
14374978Sgd78059
14384978Sgd78059 if (mxfep->mxfe_ifspeed != mxfep->mxfe_lastifspeed) {
14394978Sgd78059 mxfep->mxfe_lastifspeed = mxfep->mxfe_ifspeed;
14404978Sgd78059 changed++;
14414978Sgd78059 }
14424978Sgd78059 if (mxfep->mxfe_duplex != mxfep->mxfe_lastduplex) {
14434978Sgd78059 mxfep->mxfe_lastduplex = mxfep->mxfe_duplex;
14444978Sgd78059 changed++;
14454978Sgd78059 }
14464978Sgd78059 if (mxfep->mxfe_linkup != mxfep->mxfe_lastlinkup) {
14474978Sgd78059 mxfep->mxfe_lastlinkup = mxfep->mxfe_linkup;
14484978Sgd78059 changed++;
14494978Sgd78059 }
14504978Sgd78059 if (changed)
14514978Sgd78059 mac_link_update(mxfep->mxfe_mh, mxfep->mxfe_linkup);
14524978Sgd78059 }
14534978Sgd78059
14544978Sgd78059 void
mxfe_checklink(mxfe_t * mxfep)14554978Sgd78059 mxfe_checklink(mxfe_t *mxfep)
14564978Sgd78059 {
14574978Sgd78059 if ((mxfep->mxfe_flags & MXFE_RUNNING) == 0)
14584978Sgd78059 return;
14594978Sgd78059
14604978Sgd78059 if ((mxfep->mxfe_txstall_time != 0) &&
14614978Sgd78059 (gethrtime() > mxfep->mxfe_txstall_time) &&
14624978Sgd78059 (mxfep->mxfe_txavail != MXFE_TXRING)) {
14634978Sgd78059 mxfep->mxfe_txstall_time = 0;
14644978Sgd78059 mxfe_error(mxfep->mxfe_dip, "TX stall detected!");
14654978Sgd78059 mxfe_resetall(mxfep);
14664978Sgd78059 return;
14674978Sgd78059 }
14684978Sgd78059
14694978Sgd78059 switch (MXFE_MODEL(mxfep)) {
14704978Sgd78059 case MXFE_98713A:
14714978Sgd78059 mxfe_checklinkmii(mxfep);
14724978Sgd78059 break;
14734978Sgd78059 default:
14744978Sgd78059 mxfe_checklinknway(mxfep);
14754978Sgd78059 }
14764978Sgd78059 }
14774978Sgd78059
14784978Sgd78059 void
mxfe_checklinkmii(mxfe_t * mxfep)14794978Sgd78059 mxfe_checklinkmii(mxfe_t *mxfep)
14804978Sgd78059 {
14814978Sgd78059 /* read MII state registers */
14824978Sgd78059 uint16_t bmsr;
14834978Sgd78059 uint16_t bmcr;
14844978Sgd78059 uint16_t anar;
14854978Sgd78059 uint16_t anlpar;
14864978Sgd78059 uint16_t aner;
14874978Sgd78059
14884978Sgd78059 /* read this twice, to clear latched link state */
14894978Sgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
14904978Sgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
14914978Sgd78059 bmcr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL);
14924978Sgd78059 anar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_ADVERT);
14934978Sgd78059 anlpar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_LPABLE);
14944978Sgd78059 aner = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_EXPANSION);
14954978Sgd78059
14964978Sgd78059 mxfep->mxfe_bmsr = bmsr;
14974978Sgd78059 mxfep->mxfe_anlpar = anlpar;
14984978Sgd78059 mxfep->mxfe_aner = aner;
14994978Sgd78059
15004978Sgd78059 if (bmsr & MII_STATUS_REMFAULT) {
15014978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Remote fault detected.");
15024978Sgd78059 }
15034978Sgd78059 if (bmsr & MII_STATUS_JABBERING) {
15044978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Jabber condition detected.");
15054978Sgd78059 }
15064978Sgd78059 if ((bmsr & MII_STATUS_LINKUP) == 0) {
15074978Sgd78059 /* no link */
15084978Sgd78059 mxfep->mxfe_ifspeed = 0;
15094978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15104978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
15114978Sgd78059 mxfe_reportlink(mxfep);
15124978Sgd78059 return;
15134978Sgd78059 }
15144978Sgd78059
15154978Sgd78059 DBG(DCHATTY, "link up!");
15164978Sgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
15174978Sgd78059
15184978Sgd78059 if (!(bmcr & MII_CONTROL_ANE)) {
15194978Sgd78059 /* forced mode */
15204978Sgd78059 if (bmcr & MII_CONTROL_100MB) {
15214978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
15224978Sgd78059 } else {
15234978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
15244978Sgd78059 }
15254978Sgd78059 if (bmcr & MII_CONTROL_FDUPLEX) {
15264978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15274978Sgd78059 } else {
15284978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15294978Sgd78059 }
15304978Sgd78059 } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
15314978Sgd78059 (!(bmsr & MII_STATUS_ANDONE))) {
15324978Sgd78059 mxfep->mxfe_ifspeed = 0;
15334978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15344978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
15354978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
15364978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15374978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
15384978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
15394978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15404978Sgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
15414978Sgd78059 mxfep->mxfe_ifspeed = 100000000;
15424978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15434978Sgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
15444978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
15454978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15464978Sgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T) {
15474978Sgd78059 mxfep->mxfe_ifspeed = 10000000;
15484978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15494978Sgd78059 } else {
15504978Sgd78059 mxfep->mxfe_ifspeed = 0;
15514978Sgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15524978Sgd78059 }
15534978Sgd78059
15544978Sgd78059 mxfe_reportlink(mxfep);
15554978Sgd78059 }
15564978Sgd78059
15574978Sgd78059 void
mxfe_miitristate(mxfe_t * mxfep)15584978Sgd78059 mxfe_miitristate(mxfe_t *mxfep)
15594978Sgd78059 {
15604978Sgd78059 unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL;
15614978Sgd78059 PUTCSR(mxfep, CSR_SPR, val);
15624978Sgd78059 drv_usecwait(1);
15634978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15644978Sgd78059 drv_usecwait(1);
15654978Sgd78059 }
15664978Sgd78059
15674978Sgd78059 void
mxfe_miiwritebit(mxfe_t * mxfep,uint8_t bit)15686684Sgd78059 mxfe_miiwritebit(mxfe_t *mxfep, uint8_t bit)
15694978Sgd78059 {
15704978Sgd78059 unsigned val = bit ? SPR_MII_DOUT : 0;
15714978Sgd78059 PUTCSR(mxfep, CSR_SPR, val);
15724978Sgd78059 drv_usecwait(1);
15734978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15744978Sgd78059 drv_usecwait(1);
15754978Sgd78059 }
15764978Sgd78059
15776684Sgd78059 uint8_t
mxfe_miireadbit(mxfe_t * mxfep)15784978Sgd78059 mxfe_miireadbit(mxfe_t *mxfep)
15794978Sgd78059 {
15804978Sgd78059 unsigned val = SPR_MII_CTRL | SPR_SROM_READ;
15816684Sgd78059 uint8_t bit;
15824978Sgd78059 PUTCSR(mxfep, CSR_SPR, val);
15834978Sgd78059 drv_usecwait(1);
15844978Sgd78059 bit = (GETCSR(mxfep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0;
15854978Sgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15864978Sgd78059 drv_usecwait(1);
15874978Sgd78059 return (bit);
15884978Sgd78059 }
15894978Sgd78059
15906684Sgd78059 uint16_t
mxfe_miiread(mxfe_t * mxfep,int phy,int reg)15914978Sgd78059 mxfe_miiread(mxfe_t *mxfep, int phy, int reg)
15924978Sgd78059 {
15934978Sgd78059 switch (MXFE_MODEL(mxfep)) {
15944978Sgd78059 case MXFE_98713A:
15954978Sgd78059 return (mxfe_miiread98713(mxfep, phy, reg));
15964978Sgd78059 default:
15974978Sgd78059 return (0xffff);
15984978Sgd78059 }
15994978Sgd78059 }
16004978Sgd78059
16016684Sgd78059 uint16_t
mxfe_miireadgeneral(mxfe_t * mxfep,int phy,int reg)16024978Sgd78059 mxfe_miireadgeneral(mxfe_t *mxfep, int phy, int reg)
16034978Sgd78059 {
16046684Sgd78059 uint16_t value = 0;
16054978Sgd78059 int i;
16064978Sgd78059
16074978Sgd78059 /* send the 32 bit preamble */
16084978Sgd78059 for (i = 0; i < 32; i++) {
16094978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16104978Sgd78059 }
16114978Sgd78059
16124978Sgd78059 /* send the start code - 01b */
16134978Sgd78059 mxfe_miiwritebit(mxfep, 0);
16144978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16154978Sgd78059
16164978Sgd78059 /* send the opcode for read, - 10b */
16174978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16184978Sgd78059 mxfe_miiwritebit(mxfep, 0);
16194978Sgd78059
16204978Sgd78059 /* next we send the 5 bit phy address */
16214978Sgd78059 for (i = 0x10; i > 0; i >>= 1) {
16224978Sgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
16234978Sgd78059 }
16244978Sgd78059
16254978Sgd78059 /* the 5 bit register address goes next */
16264978Sgd78059 for (i = 0x10; i > 0; i >>= 1) {
16274978Sgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
16284978Sgd78059 }
16294978Sgd78059
16304978Sgd78059 /* turnaround - tristate followed by logic 0 */
16314978Sgd78059 mxfe_miitristate(mxfep);
16324978Sgd78059 mxfe_miiwritebit(mxfep, 0);
16334978Sgd78059
16344978Sgd78059 /* read the 16 bit register value */
16354978Sgd78059 for (i = 0x8000; i > 0; i >>= 1) {
16364978Sgd78059 value <<= 1;
16374978Sgd78059 value |= mxfe_miireadbit(mxfep);
16384978Sgd78059 }
16394978Sgd78059 mxfe_miitristate(mxfep);
16404978Sgd78059 return (value);
16414978Sgd78059 }
16424978Sgd78059
16436684Sgd78059 uint16_t
mxfe_miiread98713(mxfe_t * mxfep,int phy,int reg)16444978Sgd78059 mxfe_miiread98713(mxfe_t *mxfep, int phy, int reg)
16454978Sgd78059 {
16464978Sgd78059 unsigned nar;
16476684Sgd78059 uint16_t retval;
16484978Sgd78059 /*
16494978Sgd78059 * like an ordinary MII, but we have to turn off portsel while
16504978Sgd78059 * we read it.
16514978Sgd78059 */
16524978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
16534978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
16544978Sgd78059 retval = mxfe_miireadgeneral(mxfep, phy, reg);
16554978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
16564978Sgd78059 return (retval);
16574978Sgd78059 }
16584978Sgd78059
16594978Sgd78059 void
mxfe_miiwrite(mxfe_t * mxfep,int phy,int reg,uint16_t val)16604978Sgd78059 mxfe_miiwrite(mxfe_t *mxfep, int phy, int reg, uint16_t val)
16614978Sgd78059 {
16624978Sgd78059 switch (MXFE_MODEL(mxfep)) {
16634978Sgd78059 case MXFE_98713A:
16644978Sgd78059 mxfe_miiwrite98713(mxfep, phy, reg, val);
16654978Sgd78059 break;
16664978Sgd78059 default:
16674978Sgd78059 break;
16684978Sgd78059 }
16694978Sgd78059 }
16704978Sgd78059
16714978Sgd78059 void
mxfe_miiwritegeneral(mxfe_t * mxfep,int phy,int reg,uint16_t val)16724978Sgd78059 mxfe_miiwritegeneral(mxfe_t *mxfep, int phy, int reg, uint16_t val)
16734978Sgd78059 {
16744978Sgd78059 int i;
16754978Sgd78059
16764978Sgd78059 /* send the 32 bit preamble */
16774978Sgd78059 for (i = 0; i < 32; i++) {
16784978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16794978Sgd78059 }
16804978Sgd78059
16814978Sgd78059 /* send the start code - 01b */
16824978Sgd78059 mxfe_miiwritebit(mxfep, 0);
16834978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16844978Sgd78059
16854978Sgd78059 /* send the opcode for write, - 01b */
16864978Sgd78059 mxfe_miiwritebit(mxfep, 0);
16874978Sgd78059 mxfe_miiwritebit(mxfep, 1);
16884978Sgd78059
16894978Sgd78059 /* next we send the 5 bit phy address */
16904978Sgd78059 for (i = 0x10; i > 0; i >>= 1) {
16914978Sgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
16924978Sgd78059 }
16934978Sgd78059
16944978Sgd78059 /* the 5 bit register address goes next */
16954978Sgd78059 for (i = 0x10; i > 0; i >>= 1) {
16964978Sgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
16974978Sgd78059 }
16984978Sgd78059
16994978Sgd78059 /* turnaround - tristate followed by logic 0 */
17004978Sgd78059 mxfe_miitristate(mxfep);
17014978Sgd78059 mxfe_miiwritebit(mxfep, 0);
17024978Sgd78059
17034978Sgd78059 /* now write out our data (16 bits) */
17044978Sgd78059 for (i = 0x8000; i > 0; i >>= 1) {
17054978Sgd78059 mxfe_miiwritebit(mxfep, (val & i) ? 1 : 0);
17064978Sgd78059 }
17074978Sgd78059
17084978Sgd78059 /* idle mode */
17094978Sgd78059 mxfe_miitristate(mxfep);
17104978Sgd78059 }
17114978Sgd78059
17124978Sgd78059 void
mxfe_miiwrite98713(mxfe_t * mxfep,int phy,int reg,uint16_t val)17134978Sgd78059 mxfe_miiwrite98713(mxfe_t *mxfep, int phy, int reg, uint16_t val)
17144978Sgd78059 {
17154978Sgd78059 unsigned nar;
17164978Sgd78059 /*
17174978Sgd78059 * like an ordinary MII, but we have to turn off portsel while
17184978Sgd78059 * we read it.
17194978Sgd78059 */
17204978Sgd78059 nar = GETCSR(mxfep, CSR_NAR);
17214978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
17224978Sgd78059 mxfe_miiwritegeneral(mxfep, phy, reg, val);
17234978Sgd78059 PUTCSR(mxfep, CSR_NAR, nar);
17244978Sgd78059 }
17254978Sgd78059
17264978Sgd78059 int
mxfe_m_start(void * arg)17274978Sgd78059 mxfe_m_start(void *arg)
17284978Sgd78059 {
17294978Sgd78059 mxfe_t *mxfep = arg;
17304978Sgd78059
17314978Sgd78059 /* grab exclusive access to the card */
17324978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
17334978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
17344978Sgd78059
17354978Sgd78059 mxfe_startall(mxfep);
17364978Sgd78059 mxfep->mxfe_flags |= MXFE_RUNNING;
17374978Sgd78059
17384978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
17394978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
17404978Sgd78059 return (0);
17414978Sgd78059 }
17424978Sgd78059
17434978Sgd78059 void
mxfe_m_stop(void * arg)17444978Sgd78059 mxfe_m_stop(void *arg)
17454978Sgd78059 {
17464978Sgd78059 mxfe_t *mxfep = arg;
17474978Sgd78059
17484978Sgd78059 /* exclusive access to the hardware! */
17494978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
17504978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
17514978Sgd78059
17524978Sgd78059 mxfe_stopall(mxfep);
17534978Sgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING;
17544978Sgd78059
17554978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
17564978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
17574978Sgd78059 }
17584978Sgd78059
17594978Sgd78059 void
mxfe_startmac(mxfe_t * mxfep)17604978Sgd78059 mxfe_startmac(mxfe_t *mxfep)
17614978Sgd78059 {
17624978Sgd78059 /* verify exclusive access to the card */
17634978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
17644978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
17654978Sgd78059
17664978Sgd78059 /* start the card */
17674978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
17684978Sgd78059
17694978Sgd78059 if (mxfep->mxfe_txavail != MXFE_TXRING)
17704978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0);
17714978Sgd78059
17724978Sgd78059 /* tell the mac that we are ready to go! */
17734978Sgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
17744978Sgd78059 mac_tx_update(mxfep->mxfe_mh);
17754978Sgd78059 }
17764978Sgd78059
17774978Sgd78059 void
mxfe_stopmac(mxfe_t * mxfep)17784978Sgd78059 mxfe_stopmac(mxfe_t *mxfep)
17794978Sgd78059 {
17804978Sgd78059 int i;
17814978Sgd78059
17824978Sgd78059 /* exclusive access to the hardware! */
17834978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
17844978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
17854978Sgd78059
17864978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
17874978Sgd78059
17884978Sgd78059 /*
17894978Sgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
17904978Sgd78059 * We just add up to the nearest msec (2), which should be
17914978Sgd78059 * plenty to complete.
17924978Sgd78059 *
17934978Sgd78059 * Note that some chips never seem to indicate the transition to
17944978Sgd78059 * the stopped state properly. Experience shows that we can safely
17954978Sgd78059 * proceed anyway, after waiting the requisite timeout.
17964978Sgd78059 */
17974978Sgd78059 for (i = 2000; i != 0; i -= 10) {
17984978Sgd78059 if ((GETCSR(mxfep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
17994978Sgd78059 break;
18004978Sgd78059 drv_usecwait(10);
18014978Sgd78059 }
18024978Sgd78059
18034978Sgd78059 /* prevent an interrupt */
18044978Sgd78059 PUTCSR(mxfep, CSR_SR, INT_RXSTOPPED | INT_TXSTOPPED);
18054978Sgd78059 }
18064978Sgd78059
18074978Sgd78059 void
mxfe_resetrings(mxfe_t * mxfep)18084978Sgd78059 mxfe_resetrings(mxfe_t *mxfep)
18094978Sgd78059 {
18104978Sgd78059 int i;
18114978Sgd78059
18124978Sgd78059 /* now we need to reset the pointers... */
18134978Sgd78059 PUTCSR(mxfep, CSR_RDB, 0);
18144978Sgd78059 PUTCSR(mxfep, CSR_TDB, 0);
18154978Sgd78059
18164978Sgd78059 /* reset the descriptor ring pointers */
18174978Sgd78059 mxfep->mxfe_rxhead = 0;
18184978Sgd78059 mxfep->mxfe_txreclaim = 0;
18194978Sgd78059 mxfep->mxfe_txsend = 0;
18204978Sgd78059 mxfep->mxfe_txavail = MXFE_TXRING;
18214978Sgd78059
18224978Sgd78059 /* set up transmit descriptor ring */
18234978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) {
18244978Sgd78059 mxfe_desc_t *tmdp = &mxfep->mxfe_txdescp[i];
18254978Sgd78059 unsigned control = 0;
18264978Sgd78059 if (i == (MXFE_TXRING - 1)) {
18274978Sgd78059 control |= TXCTL_ENDRING;
18284978Sgd78059 }
18294978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_status, 0);
18304978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_control, control);
18314978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, 0);
18324978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
18334978Sgd78059 SYNCTXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
18344978Sgd78059 }
18354978Sgd78059 PUTCSR(mxfep, CSR_TDB, mxfep->mxfe_txdesc_paddr);
18364978Sgd78059
18374978Sgd78059 /* make the receive buffers available */
18384978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) {
18394978Sgd78059 mxfe_rxbuf_t *rxb = mxfep->mxfe_rxbufs[i];
18404978Sgd78059 mxfe_desc_t *rmdp = &mxfep->mxfe_rxdescp[i];
18414978Sgd78059 unsigned control;
18424978Sgd78059
18434978Sgd78059 control = MXFE_BUFSZ & RXCTL_BUFLEN1;
18444978Sgd78059 if (i == (MXFE_RXRING - 1)) {
18454978Sgd78059 control |= RXCTL_ENDRING;
18464978Sgd78059 }
18474978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer1, rxb->rxb_paddr);
18484978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer2, 0);
18494978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_control, control);
18504978Sgd78059 PUTRXDESC(mxfep, rmdp->desc_status, RXSTAT_OWN);
18514978Sgd78059 SYNCRXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
18524978Sgd78059 }
18534978Sgd78059 PUTCSR(mxfep, CSR_RDB, mxfep->mxfe_rxdesc_paddr);
18544978Sgd78059 }
18554978Sgd78059
18564978Sgd78059 void
mxfe_stopall(mxfe_t * mxfep)18574978Sgd78059 mxfe_stopall(mxfe_t *mxfep)
18584978Sgd78059 {
18594978Sgd78059 mxfe_disableinterrupts(mxfep);
18604978Sgd78059
18614978Sgd78059 mxfe_stopmac(mxfep);
18624978Sgd78059
18634978Sgd78059 /* stop the phy */
18644978Sgd78059 mxfe_stopphy(mxfep);
18654978Sgd78059 }
18664978Sgd78059
18674978Sgd78059 void
mxfe_startall(mxfe_t * mxfep)18684978Sgd78059 mxfe_startall(mxfe_t *mxfep)
18694978Sgd78059 {
18704978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
18714978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
18724978Sgd78059
18734978Sgd78059 /* make sure interrupts are disabled to begin */
18744978Sgd78059 mxfe_disableinterrupts(mxfep);
18754978Sgd78059
18764978Sgd78059 /* initialize the chip */
18774978Sgd78059 (void) mxfe_initialize(mxfep);
18784978Sgd78059
18794978Sgd78059 /* now we can enable interrupts */
18804978Sgd78059 mxfe_enableinterrupts(mxfep);
18814978Sgd78059
18824978Sgd78059 /* start up the phy */
18834978Sgd78059 mxfe_startphy(mxfep);
18844978Sgd78059
18854978Sgd78059 /* start up the mac */
18864978Sgd78059 mxfe_startmac(mxfep);
18874978Sgd78059 }
18884978Sgd78059
18894978Sgd78059 void
mxfe_resetall(mxfe_t * mxfep)18904978Sgd78059 mxfe_resetall(mxfe_t *mxfep)
18914978Sgd78059 {
18924978Sgd78059 mxfep->mxfe_resetting = B_TRUE;
18934978Sgd78059 mxfe_stopall(mxfep);
18944978Sgd78059 mxfep->mxfe_resetting = B_FALSE;
18954978Sgd78059 mxfe_startall(mxfep);
18964978Sgd78059 }
18974978Sgd78059
18984978Sgd78059 mxfe_txbuf_t *
mxfe_alloctxbuf(mxfe_t * mxfep)18994978Sgd78059 mxfe_alloctxbuf(mxfe_t *mxfep)
19004978Sgd78059 {
19014978Sgd78059 ddi_dma_cookie_t dmac;
19024978Sgd78059 unsigned ncookies;
19034978Sgd78059 mxfe_txbuf_t *txb;
19044978Sgd78059 size_t len;
19054978Sgd78059
19064978Sgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP);
19074978Sgd78059
19084978Sgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_txattr,
19094978Sgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) {
19104978Sgd78059 return (NULL);
19114978Sgd78059 }
19124978Sgd78059
19134978Sgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
19144978Sgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf,
19154978Sgd78059 &len, &txb->txb_acch) != DDI_SUCCESS) {
19164978Sgd78059 return (NULL);
19174978Sgd78059 }
19184978Sgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
19194978Sgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
19204978Sgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) {
19214978Sgd78059 return (NULL);
19224978Sgd78059 }
19234978Sgd78059 txb->txb_paddr = dmac.dmac_address;
19244978Sgd78059
19254978Sgd78059 return (txb);
19264978Sgd78059 }
19274978Sgd78059
19284978Sgd78059 void
mxfe_destroytxbuf(mxfe_txbuf_t * txb)19294978Sgd78059 mxfe_destroytxbuf(mxfe_txbuf_t *txb)
19304978Sgd78059 {
19314978Sgd78059 if (txb != NULL) {
19324978Sgd78059 if (txb->txb_paddr)
19334978Sgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah);
19344978Sgd78059 if (txb->txb_acch)
19354978Sgd78059 ddi_dma_mem_free(&txb->txb_acch);
19364978Sgd78059 if (txb->txb_dmah)
19374978Sgd78059 ddi_dma_free_handle(&txb->txb_dmah);
19384978Sgd78059 kmem_free(txb, sizeof (*txb));
19394978Sgd78059 }
19404978Sgd78059 }
19414978Sgd78059
19424978Sgd78059 mxfe_rxbuf_t *
mxfe_allocrxbuf(mxfe_t * mxfep)19434978Sgd78059 mxfe_allocrxbuf(mxfe_t *mxfep)
19444978Sgd78059 {
19454978Sgd78059 mxfe_rxbuf_t *rxb;
19464978Sgd78059 size_t len;
19474978Sgd78059 unsigned ccnt;
19484978Sgd78059 ddi_dma_cookie_t dmac;
19494978Sgd78059
19504978Sgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP);
19514978Sgd78059
19524978Sgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
19534978Sgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) {
19544978Sgd78059 kmem_free(rxb, sizeof (*rxb));
19554978Sgd78059 return (NULL);
19564978Sgd78059 }
19574978Sgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
19584978Sgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
19594978Sgd78059 &rxb->rxb_buf, &len, &rxb->rxb_acch) != DDI_SUCCESS) {
19604978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
19614978Sgd78059 kmem_free(rxb, sizeof (*rxb));
19624978Sgd78059 return (NULL);
19634978Sgd78059 }
19644978Sgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
19654978Sgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
19664978Sgd78059 &ccnt) != DDI_DMA_MAPPED) {
19674978Sgd78059 ddi_dma_mem_free(&rxb->rxb_acch);
19684978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
19694978Sgd78059 kmem_free(rxb, sizeof (*rxb));
19704978Sgd78059 return (NULL);
19714978Sgd78059 }
19724978Sgd78059 rxb->rxb_paddr = dmac.dmac_address;
19734978Sgd78059
19744978Sgd78059 return (rxb);
19754978Sgd78059 }
19764978Sgd78059
19774978Sgd78059 void
mxfe_destroyrxbuf(mxfe_rxbuf_t * rxb)19784978Sgd78059 mxfe_destroyrxbuf(mxfe_rxbuf_t *rxb)
19794978Sgd78059 {
19804978Sgd78059 if (rxb != NULL) {
19814978Sgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah);
19824978Sgd78059 ddi_dma_mem_free(&rxb->rxb_acch);
19834978Sgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
19844978Sgd78059 kmem_free(rxb, sizeof (*rxb));
19854978Sgd78059 }
19864978Sgd78059 }
19874978Sgd78059
19884978Sgd78059 /*
19894978Sgd78059 * Allocate receive resources.
19904978Sgd78059 */
19914978Sgd78059 int
mxfe_allocrxring(mxfe_t * mxfep)19924978Sgd78059 mxfe_allocrxring(mxfe_t *mxfep)
19934978Sgd78059 {
19944978Sgd78059 int rval;
19954978Sgd78059 int i;
19964978Sgd78059 size_t size;
19974978Sgd78059 size_t len;
19984978Sgd78059 ddi_dma_cookie_t dmac;
19994978Sgd78059 unsigned ncookies;
20004978Sgd78059 caddr_t kaddr;
20014978Sgd78059
20024978Sgd78059 size = MXFE_RXRING * sizeof (mxfe_desc_t);
20034978Sgd78059
20044978Sgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
20054978Sgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_rxdesc_dmah);
20064978Sgd78059 if (rval != DDI_SUCCESS) {
20074978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20084978Sgd78059 "unable to allocate DMA handle for rx descriptors");
20094978Sgd78059 return (DDI_FAILURE);
20104978Sgd78059 }
20114978Sgd78059
20124978Sgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_rxdesc_dmah, size, &mxfe_devattr,
20134978Sgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
20144978Sgd78059 &mxfep->mxfe_rxdesc_acch);
20154978Sgd78059 if (rval != DDI_SUCCESS) {
20164978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20174978Sgd78059 "unable to allocate DMA memory for rx descriptors");
20184978Sgd78059 return (DDI_FAILURE);
20194978Sgd78059 }
20204978Sgd78059
20214978Sgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_rxdesc_dmah, NULL, kaddr,
20224978Sgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
20234978Sgd78059 &dmac, &ncookies);
20244978Sgd78059 if (rval != DDI_DMA_MAPPED) {
20254978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20264978Sgd78059 "unable to bind DMA for rx descriptors");
20274978Sgd78059 return (DDI_FAILURE);
20284978Sgd78059 }
20294978Sgd78059
20304978Sgd78059 /* because of mxfe_dma_attr */
20314978Sgd78059 ASSERT(ncookies == 1);
20324978Sgd78059
20334978Sgd78059 /* we take the 32-bit physical address out of the cookie */
20344978Sgd78059 mxfep->mxfe_rxdesc_paddr = dmac.dmac_address;
20354978Sgd78059 mxfep->mxfe_rxdescp = (void *)kaddr;
20364978Sgd78059
20374978Sgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */
20384978Sgd78059 mxfep->mxfe_rxbufs = kmem_zalloc(MXFE_RXRING * sizeof (mxfe_rxbuf_t *),
20394978Sgd78059 KM_SLEEP);
20404978Sgd78059
20414978Sgd78059 /* now allocate rx buffers */
20424978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) {
20434978Sgd78059 mxfe_rxbuf_t *rxb = mxfe_allocrxbuf(mxfep);
20444978Sgd78059 if (rxb == NULL)
20454978Sgd78059 return (DDI_FAILURE);
20464978Sgd78059 mxfep->mxfe_rxbufs[i] = rxb;
20474978Sgd78059 }
20484978Sgd78059
20494978Sgd78059 return (DDI_SUCCESS);
20504978Sgd78059 }
20514978Sgd78059
20524978Sgd78059 /*
20534978Sgd78059 * Allocate transmit resources.
20544978Sgd78059 */
20554978Sgd78059 int
mxfe_alloctxring(mxfe_t * mxfep)20564978Sgd78059 mxfe_alloctxring(mxfe_t *mxfep)
20574978Sgd78059 {
20584978Sgd78059 int rval;
20594978Sgd78059 int i;
20604978Sgd78059 size_t size;
20614978Sgd78059 size_t len;
20624978Sgd78059 ddi_dma_cookie_t dmac;
20634978Sgd78059 unsigned ncookies;
20644978Sgd78059 caddr_t kaddr;
20654978Sgd78059
20664978Sgd78059 size = MXFE_TXRING * sizeof (mxfe_desc_t);
20674978Sgd78059
20684978Sgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
20694978Sgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_txdesc_dmah);
20704978Sgd78059 if (rval != DDI_SUCCESS) {
20714978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20724978Sgd78059 "unable to allocate DMA handle for tx descriptors");
20734978Sgd78059 return (DDI_FAILURE);
20744978Sgd78059 }
20754978Sgd78059
20764978Sgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_txdesc_dmah, size, &mxfe_devattr,
20774978Sgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
20784978Sgd78059 &mxfep->mxfe_txdesc_acch);
20794978Sgd78059 if (rval != DDI_SUCCESS) {
20804978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20814978Sgd78059 "unable to allocate DMA memory for tx descriptors");
20824978Sgd78059 return (DDI_FAILURE);
20834978Sgd78059 }
20844978Sgd78059
20854978Sgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_txdesc_dmah, NULL, kaddr,
20864978Sgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
20874978Sgd78059 &dmac, &ncookies);
20884978Sgd78059 if (rval != DDI_DMA_MAPPED) {
20894978Sgd78059 mxfe_error(mxfep->mxfe_dip,
20904978Sgd78059 "unable to bind DMA for tx descriptors");
20914978Sgd78059 return (DDI_FAILURE);
20924978Sgd78059 }
20934978Sgd78059
20944978Sgd78059 /* because of mxfe_dma_attr */
20954978Sgd78059 ASSERT(ncookies == 1);
20964978Sgd78059
20974978Sgd78059 /* we take the 32-bit physical address out of the cookie */
20984978Sgd78059 mxfep->mxfe_txdesc_paddr = dmac.dmac_address;
20994978Sgd78059 mxfep->mxfe_txdescp = (void *)kaddr;
21004978Sgd78059
21014978Sgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */
21024978Sgd78059 mxfep->mxfe_txbufs = kmem_zalloc(MXFE_TXRING * sizeof (mxfe_txbuf_t *),
21034978Sgd78059 KM_SLEEP);
21044978Sgd78059
21054978Sgd78059 /* now allocate tx buffers */
21064978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) {
21074978Sgd78059 mxfe_txbuf_t *txb = mxfe_alloctxbuf(mxfep);
21084978Sgd78059 if (txb == NULL)
21094978Sgd78059 return (DDI_FAILURE);
21104978Sgd78059 /* stick it in the stack */
21114978Sgd78059 mxfep->mxfe_txbufs[i] = txb;
21124978Sgd78059 }
21134978Sgd78059
21144978Sgd78059 return (DDI_SUCCESS);
21154978Sgd78059 }
21164978Sgd78059
21174978Sgd78059 void
mxfe_freerxring(mxfe_t * mxfep)21184978Sgd78059 mxfe_freerxring(mxfe_t *mxfep)
21194978Sgd78059 {
21204978Sgd78059 int i;
21214978Sgd78059
21224978Sgd78059 for (i = 0; i < MXFE_RXRING; i++) {
21234978Sgd78059 mxfe_destroyrxbuf(mxfep->mxfe_rxbufs[i]);
21244978Sgd78059 }
21254978Sgd78059
21264978Sgd78059 if (mxfep->mxfe_rxbufs) {
21274978Sgd78059 kmem_free(mxfep->mxfe_rxbufs,
21284978Sgd78059 MXFE_RXRING * sizeof (mxfe_rxbuf_t *));
21294978Sgd78059 }
21304978Sgd78059
21314978Sgd78059 if (mxfep->mxfe_rxdesc_paddr)
21324978Sgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_rxdesc_dmah);
21334978Sgd78059 if (mxfep->mxfe_rxdesc_acch)
21344978Sgd78059 ddi_dma_mem_free(&mxfep->mxfe_rxdesc_acch);
21354978Sgd78059 if (mxfep->mxfe_rxdesc_dmah)
21364978Sgd78059 ddi_dma_free_handle(&mxfep->mxfe_rxdesc_dmah);
21374978Sgd78059 }
21384978Sgd78059
21394978Sgd78059 void
mxfe_freetxring(mxfe_t * mxfep)21404978Sgd78059 mxfe_freetxring(mxfe_t *mxfep)
21414978Sgd78059 {
21424978Sgd78059 int i;
21434978Sgd78059
21444978Sgd78059 for (i = 0; i < MXFE_TXRING; i++) {
21454978Sgd78059 mxfe_destroytxbuf(mxfep->mxfe_txbufs[i]);
21464978Sgd78059 }
21474978Sgd78059
21484978Sgd78059 if (mxfep->mxfe_txbufs) {
21494978Sgd78059 kmem_free(mxfep->mxfe_txbufs,
21504978Sgd78059 MXFE_TXRING * sizeof (mxfe_txbuf_t *));
21514978Sgd78059 }
21524978Sgd78059 if (mxfep->mxfe_txdesc_paddr)
21534978Sgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_txdesc_dmah);
21544978Sgd78059 if (mxfep->mxfe_txdesc_acch)
21554978Sgd78059 ddi_dma_mem_free(&mxfep->mxfe_txdesc_acch);
21564978Sgd78059 if (mxfep->mxfe_txdesc_dmah)
21574978Sgd78059 ddi_dma_free_handle(&mxfep->mxfe_txdesc_dmah);
21584978Sgd78059 }
21594978Sgd78059
21604978Sgd78059 /*
21614978Sgd78059 * Interrupt service routine.
21624978Sgd78059 */
21634978Sgd78059 unsigned
mxfe_intr(caddr_t arg)21644978Sgd78059 mxfe_intr(caddr_t arg)
21654978Sgd78059 {
21664978Sgd78059 mxfe_t *mxfep = (void *)arg;
21674978Sgd78059 uint32_t status;
21684978Sgd78059 mblk_t *mp = NULL;
21699199Sgdamore@opensolaris.org boolean_t error = B_FALSE;
21704978Sgd78059
21714978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
21724978Sgd78059
21734978Sgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
21744978Sgd78059 /* we cannot receive interrupts! */
21754978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
21764978Sgd78059 return (DDI_INTR_UNCLAIMED);
21774978Sgd78059 }
21784978Sgd78059
21794978Sgd78059 /* check interrupt status bits, did we interrupt? */
21804978Sgd78059 status = GETCSR(mxfep, CSR_SR) & INT_ALL;
21814978Sgd78059
21824978Sgd78059 if (status == 0) {
21834978Sgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
21844978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
21854978Sgd78059 return (DDI_INTR_UNCLAIMED);
21864978Sgd78059 }
21874978Sgd78059 /* ack the interrupt */
21884978Sgd78059 PUTCSR(mxfep, CSR_SR, status);
21894978Sgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++;
21904978Sgd78059
21914978Sgd78059 if (!(mxfep->mxfe_flags & MXFE_RUNNING)) {
21924978Sgd78059 /* not running, don't touch anything */
21934978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
21944978Sgd78059 return (DDI_INTR_CLAIMED);
21954978Sgd78059 }
21964978Sgd78059
21974978Sgd78059 if (status & INT_RXOK) {
21984978Sgd78059 /* receive packets */
21999199Sgdamore@opensolaris.org if (mxfe_receive(mxfep, &mp)) {
22009199Sgdamore@opensolaris.org error = B_TRUE;
22019199Sgdamore@opensolaris.org }
22024978Sgd78059 }
22034978Sgd78059
22044978Sgd78059 if (status & INT_TXOK) {
22054978Sgd78059 /* transmit completed */
22064978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
22074978Sgd78059 mxfe_reclaim(mxfep);
22084978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
22094978Sgd78059 }
22104978Sgd78059
22114978Sgd78059 if (((status & (INT_TIMER|INT_ANEG)) != 0) ||
22124978Sgd78059 ((mxfep->mxfe_linkup == LINK_STATE_UP) &&
22134978Sgd78059 ((status & (INT_10LINK|INT_100LINK)) != 0))) {
22144978Sgd78059 /* rescan the link */
22154978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
22164978Sgd78059 mxfe_checklink(mxfep);
22174978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
22184978Sgd78059 }
22194978Sgd78059
22204978Sgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED|INT_RXNOBUF|
22214978Sgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) {
22224978Sgd78059
22234978Sgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) {
22244978Sgd78059 mxfep->mxfe_jabber++;
22254978Sgd78059 }
22269199Sgdamore@opensolaris.org DBG(DWARN, "error interrupt: status %x", status);
22279199Sgdamore@opensolaris.org error = B_TRUE;
22284978Sgd78059 }
22294978Sgd78059
22304978Sgd78059 if (status & INT_BUSERR) {
22314978Sgd78059 switch (status & SR_BERR_TYPE) {
22324978Sgd78059 case SR_BERR_PARITY:
22334978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI parity error");
22344978Sgd78059 break;
22354978Sgd78059 case SR_BERR_TARGET_ABORT:
22364978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI target abort");
22374978Sgd78059 break;
22384978Sgd78059 case SR_BERR_MASTER_ABORT:
22394978Sgd78059 mxfe_error(mxfep->mxfe_dip, "PCI master abort");
22404978Sgd78059 break;
22414978Sgd78059 default:
22424978Sgd78059 mxfe_error(mxfep->mxfe_dip, "Unknown PCI error");
22434978Sgd78059 break;
22444978Sgd78059 }
22454978Sgd78059
22469199Sgdamore@opensolaris.org error = B_TRUE;
22479199Sgdamore@opensolaris.org }
22489199Sgdamore@opensolaris.org
22499199Sgdamore@opensolaris.org if (error) {
22504978Sgd78059 /* reset the chip in an attempt to fix things */
22514978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
22524978Sgd78059 mxfe_resetall(mxfep);
22534978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
22544978Sgd78059 }
22554978Sgd78059
22564978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
22574978Sgd78059
22584978Sgd78059 /*
22594978Sgd78059 * Send up packets. We do this outside of the intrlock.
22604978Sgd78059 */
22614978Sgd78059 if (mp) {
22624978Sgd78059 mac_rx(mxfep->mxfe_mh, NULL, mp);
22634978Sgd78059 }
22644978Sgd78059
22654978Sgd78059 return (DDI_INTR_CLAIMED);
22664978Sgd78059 }
22674978Sgd78059
22684978Sgd78059 void
mxfe_enableinterrupts(mxfe_t * mxfep)22694978Sgd78059 mxfe_enableinterrupts(mxfe_t *mxfep)
22704978Sgd78059 {
22714978Sgd78059 unsigned mask = INT_WANTED;
22724978Sgd78059
22734978Sgd78059 if (mxfep->mxfe_wantw)
22744978Sgd78059 mask |= INT_TXOK;
22754978Sgd78059
22764978Sgd78059 if (MXFE_MODEL(mxfep) != MXFE_98713A)
22774978Sgd78059 mask |= INT_LINKSTATUS;
22784978Sgd78059
22794978Sgd78059 DBG(DINTR, "setting int mask to 0x%x", mask);
22804978Sgd78059 PUTCSR(mxfep, CSR_IER, mask);
22814978Sgd78059 }
22824978Sgd78059
22834978Sgd78059 void
mxfe_disableinterrupts(mxfe_t * mxfep)22844978Sgd78059 mxfe_disableinterrupts(mxfe_t *mxfep)
22854978Sgd78059 {
22864978Sgd78059 /* disable further interrupts */
22874978Sgd78059 PUTCSR(mxfep, CSR_IER, 0);
22884978Sgd78059
22894978Sgd78059 /* clear any pending interrupts */
22904978Sgd78059 PUTCSR(mxfep, CSR_SR, INT_ALL);
22914978Sgd78059 }
22924978Sgd78059
22934978Sgd78059 void
mxfe_send_setup(mxfe_t * mxfep)22944978Sgd78059 mxfe_send_setup(mxfe_t *mxfep)
22954978Sgd78059 {
22964978Sgd78059 mxfe_txbuf_t *txb;
22974978Sgd78059 mxfe_desc_t *tmdp;
22984978Sgd78059
22994978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
23004978Sgd78059
23014978Sgd78059 /* setup frame -- must be at head of list -- guaranteed by caller! */
23024978Sgd78059 ASSERT(mxfep->mxfe_txsend == 0);
23034978Sgd78059
23044978Sgd78059 txb = mxfep->mxfe_txbufs[0];
23054978Sgd78059 tmdp = &mxfep->mxfe_txdescp[0];
23064978Sgd78059
23074978Sgd78059 bzero(txb->txb_buf, MXFE_SETUP_LEN);
23084978Sgd78059
23094978Sgd78059 /* program the unicast address */
23104978Sgd78059 txb->txb_buf[156] = mxfep->mxfe_curraddr[0];
23114978Sgd78059 txb->txb_buf[157] = mxfep->mxfe_curraddr[1];
23124978Sgd78059 txb->txb_buf[160] = mxfep->mxfe_curraddr[2];
23134978Sgd78059 txb->txb_buf[161] = mxfep->mxfe_curraddr[3];
23144978Sgd78059 txb->txb_buf[164] = mxfep->mxfe_curraddr[4];
23154978Sgd78059 txb->txb_buf[165] = mxfep->mxfe_curraddr[5];
23164978Sgd78059
23174978Sgd78059 /* make sure that the hardware can see it */
23184978Sgd78059 SYNCTXBUF(txb, MXFE_SETUP_LEN, DDI_DMA_SYNC_FORDEV);
23194978Sgd78059
23204978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_control,
23214978Sgd78059 TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE | TXCTL_HASHPERF |
23224978Sgd78059 TXCTL_SETUP | MXFE_SETUP_LEN);
23234978Sgd78059
23244978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, txb->txb_paddr);
23254978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
23264978Sgd78059 PUTTXDESC(mxfep, tmdp->desc_status, TXSTAT_OWN);
23274978Sgd78059
23284978Sgd78059 /* sync the descriptor out to the device */
23294978Sgd78059 SYNCTXDESC(mxfep, 0, DDI_DMA_SYNC_FORDEV);
23304978Sgd78059
23314978Sgd78059 /*
23324978Sgd78059 * wake up the chip ... inside the lock to protect against DR suspend,
23334978Sgd78059 * etc.
23344978Sgd78059 */
23354978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0);
23364978Sgd78059 mxfep->mxfe_txsend++;
23374978Sgd78059 mxfep->mxfe_txavail--;
23384978Sgd78059
23394978Sgd78059 /*
23404978Sgd78059 * Program promiscuous mode.
23414978Sgd78059 */
23424978Sgd78059 if (mxfep->mxfe_promisc) {
23434978Sgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
23444978Sgd78059 } else {
23454978Sgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
23464978Sgd78059 }
23474978Sgd78059 }
23484978Sgd78059
23494978Sgd78059 boolean_t
mxfe_send(mxfe_t * mxfep,mblk_t * mp)23504978Sgd78059 mxfe_send(mxfe_t *mxfep, mblk_t *mp)
23514978Sgd78059 {
23524978Sgd78059 size_t len;
23534978Sgd78059 mxfe_txbuf_t *txb;
23544978Sgd78059 mxfe_desc_t *tmd;
23554978Sgd78059 uint32_t control;
23564978Sgd78059 int txsend;
23574978Sgd78059
23584978Sgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
23594978Sgd78059 ASSERT(mp != NULL);
23604978Sgd78059
23614978Sgd78059 len = msgsize(mp);
23624978Sgd78059 if (len > ETHERVLANMTU) {
23634978Sgd78059 DBG(DXMIT, "frame too long: %d", len);
23644978Sgd78059 mxfep->mxfe_macxmt_errors++;
23654978Sgd78059 freemsg(mp);
23664978Sgd78059 return (B_TRUE);
23674978Sgd78059 }
23684978Sgd78059
23694978Sgd78059 if (mxfep->mxfe_txavail < MXFE_TXRECLAIM)
23704978Sgd78059 mxfe_reclaim(mxfep);
23714978Sgd78059
23724978Sgd78059 if (mxfep->mxfe_txavail == 0) {
23734978Sgd78059 /* no more tmds */
23744978Sgd78059 mxfep->mxfe_wantw = B_TRUE;
23754978Sgd78059 /* enable TX interrupt */
23764978Sgd78059 mxfe_enableinterrupts(mxfep);
23774978Sgd78059 return (B_FALSE);
23784978Sgd78059 }
23794978Sgd78059
23804978Sgd78059 txsend = mxfep->mxfe_txsend;
23814978Sgd78059
23824978Sgd78059 /*
23834978Sgd78059 * For simplicity, we just do a copy into a preallocated
23844978Sgd78059 * DMA buffer.
23854978Sgd78059 */
23864978Sgd78059
23874978Sgd78059 txb = mxfep->mxfe_txbufs[txsend];
23884978Sgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */
23894978Sgd78059
23904978Sgd78059 /*
23914978Sgd78059 * Statistics.
23924978Sgd78059 */
23934978Sgd78059 mxfep->mxfe_opackets++;
23944978Sgd78059 mxfep->mxfe_obytes += len;
23954978Sgd78059 if (txb->txb_buf[0] & 0x1) {
23964978Sgd78059 if (bcmp(txb->txb_buf, mxfe_broadcast, ETHERADDRL) != 0)
23974978Sgd78059 mxfep->mxfe_multixmt++;
23984978Sgd78059 else
23994978Sgd78059 mxfep->mxfe_brdcstxmt++;
24004978Sgd78059 }
24014978Sgd78059
24024978Sgd78059 /* note len is already known to be a small unsigned */
24034978Sgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
24044978Sgd78059
24054978Sgd78059 if (txsend == (MXFE_TXRING - 1))
24064978Sgd78059 control |= TXCTL_ENDRING;
24074978Sgd78059
24084978Sgd78059 tmd = &mxfep->mxfe_txdescp[txsend];
24094978Sgd78059
24104978Sgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV);
24114978Sgd78059 PUTTXDESC(mxfep, tmd->desc_control, control);
24124978Sgd78059 PUTTXDESC(mxfep, tmd->desc_buffer1, txb->txb_paddr);
24134978Sgd78059 PUTTXDESC(mxfep, tmd->desc_buffer2, 0);
24144978Sgd78059 PUTTXDESC(mxfep, tmd->desc_status, TXSTAT_OWN);
24154978Sgd78059 /* sync the descriptor out to the device */
24164978Sgd78059 SYNCTXDESC(mxfep, txsend, DDI_DMA_SYNC_FORDEV);
24174978Sgd78059
24184978Sgd78059 /*
24194978Sgd78059 * Note the new values of txavail and txsend.
24204978Sgd78059 */
24214978Sgd78059 mxfep->mxfe_txavail--;
24224978Sgd78059 mxfep->mxfe_txsend = (txsend + 1) % MXFE_TXRING;
24234978Sgd78059
24244978Sgd78059 /*
24254978Sgd78059 * It should never, ever take more than 5 seconds to drain
24264978Sgd78059 * the ring. If it happens, then we are stuck!
24274978Sgd78059 */
24284978Sgd78059 mxfep->mxfe_txstall_time = gethrtime() + (5 * 1000000000ULL);
24294978Sgd78059
24304978Sgd78059 /*
24314978Sgd78059 * wake up the chip ... inside the lock to protect against DR suspend,
24324978Sgd78059 * etc.
24334978Sgd78059 */
24344978Sgd78059 PUTCSR(mxfep, CSR_TDR, 0);
24354978Sgd78059
24364978Sgd78059 return (B_TRUE);
24374978Sgd78059 }
24384978Sgd78059
24394978Sgd78059 /*
24404978Sgd78059 * Reclaim buffers that have completed transmission.
24414978Sgd78059 */
24424978Sgd78059 void
mxfe_reclaim(mxfe_t * mxfep)24434978Sgd78059 mxfe_reclaim(mxfe_t *mxfep)
24444978Sgd78059 {
24454978Sgd78059 mxfe_desc_t *tmdp;
24464978Sgd78059
24474978Sgd78059 while (mxfep->mxfe_txavail != MXFE_TXRING) {
24484978Sgd78059 uint32_t status;
24494978Sgd78059 uint32_t control;
24504978Sgd78059 int index = mxfep->mxfe_txreclaim;
24514978Sgd78059
24524978Sgd78059 tmdp = &mxfep->mxfe_txdescp[index];
24534978Sgd78059
24544978Sgd78059 /* sync it before we read it */
24554978Sgd78059 SYNCTXDESC(mxfep, index, DDI_DMA_SYNC_FORKERNEL);
24564978Sgd78059
24574978Sgd78059 control = GETTXDESC(mxfep, tmdp->desc_control);
24584978Sgd78059 status = GETTXDESC(mxfep, tmdp->desc_status);
24594978Sgd78059
24604978Sgd78059 if (status & TXSTAT_OWN) {
24614978Sgd78059 /* chip is still working on it, we're done */
24624978Sgd78059 break;
24634978Sgd78059 }
24644978Sgd78059
24654978Sgd78059 mxfep->mxfe_txavail++;
24664978Sgd78059 mxfep->mxfe_txreclaim = (index + 1) % MXFE_TXRING;
24674978Sgd78059
24684978Sgd78059 /* in the most common successful case, all bits are clear */
24694978Sgd78059 if (status == 0)
24704978Sgd78059 continue;
24714978Sgd78059
24724978Sgd78059 if (((control & TXCTL_SETUP) != 0) ||
24734978Sgd78059 ((control & TXCTL_LAST) == 0)) {
24744978Sgd78059 /* no interesting statistics here */
24754978Sgd78059 continue;
24764978Sgd78059 }
24774978Sgd78059
24784978Sgd78059 if (status & TXSTAT_TXERR) {
24794978Sgd78059 mxfep->mxfe_errxmt++;
24804978Sgd78059
24814978Sgd78059 if (status & TXSTAT_JABBER) {
24824978Sgd78059 /* transmit jabber timeout */
24834978Sgd78059 mxfep->mxfe_macxmt_errors++;
24844978Sgd78059 }
24854978Sgd78059 if (status & (TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
24864978Sgd78059 mxfep->mxfe_carrier_errors++;
24874978Sgd78059 }
24884978Sgd78059 if (status & TXSTAT_UFLOW) {
24894978Sgd78059 mxfep->mxfe_underflow++;
24904978Sgd78059 }
24914978Sgd78059 if (status & TXSTAT_LATECOL) {
24924978Sgd78059 mxfep->mxfe_tx_late_collisions++;
24934978Sgd78059 }
24944978Sgd78059 if (status & TXSTAT_EXCOLL) {
24954978Sgd78059 mxfep->mxfe_ex_collisions++;
24964978Sgd78059 mxfep->mxfe_collisions += 16;
24974978Sgd78059 }
24984978Sgd78059 }
24994978Sgd78059
25004978Sgd78059 if (status & TXSTAT_DEFER) {
25014978Sgd78059 mxfep->mxfe_defer_xmts++;
25024978Sgd78059 }
25034978Sgd78059
25044978Sgd78059 /* collision counting */
25054978Sgd78059 if (TXCOLLCNT(status) == 1) {
25064978Sgd78059 mxfep->mxfe_collisions++;
25074978Sgd78059 mxfep->mxfe_first_collisions++;
25084978Sgd78059 } else if (TXCOLLCNT(status)) {
25094978Sgd78059 mxfep->mxfe_collisions += TXCOLLCNT(status);
25104978Sgd78059 mxfep->mxfe_multi_collisions += TXCOLLCNT(status);
25114978Sgd78059 }
25124978Sgd78059 }
25134978Sgd78059
25144978Sgd78059 if (mxfep->mxfe_txavail >= MXFE_TXRESCHED) {
25154978Sgd78059 if (mxfep->mxfe_wantw) {
25164978Sgd78059 /*
25174978Sgd78059 * we were able to reclaim some packets, so
25184978Sgd78059 * disable tx interrupts
25194978Sgd78059 */
25204978Sgd78059 mxfep->mxfe_wantw = B_FALSE;
25214978Sgd78059 mxfe_enableinterrupts(mxfep);
25224978Sgd78059 mac_tx_update(mxfep->mxfe_mh);
25234978Sgd78059 }
25244978Sgd78059 }
25254978Sgd78059 }
25264978Sgd78059
25279199Sgdamore@opensolaris.org boolean_t
mxfe_receive(mxfe_t * mxfep,mblk_t ** rxchain)25289199Sgdamore@opensolaris.org mxfe_receive(mxfe_t *mxfep, mblk_t **rxchain)
25294978Sgd78059 {
25304978Sgd78059 unsigned len;
25314978Sgd78059 mxfe_rxbuf_t *rxb;
25324978Sgd78059 mxfe_desc_t *rmd;
25334978Sgd78059 uint32_t status;
25344978Sgd78059 mblk_t *mpchain, **mpp, *mp;
25354978Sgd78059 int head, cnt;
25369199Sgdamore@opensolaris.org boolean_t error = B_FALSE;
25374978Sgd78059
25384978Sgd78059 mpchain = NULL;
25394978Sgd78059 mpp = &mpchain;
25404978Sgd78059 head = mxfep->mxfe_rxhead;
25414978Sgd78059
25424978Sgd78059 /* limit the number of packets we process to a ring size */
25434978Sgd78059 for (cnt = 0; cnt < MXFE_RXRING; cnt++) {
25444978Sgd78059
25454978Sgd78059 DBG(DRECV, "receive at index %d", head);
25464978Sgd78059
25474978Sgd78059 rmd = &mxfep->mxfe_rxdescp[head];
25484978Sgd78059 rxb = mxfep->mxfe_rxbufs[head];
25494978Sgd78059
25504978Sgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORKERNEL);
25514978Sgd78059 status = GETRXDESC(mxfep, rmd->desc_status);
25524978Sgd78059 if (status & RXSTAT_OWN) {
25534978Sgd78059 /* chip is still chewing on it */
25544978Sgd78059 break;
25554978Sgd78059 }
25564978Sgd78059
25574978Sgd78059 /* discard the ethernet frame checksum */
25584978Sgd78059 len = RXLENGTH(status) - ETHERFCSL;
25594978Sgd78059
25604978Sgd78059 DBG(DRECV, "recv length %d, status %x", len, status);
25614978Sgd78059
25624978Sgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
25634978Sgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) {
25644978Sgd78059
25654978Sgd78059 mxfep->mxfe_errrcv++;
25664978Sgd78059
25674978Sgd78059 /*
25684978Sgd78059 * Abnormal status bits detected, analyze further.
25694978Sgd78059 */
25704978Sgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) !=
25714978Sgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) {
25729199Sgdamore@opensolaris.org /* someone trying to send jumbo frames? */
25734978Sgd78059 DBG(DRECV, "rx packet overspill");
25744978Sgd78059 if (status & RXSTAT_FIRST) {
25754978Sgd78059 mxfep->mxfe_toolong_errors++;
25764978Sgd78059 }
25774978Sgd78059 } else if (status & RXSTAT_DESCERR) {
25789199Sgdamore@opensolaris.org /* this should never occur! */
25794978Sgd78059 mxfep->mxfe_macrcv_errors++;
25809199Sgdamore@opensolaris.org error = B_TRUE;
25814978Sgd78059
25824978Sgd78059 } else if (status & RXSTAT_RUNT) {
25834978Sgd78059 mxfep->mxfe_runt++;
25844978Sgd78059
25854978Sgd78059 } else if (status & RXSTAT_COLLSEEN) {
25864978Sgd78059 /* this should really be rx_late_collisions */
25874978Sgd78059 mxfep->mxfe_macrcv_errors++;
25884978Sgd78059
25894978Sgd78059 } else if (status & RXSTAT_DRIBBLE) {
25904978Sgd78059 mxfep->mxfe_align_errors++;
25914978Sgd78059
25924978Sgd78059 } else if (status & RXSTAT_CRCERR) {
25934978Sgd78059 mxfep->mxfe_fcs_errors++;
25944978Sgd78059
25954978Sgd78059 } else if (status & RXSTAT_OFLOW) {
25969199Sgdamore@opensolaris.org /* this is a MAC FIFO error, need to reset */
25974978Sgd78059 mxfep->mxfe_overflow++;
25989199Sgdamore@opensolaris.org error = B_TRUE;
25994978Sgd78059 }
26004978Sgd78059 }
26014978Sgd78059
26024978Sgd78059 else if (len > ETHERVLANMTU) {
26034978Sgd78059 mxfep->mxfe_errrcv++;
26044978Sgd78059 mxfep->mxfe_toolong_errors++;
26054978Sgd78059 }
26064978Sgd78059
26074978Sgd78059 /*
26084978Sgd78059 * At this point, the chip thinks the packet is OK.
26094978Sgd78059 */
26104978Sgd78059 else {
26114978Sgd78059 mp = allocb(len + MXFE_HEADROOM, 0);
26124978Sgd78059 if (mp == NULL) {
26134978Sgd78059 mxfep->mxfe_errrcv++;
26144978Sgd78059 mxfep->mxfe_norcvbuf++;
26154978Sgd78059 goto skip;
26164978Sgd78059 }
26174978Sgd78059
26184978Sgd78059 /* sync the buffer before we look at it */
26194978Sgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
26204978Sgd78059 mp->b_rptr += MXFE_HEADROOM;
26214978Sgd78059 mp->b_wptr = mp->b_rptr + len;
26224978Sgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len);
26234978Sgd78059
26244978Sgd78059 mxfep->mxfe_ipackets++;
26254978Sgd78059 mxfep->mxfe_rbytes += len;
26264978Sgd78059 if (status & RXSTAT_GROUP) {
26274978Sgd78059 if (bcmp(mp->b_rptr, mxfe_broadcast,
26284978Sgd78059 ETHERADDRL) == 0)
26294978Sgd78059 mxfep->mxfe_brdcstrcv++;
26304978Sgd78059 else
26314978Sgd78059 mxfep->mxfe_multircv++;
26324978Sgd78059 }
26334978Sgd78059 *mpp = mp;
26344978Sgd78059 mpp = &mp->b_next;
26354978Sgd78059 }
26364978Sgd78059
26374978Sgd78059 skip:
26384978Sgd78059 /* return ring entry to the hardware */
26394978Sgd78059 PUTRXDESC(mxfep, rmd->desc_status, RXSTAT_OWN);
26404978Sgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORDEV);
26414978Sgd78059
26424978Sgd78059 /* advance to next RMD */
26434978Sgd78059 head = (head + 1) % MXFE_RXRING;
26444978Sgd78059 }
26454978Sgd78059
26464978Sgd78059 mxfep->mxfe_rxhead = head;
26474978Sgd78059
26489199Sgdamore@opensolaris.org *rxchain = mpchain;
26499199Sgdamore@opensolaris.org return (error);
26504978Sgd78059 }
26514978Sgd78059
26524978Sgd78059 int
mxfe_m_stat(void * arg,uint_t stat,uint64_t * val)26534978Sgd78059 mxfe_m_stat(void *arg, uint_t stat, uint64_t *val)
26544978Sgd78059 {
26554978Sgd78059 mxfe_t *mxfep = arg;
26564978Sgd78059
26574978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
26584978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == MXFE_RUNNING)
26594978Sgd78059 mxfe_reclaim(mxfep);
26604978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
26614978Sgd78059
26624978Sgd78059 switch (stat) {
26634978Sgd78059 case MAC_STAT_IFSPEED:
26644978Sgd78059 *val = mxfep->mxfe_ifspeed;
26654978Sgd78059 break;
26664978Sgd78059
26674978Sgd78059 case MAC_STAT_MULTIRCV:
26684978Sgd78059 *val = mxfep->mxfe_multircv;
26694978Sgd78059 break;
26704978Sgd78059
26714978Sgd78059 case MAC_STAT_BRDCSTRCV:
26724978Sgd78059 *val = mxfep->mxfe_brdcstrcv;
26734978Sgd78059 break;
26744978Sgd78059
26754978Sgd78059 case MAC_STAT_MULTIXMT:
26764978Sgd78059 *val = mxfep->mxfe_multixmt;
26774978Sgd78059 break;
26784978Sgd78059
26794978Sgd78059 case MAC_STAT_BRDCSTXMT:
26804978Sgd78059 *val = mxfep->mxfe_brdcstxmt;
26814978Sgd78059 break;
26824978Sgd78059
26834978Sgd78059 case MAC_STAT_IPACKETS:
26844978Sgd78059 *val = mxfep->mxfe_ipackets;
26854978Sgd78059 break;
26864978Sgd78059
26874978Sgd78059 case MAC_STAT_RBYTES:
26884978Sgd78059 *val = mxfep->mxfe_rbytes;
26894978Sgd78059 break;
26904978Sgd78059
26914978Sgd78059 case MAC_STAT_OPACKETS:
26924978Sgd78059 *val = mxfep->mxfe_opackets;
26934978Sgd78059 break;
26944978Sgd78059
26954978Sgd78059 case MAC_STAT_OBYTES:
26964978Sgd78059 *val = mxfep->mxfe_obytes;
26974978Sgd78059 break;
26984978Sgd78059
26994978Sgd78059 case MAC_STAT_NORCVBUF:
27004978Sgd78059 *val = mxfep->mxfe_norcvbuf;
27014978Sgd78059 break;
27024978Sgd78059
27034978Sgd78059 case MAC_STAT_NOXMTBUF:
27044978Sgd78059 *val = mxfep->mxfe_noxmtbuf;
27054978Sgd78059 break;
27064978Sgd78059
27074978Sgd78059 case MAC_STAT_COLLISIONS:
27084978Sgd78059 *val = mxfep->mxfe_collisions;
27094978Sgd78059 break;
27104978Sgd78059
27114978Sgd78059 case MAC_STAT_IERRORS:
27124978Sgd78059 *val = mxfep->mxfe_errrcv;
27134978Sgd78059 break;
27144978Sgd78059
27154978Sgd78059 case MAC_STAT_OERRORS:
27164978Sgd78059 *val = mxfep->mxfe_errxmt;
27174978Sgd78059 break;
27184978Sgd78059
27194978Sgd78059 case ETHER_STAT_LINK_DUPLEX:
27204978Sgd78059 *val = mxfep->mxfe_duplex;
27214978Sgd78059 break;
27224978Sgd78059
27234978Sgd78059 case ETHER_STAT_ALIGN_ERRORS:
27244978Sgd78059 *val = mxfep->mxfe_align_errors;
27254978Sgd78059 break;
27264978Sgd78059
27274978Sgd78059 case ETHER_STAT_FCS_ERRORS:
27284978Sgd78059 *val = mxfep->mxfe_fcs_errors;
27294978Sgd78059 break;
27304978Sgd78059
27314978Sgd78059 case ETHER_STAT_SQE_ERRORS:
27324978Sgd78059 *val = mxfep->mxfe_sqe_errors;
27334978Sgd78059 break;
27344978Sgd78059
27354978Sgd78059 case ETHER_STAT_DEFER_XMTS:
27364978Sgd78059 *val = mxfep->mxfe_defer_xmts;
27374978Sgd78059 break;
27384978Sgd78059
27394978Sgd78059 case ETHER_STAT_FIRST_COLLISIONS:
27404978Sgd78059 *val = mxfep->mxfe_first_collisions;
27414978Sgd78059 break;
27424978Sgd78059
27434978Sgd78059 case ETHER_STAT_MULTI_COLLISIONS:
27444978Sgd78059 *val = mxfep->mxfe_multi_collisions;
27454978Sgd78059 break;
27464978Sgd78059
27474978Sgd78059 case ETHER_STAT_TX_LATE_COLLISIONS:
27484978Sgd78059 *val = mxfep->mxfe_tx_late_collisions;
27494978Sgd78059 break;
27504978Sgd78059
27514978Sgd78059 case ETHER_STAT_EX_COLLISIONS:
27524978Sgd78059 *val = mxfep->mxfe_ex_collisions;
27534978Sgd78059 break;
27544978Sgd78059
27554978Sgd78059 case ETHER_STAT_MACXMT_ERRORS:
27564978Sgd78059 *val = mxfep->mxfe_macxmt_errors;
27574978Sgd78059 break;
27584978Sgd78059
27594978Sgd78059 case ETHER_STAT_CARRIER_ERRORS:
27604978Sgd78059 *val = mxfep->mxfe_carrier_errors;
27614978Sgd78059 break;
27624978Sgd78059
27634978Sgd78059 case ETHER_STAT_TOOLONG_ERRORS:
27644978Sgd78059 *val = mxfep->mxfe_toolong_errors;
27654978Sgd78059 break;
27664978Sgd78059
27674978Sgd78059 case ETHER_STAT_MACRCV_ERRORS:
27684978Sgd78059 *val = mxfep->mxfe_macrcv_errors;
27694978Sgd78059 break;
27704978Sgd78059
27714978Sgd78059 case MAC_STAT_OVERFLOWS:
27724978Sgd78059 *val = mxfep->mxfe_overflow;
27734978Sgd78059 break;
27744978Sgd78059
27754978Sgd78059 case MAC_STAT_UNDERFLOWS:
27764978Sgd78059 *val = mxfep->mxfe_underflow;
27774978Sgd78059 break;
27784978Sgd78059
27794978Sgd78059 case ETHER_STAT_TOOSHORT_ERRORS:
27804978Sgd78059 *val = mxfep->mxfe_runt;
27814978Sgd78059 break;
27824978Sgd78059
27834978Sgd78059 case ETHER_STAT_JABBER_ERRORS:
27844978Sgd78059 *val = mxfep->mxfe_jabber;
27854978Sgd78059 break;
27864978Sgd78059
27874978Sgd78059 case ETHER_STAT_ADV_CAP_100T4:
27884978Sgd78059 *val = mxfep->mxfe_adv_100T4;
27894978Sgd78059 break;
27904978Sgd78059
27914978Sgd78059 case ETHER_STAT_LP_CAP_100T4:
27924978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_T4) ? 1 : 0;
27934978Sgd78059 break;
27944978Sgd78059
27956684Sgd78059 case ETHER_STAT_CAP_100T4:
27966684Sgd78059 *val = mxfep->mxfe_cap_100T4;
27976684Sgd78059 break;
27986684Sgd78059
27994978Sgd78059 case ETHER_STAT_CAP_100FDX:
28006684Sgd78059 *val = mxfep->mxfe_cap_100fdx;
28014978Sgd78059 break;
28024978Sgd78059
28034978Sgd78059 case ETHER_STAT_CAP_100HDX:
28046684Sgd78059 *val = mxfep->mxfe_cap_100hdx;
28054978Sgd78059 break;
28064978Sgd78059
28074978Sgd78059 case ETHER_STAT_CAP_10FDX:
28086684Sgd78059 *val = mxfep->mxfe_cap_10fdx;
28094978Sgd78059 break;
28104978Sgd78059
28114978Sgd78059 case ETHER_STAT_CAP_10HDX:
28126684Sgd78059 *val = mxfep->mxfe_cap_10hdx;
28134978Sgd78059 break;
28144978Sgd78059
28154978Sgd78059 case ETHER_STAT_CAP_AUTONEG:
28166684Sgd78059 *val = mxfep->mxfe_cap_aneg;
28174978Sgd78059 break;
28184978Sgd78059
28194978Sgd78059 case ETHER_STAT_LINK_AUTONEG:
28204978Sgd78059 *val = ((mxfep->mxfe_adv_aneg != 0) &&
28214978Sgd78059 ((mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) != 0));
28224978Sgd78059 break;
28234978Sgd78059
28244978Sgd78059 case ETHER_STAT_ADV_CAP_100FDX:
28254978Sgd78059 *val = mxfep->mxfe_adv_100fdx;
28264978Sgd78059 break;
28274978Sgd78059
28284978Sgd78059 case ETHER_STAT_ADV_CAP_100HDX:
28294978Sgd78059 *val = mxfep->mxfe_adv_100hdx;
28304978Sgd78059 break;
28314978Sgd78059
28324978Sgd78059 case ETHER_STAT_ADV_CAP_10FDX:
28334978Sgd78059 *val = mxfep->mxfe_adv_10fdx;
28344978Sgd78059 break;
28354978Sgd78059
28364978Sgd78059 case ETHER_STAT_ADV_CAP_10HDX:
28374978Sgd78059 *val = mxfep->mxfe_adv_10hdx;
28384978Sgd78059 break;
28394978Sgd78059
28404978Sgd78059 case ETHER_STAT_ADV_CAP_AUTONEG:
28414978Sgd78059 *val = mxfep->mxfe_adv_aneg;
28424978Sgd78059 break;
28434978Sgd78059
28444978Sgd78059 case ETHER_STAT_LP_CAP_100FDX:
28454978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX_FD) ? 1 : 0;
28464978Sgd78059 break;
28474978Sgd78059
28484978Sgd78059 case ETHER_STAT_LP_CAP_100HDX:
28494978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX) ? 1 : 0;
28504978Sgd78059 break;
28514978Sgd78059
28524978Sgd78059 case ETHER_STAT_LP_CAP_10FDX:
28534978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T_FD) ? 1 : 0;
28544978Sgd78059 break;
28554978Sgd78059
28564978Sgd78059 case ETHER_STAT_LP_CAP_10HDX:
28574978Sgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T) ? 1 : 0;
28584978Sgd78059 break;
28594978Sgd78059
28604978Sgd78059 case ETHER_STAT_LP_CAP_AUTONEG:
28614978Sgd78059 *val = (mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) ? 1 : 0;
28624978Sgd78059 break;
28634978Sgd78059
28644978Sgd78059 case ETHER_STAT_XCVR_ADDR:
28654978Sgd78059 *val = mxfep->mxfe_phyaddr;
28664978Sgd78059 break;
28674978Sgd78059
28684978Sgd78059 case ETHER_STAT_XCVR_ID:
28694978Sgd78059 *val = mxfep->mxfe_phyid;
28704978Sgd78059 break;
28714978Sgd78059
28724978Sgd78059 case ETHER_STAT_XCVR_INUSE:
28734978Sgd78059 *val = mxfep->mxfe_phyinuse;
28744978Sgd78059 break;
28754978Sgd78059
28764978Sgd78059 default:
28774978Sgd78059 return (ENOTSUP);
28784978Sgd78059 }
28794978Sgd78059 return (0);
28804978Sgd78059 }
28814978Sgd78059
28826684Sgd78059 /*ARGSUSED*/
28836684Sgd78059 int
mxfe_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)2884*11878SVenu.Iyer@Sun.COM mxfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2885*11878SVenu.Iyer@Sun.COM void *val)
28864978Sgd78059 {
28876684Sgd78059 mxfe_t *mxfep = arg;
28886684Sgd78059 int err = 0;
2889*11878SVenu.Iyer@Sun.COM
28906684Sgd78059 switch (num) {
28916789Sam223141 case MAC_PROP_DUPLEX:
2892*11878SVenu.Iyer@Sun.COM ASSERT(sz >= sizeof (link_duplex_t));
2893*11878SVenu.Iyer@Sun.COM bcopy(&mxfep->mxfe_duplex, val, sizeof (link_duplex_t));
28946684Sgd78059 break;
28956684Sgd78059
28966789Sam223141 case MAC_PROP_SPEED:
2897*11878SVenu.Iyer@Sun.COM ASSERT(sz >= sizeof (uint64_t));
2898*11878SVenu.Iyer@Sun.COM bcopy(&mxfep->mxfe_ifspeed, val, sizeof (uint64_t));
28996684Sgd78059 break;
29006684Sgd78059
29016789Sam223141 case MAC_PROP_AUTONEG:
2902*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_aneg;
29036684Sgd78059 break;
29046684Sgd78059
29056789Sam223141 case MAC_PROP_ADV_100FDX_CAP:
29066789Sam223141 case MAC_PROP_EN_100FDX_CAP:
2907*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_100fdx;
29086684Sgd78059 break;
29096684Sgd78059
29106789Sam223141 case MAC_PROP_ADV_100HDX_CAP:
29116789Sam223141 case MAC_PROP_EN_100HDX_CAP:
2912*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_100hdx;
29136684Sgd78059 break;
29146684Sgd78059
29156789Sam223141 case MAC_PROP_ADV_10FDX_CAP:
29166789Sam223141 case MAC_PROP_EN_10FDX_CAP:
2917*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_10fdx;
29186684Sgd78059 break;
29196684Sgd78059
29206789Sam223141 case MAC_PROP_ADV_10HDX_CAP:
29216789Sam223141 case MAC_PROP_EN_10HDX_CAP:
2922*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_10hdx;
29236684Sgd78059 break;
29246684Sgd78059
29256789Sam223141 case MAC_PROP_ADV_100T4_CAP:
29266789Sam223141 case MAC_PROP_EN_100T4_CAP:
2927*11878SVenu.Iyer@Sun.COM *(uint8_t *)val = mxfep->mxfe_adv_100T4;
29286684Sgd78059 break;
29296684Sgd78059
29306684Sgd78059 default:
29316684Sgd78059 err = ENOTSUP;
29324978Sgd78059 }
29336684Sgd78059
29346684Sgd78059 return (err);
29354978Sgd78059 }
29364978Sgd78059
29374978Sgd78059 /*ARGSUSED*/
29384978Sgd78059 int
mxfe_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)29396684Sgd78059 mxfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
29406684Sgd78059 const void *val)
29414978Sgd78059 {
29426684Sgd78059 mxfe_t *mxfep = arg;
29436684Sgd78059 uint8_t *advp;
29446684Sgd78059 uint8_t *capp;
29456684Sgd78059
29466684Sgd78059 switch (num) {
29476789Sam223141 case MAC_PROP_EN_100FDX_CAP:
29486684Sgd78059 advp = &mxfep->mxfe_adv_100fdx;
29496684Sgd78059 capp = &mxfep->mxfe_cap_100fdx;
29506684Sgd78059 break;
29516684Sgd78059
29526789Sam223141 case MAC_PROP_EN_100HDX_CAP:
29536684Sgd78059 advp = &mxfep->mxfe_adv_100hdx;
29546684Sgd78059 capp = &mxfep->mxfe_cap_100hdx;
29556684Sgd78059 break;
29566684Sgd78059
29576789Sam223141 case MAC_PROP_EN_10FDX_CAP:
29586684Sgd78059 advp = &mxfep->mxfe_adv_10fdx;
29596684Sgd78059 capp = &mxfep->mxfe_cap_10fdx;
29606684Sgd78059 break;
29616684Sgd78059
29626789Sam223141 case MAC_PROP_EN_10HDX_CAP:
29636684Sgd78059 advp = &mxfep->mxfe_adv_10hdx;
29646684Sgd78059 capp = &mxfep->mxfe_cap_10hdx;
29656684Sgd78059 break;
29666684Sgd78059
29676789Sam223141 case MAC_PROP_EN_100T4_CAP:
29686684Sgd78059 advp = &mxfep->mxfe_adv_100T4;
29696684Sgd78059 capp = &mxfep->mxfe_cap_100T4;
29706684Sgd78059 break;
29716684Sgd78059
29726789Sam223141 case MAC_PROP_AUTONEG:
29736684Sgd78059 advp = &mxfep->mxfe_adv_aneg;
29746684Sgd78059 capp = &mxfep->mxfe_cap_aneg;
29756684Sgd78059 break;
29766684Sgd78059
29776684Sgd78059 default:
29786684Sgd78059 return (ENOTSUP);
29796684Sgd78059 }
29806684Sgd78059
29816684Sgd78059 if (*capp == 0) /* ensure phy can support value */
29826684Sgd78059 return (ENOTSUP);
29834978Sgd78059
29844978Sgd78059 mutex_enter(&mxfep->mxfe_intrlock);
29854978Sgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
29864978Sgd78059
29876684Sgd78059 if (*advp != *(const uint8_t *)val) {
29886684Sgd78059 *advp = *(const uint8_t *)val;
29896684Sgd78059
29904978Sgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
29914978Sgd78059 MXFE_RUNNING) {
29924978Sgd78059 /*
29934978Sgd78059 * This re-initializes the phy, but it also
29944978Sgd78059 * restarts transmit and receive rings.
29954978Sgd78059 * Needless to say, changing the link
29964978Sgd78059 * parameters is destructive to traffic in
29974978Sgd78059 * progress.
29984978Sgd78059 */
29994978Sgd78059 mxfe_resetall(mxfep);
30004978Sgd78059 }
30014978Sgd78059 }
30024978Sgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
30034978Sgd78059 mutex_exit(&mxfep->mxfe_intrlock);
30044978Sgd78059
30054978Sgd78059 return (0);
30064978Sgd78059 }
30074978Sgd78059
3008*11878SVenu.Iyer@Sun.COM static void
mxfe_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t mph)3009*11878SVenu.Iyer@Sun.COM mxfe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
3010*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t mph)
3011*11878SVenu.Iyer@Sun.COM {
3012*11878SVenu.Iyer@Sun.COM mxfe_t *mxfep = arg;
3013*11878SVenu.Iyer@Sun.COM
3014*11878SVenu.Iyer@Sun.COM _NOTE(ARGUNUSED(name));
3015*11878SVenu.Iyer@Sun.COM
3016*11878SVenu.Iyer@Sun.COM switch (num) {
3017*11878SVenu.Iyer@Sun.COM case MAC_PROP_DUPLEX:
3018*11878SVenu.Iyer@Sun.COM case MAC_PROP_SPEED:
3019*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100FDX_CAP:
3020*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100HDX_CAP:
3021*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10FDX_CAP:
3022*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_10HDX_CAP:
3023*11878SVenu.Iyer@Sun.COM case MAC_PROP_ADV_100T4_CAP:
3024*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
3025*11878SVenu.Iyer@Sun.COM break;
3026*11878SVenu.Iyer@Sun.COM
3027*11878SVenu.Iyer@Sun.COM case MAC_PROP_AUTONEG:
3028*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_aneg);
3029*11878SVenu.Iyer@Sun.COM break;
3030*11878SVenu.Iyer@Sun.COM
3031*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100FDX_CAP:
3032*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100fdx);
3033*11878SVenu.Iyer@Sun.COM break;
3034*11878SVenu.Iyer@Sun.COM
3035*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100HDX_CAP:
3036*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100hdx);
3037*11878SVenu.Iyer@Sun.COM break;
3038*11878SVenu.Iyer@Sun.COM
3039*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10FDX_CAP:
3040*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10fdx);
3041*11878SVenu.Iyer@Sun.COM break;
3042*11878SVenu.Iyer@Sun.COM
3043*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_10HDX_CAP:
3044*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10hdx);
3045*11878SVenu.Iyer@Sun.COM break;
3046*11878SVenu.Iyer@Sun.COM
3047*11878SVenu.Iyer@Sun.COM case MAC_PROP_EN_100T4_CAP:
3048*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100T4);
3049*11878SVenu.Iyer@Sun.COM break;
3050*11878SVenu.Iyer@Sun.COM }
3051*11878SVenu.Iyer@Sun.COM }
3052*11878SVenu.Iyer@Sun.COM
30534978Sgd78059 /*
30544978Sgd78059 * Debugging and error reporting.
30554978Sgd78059 */
30564978Sgd78059 void
mxfe_error(dev_info_t * dip,char * fmt,...)30574978Sgd78059 mxfe_error(dev_info_t *dip, char *fmt, ...)
30584978Sgd78059 {
30594978Sgd78059 va_list ap;
30604978Sgd78059 char buf[256];
30614978Sgd78059
30624978Sgd78059 va_start(ap, fmt);
30634978Sgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
30644978Sgd78059 va_end(ap);
30654978Sgd78059
30664978Sgd78059 if (dip) {
30674978Sgd78059 cmn_err(CE_WARN, "%s%d: %s",
30684978Sgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf);
30694978Sgd78059 } else {
30704978Sgd78059 cmn_err(CE_WARN, "mxfe: %s", buf);
30714978Sgd78059 }
30724978Sgd78059 }
30734978Sgd78059
30744978Sgd78059 #ifdef DEBUG
30754978Sgd78059
30764978Sgd78059 void
mxfe_dprintf(mxfe_t * mxfep,const char * func,int level,char * fmt,...)30774978Sgd78059 mxfe_dprintf(mxfe_t *mxfep, const char *func, int level, char *fmt, ...)
30784978Sgd78059 {
30794978Sgd78059 va_list ap;
30804978Sgd78059
30814978Sgd78059 va_start(ap, fmt);
30824978Sgd78059 if (mxfe_debug & level) {
30834978Sgd78059 char tag[64];
30844978Sgd78059 char buf[256];
30854978Sgd78059
30864978Sgd78059 if (mxfep && mxfep->mxfe_dip) {
30874978Sgd78059 (void) snprintf(tag, sizeof (tag),
30884978Sgd78059 "%s%d", ddi_driver_name(mxfep->mxfe_dip),
30894978Sgd78059 ddi_get_instance(mxfep->mxfe_dip));
30904978Sgd78059 } else {
30914978Sgd78059 (void) snprintf(tag, sizeof (tag), "mxfe");
30924978Sgd78059 }
30934978Sgd78059
30944978Sgd78059 (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", tag,
30954978Sgd78059 func, fmt);
30964978Sgd78059
30974978Sgd78059 vcmn_err(CE_CONT, buf, ap);
30984978Sgd78059 }
30994978Sgd78059 va_end(ap);
31004978Sgd78059 }
31014978Sgd78059
31024978Sgd78059 #endif
3103