129e83d4bSgd78059 /*
229e83d4bSgd78059 * Solaris driver for ethernet cards based on the Macronix 98715
329e83d4bSgd78059 *
429e83d4bSgd78059 * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
529e83d4bSgd78059 * All rights reserved.
629e83d4bSgd78059 *
729e83d4bSgd78059 * Redistribution and use in source and binary forms, with or without
829e83d4bSgd78059 * modification, are permitted provided that the following conditions
929e83d4bSgd78059 * are met:
1029e83d4bSgd78059 * 1. Redistributions of source code must retain the above copyright
1129e83d4bSgd78059 * notice, this list of conditions and the following disclaimer.
1229e83d4bSgd78059 * 2. Redistributions in binary form must reproduce the above copyright
1329e83d4bSgd78059 * notice, this list of conditions and the following disclaimer in the
1429e83d4bSgd78059 * documentation and/or other materials provided with the distribution.
1529e83d4bSgd78059 * 3. Neither the name of the author nor the names of any co-contributors
1629e83d4bSgd78059 * may be used to endorse or promote products derived from this software
1729e83d4bSgd78059 * without specific prior written permission.
1829e83d4bSgd78059 *
1929e83d4bSgd78059 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
2029e83d4bSgd78059 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2129e83d4bSgd78059 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2229e83d4bSgd78059 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2329e83d4bSgd78059 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2429e83d4bSgd78059 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2529e83d4bSgd78059 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2629e83d4bSgd78059 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2729e83d4bSgd78059 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2829e83d4bSgd78059 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2929e83d4bSgd78059 * POSSIBILITY OF SUCH DAMAGE.
3029e83d4bSgd78059 */
3196fb08b9Sgd78059 /*
32*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3396fb08b9Sgd78059 * Use is subject to license terms.
3496fb08b9Sgd78059 */
3529e83d4bSgd78059
3629e83d4bSgd78059
3729e83d4bSgd78059 #include <sys/varargs.h>
3829e83d4bSgd78059 #include <sys/types.h>
3929e83d4bSgd78059 #include <sys/modctl.h>
4029e83d4bSgd78059 #include <sys/conf.h>
4129e83d4bSgd78059 #include <sys/devops.h>
4229e83d4bSgd78059 #include <sys/stream.h>
4329e83d4bSgd78059 #include <sys/strsun.h>
4429e83d4bSgd78059 #include <sys/cmn_err.h>
4529e83d4bSgd78059 #include <sys/dlpi.h>
4629e83d4bSgd78059 #include <sys/ethernet.h>
4729e83d4bSgd78059 #include <sys/kmem.h>
4829e83d4bSgd78059 #include <sys/time.h>
4929e83d4bSgd78059 #include <sys/miiregs.h>
5029e83d4bSgd78059 #include <sys/strsun.h>
5129e83d4bSgd78059 #include <sys/mac.h>
5229e83d4bSgd78059 #include <sys/mac_ether.h>
5329e83d4bSgd78059 #include <sys/ddi.h>
5429e83d4bSgd78059 #include <sys/sunddi.h>
55d62bc4baSyz147064 #include <sys/vlan.h>
5629e83d4bSgd78059
5729e83d4bSgd78059 #include "mxfe.h"
5829e83d4bSgd78059 #include "mxfeimpl.h"
5929e83d4bSgd78059
6029e83d4bSgd78059 /*
6129e83d4bSgd78059 * Driver globals.
6229e83d4bSgd78059 */
6329e83d4bSgd78059
6429e83d4bSgd78059 /* patchable debug flag ... must not be static! */
6529e83d4bSgd78059 #ifdef DEBUG
6629e83d4bSgd78059 unsigned mxfe_debug = DWARN;
6729e83d4bSgd78059 #endif
6829e83d4bSgd78059
6929e83d4bSgd78059 /* table of supported devices */
7029e83d4bSgd78059 static mxfe_card_t mxfe_cards[] = {
7129e83d4bSgd78059
7229e83d4bSgd78059 /*
7329e83d4bSgd78059 * Lite-On products
7429e83d4bSgd78059 */
7529e83d4bSgd78059 { 0x11ad, 0xc115, 0, 0, "Lite-On LC82C115", MXFE_PNICII },
7629e83d4bSgd78059
7729e83d4bSgd78059 /*
7829e83d4bSgd78059 * Macronix chips
7929e83d4bSgd78059 */
8029e83d4bSgd78059 { 0x10d9, 0x0531, 0x25, 0xff, "Macronix MX98715AEC", MXFE_98715AEC },
8129e83d4bSgd78059 { 0x10d9, 0x0531, 0x20, 0xff, "Macronix MX98715A", MXFE_98715A },
8229e83d4bSgd78059 { 0x10d9, 0x0531, 0x60, 0xff, "Macronix MX98715B", MXFE_98715B },
8329e83d4bSgd78059 { 0x10d9, 0x0531, 0x30, 0xff, "Macronix MX98725", MXFE_98725 },
8429e83d4bSgd78059 { 0x10d9, 0x0531, 0x00, 0xff, "Macronix MX98715", MXFE_98715 },
8529e83d4bSgd78059 { 0x10d9, 0x0512, 0, 0, "Macronix MX98713", MXFE_98713 },
8629e83d4bSgd78059
8729e83d4bSgd78059 /*
8829e83d4bSgd78059 * Compex (relabeled Macronix products)
8929e83d4bSgd78059 */
9029e83d4bSgd78059 { 0x11fc, 0x9881, 0x00, 0x00, "Compex 9881", MXFE_98713 },
9129e83d4bSgd78059 { 0x11fc, 0x9881, 0x10, 0xff, "Compex 9881A", MXFE_98713A },
9229e83d4bSgd78059 /*
9329e83d4bSgd78059 * Models listed here
9429e83d4bSgd78059 */
9529e83d4bSgd78059 { 0x11ad, 0xc001, 0, 0, "Linksys LNE100TX", MXFE_PNICII },
9629e83d4bSgd78059 { 0x2646, 0x000b, 0, 0, "Kingston KNE111TX", MXFE_PNICII },
9729e83d4bSgd78059 { 0x1154, 0x0308, 0, 0, "Buffalo LGY-PCI-TXL", MXFE_98715AEC },
9829e83d4bSgd78059 };
9929e83d4bSgd78059
10029e83d4bSgd78059 #define ETHERVLANMTU (ETHERMAX + 4)
10129e83d4bSgd78059
10229e83d4bSgd78059 /*
10329e83d4bSgd78059 * Function prototypes
10429e83d4bSgd78059 */
10529e83d4bSgd78059 static int mxfe_attach(dev_info_t *, ddi_attach_cmd_t);
10629e83d4bSgd78059 static int mxfe_detach(dev_info_t *, ddi_detach_cmd_t);
10729e83d4bSgd78059 static int mxfe_resume(dev_info_t *);
10877860f66SGarrett D'Amore static int mxfe_quiesce(dev_info_t *);
10929e83d4bSgd78059 static int mxfe_m_unicst(void *, const uint8_t *);
11029e83d4bSgd78059 static int mxfe_m_multicst(void *, boolean_t, const uint8_t *);
11129e83d4bSgd78059 static int mxfe_m_promisc(void *, boolean_t);
11229e83d4bSgd78059 static mblk_t *mxfe_m_tx(void *, mblk_t *);
11329e83d4bSgd78059 static int mxfe_m_stat(void *, uint_t, uint64_t *);
11429e83d4bSgd78059 static int mxfe_m_start(void *);
11529e83d4bSgd78059 static void mxfe_m_stop(void *);
11696fb08b9Sgd78059 static int mxfe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
117*0dc2366fSVenugopal Iyer void *);
11896fb08b9Sgd78059 static int mxfe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
11996fb08b9Sgd78059 const void *);
120*0dc2366fSVenugopal Iyer static void mxfe_m_propinfo(void *, const char *, mac_prop_id_t,
121*0dc2366fSVenugopal Iyer mac_prop_info_handle_t);
12229e83d4bSgd78059 static unsigned mxfe_intr(caddr_t);
12329e83d4bSgd78059 static void mxfe_startmac(mxfe_t *);
12429e83d4bSgd78059 static void mxfe_stopmac(mxfe_t *);
12529e83d4bSgd78059 static void mxfe_resetrings(mxfe_t *);
12629e83d4bSgd78059 static boolean_t mxfe_initialize(mxfe_t *);
12729e83d4bSgd78059 static void mxfe_startall(mxfe_t *);
12829e83d4bSgd78059 static void mxfe_stopall(mxfe_t *);
12929e83d4bSgd78059 static void mxfe_resetall(mxfe_t *);
13029e83d4bSgd78059 static mxfe_txbuf_t *mxfe_alloctxbuf(mxfe_t *);
13129e83d4bSgd78059 static void mxfe_destroytxbuf(mxfe_txbuf_t *);
13229e83d4bSgd78059 static mxfe_rxbuf_t *mxfe_allocrxbuf(mxfe_t *);
13329e83d4bSgd78059 static void mxfe_destroyrxbuf(mxfe_rxbuf_t *);
13429e83d4bSgd78059 static void mxfe_send_setup(mxfe_t *);
13529e83d4bSgd78059 static boolean_t mxfe_send(mxfe_t *, mblk_t *);
13629e83d4bSgd78059 static int mxfe_allocrxring(mxfe_t *);
13729e83d4bSgd78059 static void mxfe_freerxring(mxfe_t *);
13829e83d4bSgd78059 static int mxfe_alloctxring(mxfe_t *);
13929e83d4bSgd78059 static void mxfe_freetxring(mxfe_t *);
14029e83d4bSgd78059 static void mxfe_error(dev_info_t *, char *, ...);
14129e83d4bSgd78059 static uint8_t mxfe_sromwidth(mxfe_t *);
14229e83d4bSgd78059 static uint16_t mxfe_readsromword(mxfe_t *, unsigned);
14329e83d4bSgd78059 static void mxfe_readsrom(mxfe_t *, unsigned, unsigned, void *);
14429e83d4bSgd78059 static void mxfe_getfactaddr(mxfe_t *, uchar_t *);
14596fb08b9Sgd78059 static uint8_t mxfe_miireadbit(mxfe_t *);
14696fb08b9Sgd78059 static void mxfe_miiwritebit(mxfe_t *, uint8_t);
14729e83d4bSgd78059 static void mxfe_miitristate(mxfe_t *);
14896fb08b9Sgd78059 static uint16_t mxfe_miiread(mxfe_t *, int, int);
14929e83d4bSgd78059 static void mxfe_miiwrite(mxfe_t *, int, int, uint16_t);
15096fb08b9Sgd78059 static uint16_t mxfe_miireadgeneral(mxfe_t *, int, int);
15129e83d4bSgd78059 static void mxfe_miiwritegeneral(mxfe_t *, int, int, uint16_t);
15296fb08b9Sgd78059 static uint16_t mxfe_miiread98713(mxfe_t *, int, int);
15329e83d4bSgd78059 static void mxfe_miiwrite98713(mxfe_t *, int, int, uint16_t);
15429e83d4bSgd78059 static void mxfe_startphy(mxfe_t *);
15529e83d4bSgd78059 static void mxfe_stopphy(mxfe_t *);
15629e83d4bSgd78059 static void mxfe_startphymii(mxfe_t *);
15729e83d4bSgd78059 static void mxfe_startphynway(mxfe_t *);
15829e83d4bSgd78059 static void mxfe_startnway(mxfe_t *);
15929e83d4bSgd78059 static void mxfe_reportlink(mxfe_t *);
16029e83d4bSgd78059 static void mxfe_checklink(mxfe_t *);
16129e83d4bSgd78059 static void mxfe_checklinkmii(mxfe_t *);
16229e83d4bSgd78059 static void mxfe_checklinknway(mxfe_t *);
16329e83d4bSgd78059 static void mxfe_disableinterrupts(mxfe_t *);
16429e83d4bSgd78059 static void mxfe_enableinterrupts(mxfe_t *);
16529e83d4bSgd78059 static void mxfe_reclaim(mxfe_t *);
16677860f66SGarrett D'Amore static boolean_t mxfe_receive(mxfe_t *, mblk_t **);
16729e83d4bSgd78059
16829e83d4bSgd78059 #ifdef DEBUG
16929e83d4bSgd78059 static void mxfe_dprintf(mxfe_t *, const char *, int, char *, ...);
17029e83d4bSgd78059 #endif
17129e83d4bSgd78059
17229e83d4bSgd78059 #define KIOIP KSTAT_INTR_PTR(mxfep->mxfe_intrstat)
17329e83d4bSgd78059
17429e83d4bSgd78059 static mac_callbacks_t mxfe_m_callbacks = {
175*0dc2366fSVenugopal Iyer MC_SETPROP | MC_GETPROP | MC_PROPINFO,
17629e83d4bSgd78059 mxfe_m_stat,
17729e83d4bSgd78059 mxfe_m_start,
17829e83d4bSgd78059 mxfe_m_stop,
17929e83d4bSgd78059 mxfe_m_promisc,
18029e83d4bSgd78059 mxfe_m_multicst,
18129e83d4bSgd78059 mxfe_m_unicst,
18229e83d4bSgd78059 mxfe_m_tx,
183*0dc2366fSVenugopal Iyer NULL,
18496fb08b9Sgd78059 NULL, /* mc_ioctl */
18596fb08b9Sgd78059 NULL, /* mc_getcapab */
18696fb08b9Sgd78059 NULL, /* mc_open */
18796fb08b9Sgd78059 NULL, /* mc_close */
18896fb08b9Sgd78059 mxfe_m_setprop,
189*0dc2366fSVenugopal Iyer mxfe_m_getprop,
190*0dc2366fSVenugopal Iyer mxfe_m_propinfo
19129e83d4bSgd78059 };
19229e83d4bSgd78059
19329e83d4bSgd78059 /*
19429e83d4bSgd78059 * Stream information
19529e83d4bSgd78059 */
19629e83d4bSgd78059 DDI_DEFINE_STREAM_OPS(mxfe_devops, nulldev, nulldev, mxfe_attach, mxfe_detach,
19777860f66SGarrett D'Amore nodev, NULL, D_MP, NULL, mxfe_quiesce);
19829e83d4bSgd78059
19929e83d4bSgd78059 /*
20029e83d4bSgd78059 * Module linkage information.
20129e83d4bSgd78059 */
20229e83d4bSgd78059
20329e83d4bSgd78059 static struct modldrv mxfe_modldrv = {
20429e83d4bSgd78059 &mod_driverops, /* drv_modops */
20529e83d4bSgd78059 "Macronix Fast Ethernet", /* drv_linkinfo */
20629e83d4bSgd78059 &mxfe_devops /* drv_dev_ops */
20729e83d4bSgd78059 };
20829e83d4bSgd78059
20929e83d4bSgd78059 static struct modlinkage mxfe_modlinkage = {
21029e83d4bSgd78059 MODREV_1, /* ml_rev */
21129e83d4bSgd78059 { &mxfe_modldrv, NULL } /* ml_linkage */
21229e83d4bSgd78059 };
21329e83d4bSgd78059
21429e83d4bSgd78059 /*
21529e83d4bSgd78059 * Device attributes.
21629e83d4bSgd78059 */
21729e83d4bSgd78059 static ddi_device_acc_attr_t mxfe_devattr = {
21829e83d4bSgd78059 DDI_DEVICE_ATTR_V0,
21929e83d4bSgd78059 DDI_STRUCTURE_LE_ACC,
22029e83d4bSgd78059 DDI_STRICTORDER_ACC
22129e83d4bSgd78059 };
22229e83d4bSgd78059
22329e83d4bSgd78059 static ddi_device_acc_attr_t mxfe_bufattr = {
22429e83d4bSgd78059 DDI_DEVICE_ATTR_V0,
22529e83d4bSgd78059 DDI_NEVERSWAP_ACC,
22629e83d4bSgd78059 DDI_STRICTORDER_ACC
22729e83d4bSgd78059 };
22829e83d4bSgd78059
22929e83d4bSgd78059 static ddi_dma_attr_t mxfe_dma_attr = {
23029e83d4bSgd78059 DMA_ATTR_V0, /* dma_attr_version */
23129e83d4bSgd78059 0, /* dma_attr_addr_lo */
23229e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */
23329e83d4bSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */
23429e83d4bSgd78059 4, /* dma_attr_align */
23529e83d4bSgd78059 0x3F, /* dma_attr_burstsizes */
23629e83d4bSgd78059 1, /* dma_attr_minxfer */
23729e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */
23829e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_seg */
23929e83d4bSgd78059 1, /* dma_attr_sgllen */
24029e83d4bSgd78059 1, /* dma_attr_granular */
24129e83d4bSgd78059 0 /* dma_attr_flags */
24229e83d4bSgd78059 };
24329e83d4bSgd78059
24429e83d4bSgd78059 /*
24529e83d4bSgd78059 * Tx buffers can be arbitrarily aligned. Additionally, they can
24629e83d4bSgd78059 * cross a page boundary, so we use the two buffer addresses of the
24729e83d4bSgd78059 * chip to provide a two-entry scatter-gather list.
24829e83d4bSgd78059 */
24929e83d4bSgd78059 static ddi_dma_attr_t mxfe_dma_txattr = {
25029e83d4bSgd78059 DMA_ATTR_V0, /* dma_attr_version */
25129e83d4bSgd78059 0, /* dma_attr_addr_lo */
25229e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_addr_hi */
25329e83d4bSgd78059 0x7FFFFFFFU, /* dma_attr_count_max */
25429e83d4bSgd78059 1, /* dma_attr_align */
25529e83d4bSgd78059 0x3F, /* dma_attr_burstsizes */
25629e83d4bSgd78059 1, /* dma_attr_minxfer */
25729e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_maxxfer */
25829e83d4bSgd78059 0xFFFFFFFFU, /* dma_attr_seg */
25929e83d4bSgd78059 2, /* dma_attr_sgllen */
26029e83d4bSgd78059 1, /* dma_attr_granular */
26129e83d4bSgd78059 0 /* dma_attr_flags */
26229e83d4bSgd78059 };
26329e83d4bSgd78059
26429e83d4bSgd78059 /*
26529e83d4bSgd78059 * Ethernet addresses.
26629e83d4bSgd78059 */
26729e83d4bSgd78059 static uchar_t mxfe_broadcast[ETHERADDRL] = {
26829e83d4bSgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
26929e83d4bSgd78059 };
27029e83d4bSgd78059
27129e83d4bSgd78059 /*
27229e83d4bSgd78059 * DDI entry points.
27329e83d4bSgd78059 */
27429e83d4bSgd78059 int
_init(void)27529e83d4bSgd78059 _init(void)
27629e83d4bSgd78059 {
27729e83d4bSgd78059 int rv;
27829e83d4bSgd78059 mac_init_ops(&mxfe_devops, "mxfe");
27929e83d4bSgd78059 if ((rv = mod_install(&mxfe_modlinkage)) != DDI_SUCCESS) {
28029e83d4bSgd78059 mac_fini_ops(&mxfe_devops);
28129e83d4bSgd78059 }
28229e83d4bSgd78059 return (rv);
28329e83d4bSgd78059 }
28429e83d4bSgd78059
28529e83d4bSgd78059 int
_fini(void)28629e83d4bSgd78059 _fini(void)
28729e83d4bSgd78059 {
28829e83d4bSgd78059 int rv;
28929e83d4bSgd78059 if ((rv = mod_remove(&mxfe_modlinkage)) == DDI_SUCCESS) {
29029e83d4bSgd78059 mac_fini_ops(&mxfe_devops);
29129e83d4bSgd78059 }
29229e83d4bSgd78059 return (rv);
29329e83d4bSgd78059 }
29429e83d4bSgd78059
29529e83d4bSgd78059 int
_info(struct modinfo * modinfop)29629e83d4bSgd78059 _info(struct modinfo *modinfop)
29729e83d4bSgd78059 {
29829e83d4bSgd78059 return (mod_info(&mxfe_modlinkage, modinfop));
29929e83d4bSgd78059 }
30029e83d4bSgd78059
30129e83d4bSgd78059 int
mxfe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)30229e83d4bSgd78059 mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
30329e83d4bSgd78059 {
30429e83d4bSgd78059 mxfe_t *mxfep;
30529e83d4bSgd78059 mac_register_t *macp;
30629e83d4bSgd78059 int inst = ddi_get_instance(dip);
30729e83d4bSgd78059 ddi_acc_handle_t pci;
30829e83d4bSgd78059 uint16_t venid;
30929e83d4bSgd78059 uint16_t devid;
31029e83d4bSgd78059 uint16_t revid;
31129e83d4bSgd78059 uint16_t svid;
31229e83d4bSgd78059 uint16_t ssid;
31329e83d4bSgd78059 uint16_t cachesize;
31429e83d4bSgd78059 mxfe_card_t *cardp;
31529e83d4bSgd78059 int i;
31629e83d4bSgd78059
31729e83d4bSgd78059 switch (cmd) {
31829e83d4bSgd78059 case DDI_RESUME:
31929e83d4bSgd78059 return (mxfe_resume(dip));
32029e83d4bSgd78059
32129e83d4bSgd78059 case DDI_ATTACH:
32229e83d4bSgd78059 break;
32329e83d4bSgd78059
32429e83d4bSgd78059 default:
32529e83d4bSgd78059 return (DDI_FAILURE);
32629e83d4bSgd78059 }
32729e83d4bSgd78059
32829e83d4bSgd78059 /* this card is a bus master, reject any slave-only slot */
32929e83d4bSgd78059 if (ddi_slaveonly(dip) == DDI_SUCCESS) {
33029e83d4bSgd78059 mxfe_error(dip, "slot does not support PCI bus-master");
33129e83d4bSgd78059 return (DDI_FAILURE);
33229e83d4bSgd78059 }
33329e83d4bSgd78059 /* PCI devices shouldn't generate hilevel interrupts */
33429e83d4bSgd78059 if (ddi_intr_hilevel(dip, 0) != 0) {
33529e83d4bSgd78059 mxfe_error(dip, "hilevel interrupts not supported");
33629e83d4bSgd78059 return (DDI_FAILURE);
33729e83d4bSgd78059 }
33829e83d4bSgd78059 if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
33929e83d4bSgd78059 mxfe_error(dip, "unable to setup PCI config handle");
34029e83d4bSgd78059 return (DDI_FAILURE);
34129e83d4bSgd78059 }
34229e83d4bSgd78059
34329e83d4bSgd78059 venid = pci_config_get16(pci, PCI_VID);
34429e83d4bSgd78059 devid = pci_config_get16(pci, PCI_DID);
34529e83d4bSgd78059 revid = pci_config_get16(pci, PCI_RID);
34629e83d4bSgd78059 svid = pci_config_get16(pci, PCI_SVID);
34729e83d4bSgd78059 ssid = pci_config_get16(pci, PCI_SSID);
34829e83d4bSgd78059
34929e83d4bSgd78059 /*
35029e83d4bSgd78059 * the last entry in the card table matches every possible
35129e83d4bSgd78059 * card, so the for-loop always terminates properly.
35229e83d4bSgd78059 */
35329e83d4bSgd78059 cardp = NULL;
35429e83d4bSgd78059 for (i = 0; i < (sizeof (mxfe_cards) / sizeof (mxfe_card_t)); i++) {
35529e83d4bSgd78059 if ((venid == mxfe_cards[i].card_venid) &&
35629e83d4bSgd78059 (devid == mxfe_cards[i].card_devid) &&
35729e83d4bSgd78059 ((revid & mxfe_cards[i].card_revmask) ==
35829e83d4bSgd78059 mxfe_cards[i].card_revid)) {
35929e83d4bSgd78059 cardp = &mxfe_cards[i];
36029e83d4bSgd78059 }
36129e83d4bSgd78059 if ((svid == mxfe_cards[i].card_venid) &&
36229e83d4bSgd78059 (ssid == mxfe_cards[i].card_devid) &&
36329e83d4bSgd78059 ((revid & mxfe_cards[i].card_revmask) ==
36429e83d4bSgd78059 mxfe_cards[i].card_revid)) {
36529e83d4bSgd78059 cardp = &mxfe_cards[i];
36629e83d4bSgd78059 break;
36729e83d4bSgd78059 }
36829e83d4bSgd78059 }
36929e83d4bSgd78059
37029e83d4bSgd78059 if (cardp == NULL) {
37129e83d4bSgd78059 pci_config_teardown(&pci);
37229e83d4bSgd78059 mxfe_error(dip, "Unable to identify PCI card");
37329e83d4bSgd78059 return (DDI_FAILURE);
37429e83d4bSgd78059 }
37529e83d4bSgd78059
37629e83d4bSgd78059 if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
37729e83d4bSgd78059 cardp->card_cardname) != DDI_PROP_SUCCESS) {
37829e83d4bSgd78059 pci_config_teardown(&pci);
37929e83d4bSgd78059 mxfe_error(dip, "Unable to create model property");
38029e83d4bSgd78059 return (DDI_FAILURE);
38129e83d4bSgd78059 }
38229e83d4bSgd78059
38329e83d4bSgd78059 /*
38429e83d4bSgd78059 * Grab the PCI cachesize -- we use this to program the
38529e83d4bSgd78059 * cache-optimization bus access bits.
38629e83d4bSgd78059 */
38729e83d4bSgd78059 cachesize = pci_config_get8(pci, PCI_CLS);
38829e83d4bSgd78059
38929e83d4bSgd78059 /* this cannot fail */
39029e83d4bSgd78059 mxfep = kmem_zalloc(sizeof (mxfe_t), KM_SLEEP);
39129e83d4bSgd78059 ddi_set_driver_private(dip, mxfep);
39229e83d4bSgd78059
39329e83d4bSgd78059 /* get the interrupt block cookie */
39429e83d4bSgd78059 if (ddi_get_iblock_cookie(dip, 0, &mxfep->mxfe_icookie)
39529e83d4bSgd78059 != DDI_SUCCESS) {
39629e83d4bSgd78059 mxfe_error(dip, "ddi_get_iblock_cookie failed");
39729e83d4bSgd78059 pci_config_teardown(&pci);
39829e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t));
39929e83d4bSgd78059 return (DDI_FAILURE);
40029e83d4bSgd78059 }
40129e83d4bSgd78059
40229e83d4bSgd78059 mxfep->mxfe_dip = dip;
40329e83d4bSgd78059 mxfep->mxfe_cardp = cardp;
40429e83d4bSgd78059 mxfep->mxfe_phyaddr = -1;
40529e83d4bSgd78059 mxfep->mxfe_cachesize = cachesize;
40629e83d4bSgd78059
40729e83d4bSgd78059 /* default properties */
40829e83d4bSgd78059 mxfep->mxfe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
40929e83d4bSgd78059 "adv_autoneg_cap", 1);
41029e83d4bSgd78059 mxfep->mxfe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
41129e83d4bSgd78059 "adv_100T4_cap", 1);
41229e83d4bSgd78059 mxfep->mxfe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
41329e83d4bSgd78059 "adv_100fdx_cap", 1);
41429e83d4bSgd78059 mxfep->mxfe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
41529e83d4bSgd78059 "adv_100hdx_cap", 1);
41629e83d4bSgd78059 mxfep->mxfe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
41729e83d4bSgd78059 "adv_10fdx_cap", 1);
41829e83d4bSgd78059 mxfep->mxfe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
41929e83d4bSgd78059 "adv_10hdx_cap", 1);
42029e83d4bSgd78059
42129e83d4bSgd78059 DBG(DPCI, "PCI vendor id = %x", venid);
42229e83d4bSgd78059 DBG(DPCI, "PCI device id = %x", devid);
42329e83d4bSgd78059 DBG(DPCI, "PCI revision id = %x", revid);
42429e83d4bSgd78059 DBG(DPCI, "PCI cachesize = %d", cachesize);
42529e83d4bSgd78059 DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD));
42629e83d4bSgd78059 DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT));
42729e83d4bSgd78059
42829e83d4bSgd78059 mutex_init(&mxfep->mxfe_xmtlock, NULL, MUTEX_DRIVER,
42929e83d4bSgd78059 mxfep->mxfe_icookie);
43029e83d4bSgd78059 mutex_init(&mxfep->mxfe_intrlock, NULL, MUTEX_DRIVER,
43129e83d4bSgd78059 mxfep->mxfe_icookie);
43229e83d4bSgd78059
43329e83d4bSgd78059 /*
43429e83d4bSgd78059 * Enable bus master, IO space, and memory space accesses.
43529e83d4bSgd78059 */
43629e83d4bSgd78059 pci_config_put16(pci, PCI_CMD,
43729e83d4bSgd78059 pci_config_get16(pci, PCI_CMD) |
43829e83d4bSgd78059 PCI_CMD_BME | PCI_CMD_MAE | PCI_CMD_MWIE);
43929e83d4bSgd78059
44029e83d4bSgd78059 /* we're done with this now, drop it */
44129e83d4bSgd78059 pci_config_teardown(&pci);
44229e83d4bSgd78059
44329e83d4bSgd78059 /*
44429e83d4bSgd78059 * Initialize interrupt kstat. This should not normally fail, since
44529e83d4bSgd78059 * we don't use a persistent stat. We do it this way to avoid having
44629e83d4bSgd78059 * to test for it at run time on the hot path.
44729e83d4bSgd78059 */
44829e83d4bSgd78059 mxfep->mxfe_intrstat = kstat_create("mxfe", inst, "intr", "controller",
44929e83d4bSgd78059 KSTAT_TYPE_INTR, 1, 0);
45029e83d4bSgd78059 if (mxfep->mxfe_intrstat == NULL) {
45129e83d4bSgd78059 mxfe_error(dip, "kstat_create failed");
45229e83d4bSgd78059 goto failed;
45329e83d4bSgd78059 }
45429e83d4bSgd78059 kstat_install(mxfep->mxfe_intrstat);
45529e83d4bSgd78059
45629e83d4bSgd78059 /*
45729e83d4bSgd78059 * Map in the device registers.
45829e83d4bSgd78059 */
45929e83d4bSgd78059 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mxfep->mxfe_regs,
46029e83d4bSgd78059 0, 0, &mxfe_devattr, &mxfep->mxfe_regshandle)) {
46129e83d4bSgd78059 mxfe_error(dip, "ddi_regs_map_setup failed");
46229e83d4bSgd78059 goto failed;
46329e83d4bSgd78059 }
46429e83d4bSgd78059
46529e83d4bSgd78059 /*
46629e83d4bSgd78059 * Allocate DMA resources (descriptor rings and buffers).
46729e83d4bSgd78059 */
46829e83d4bSgd78059 if ((mxfe_allocrxring(mxfep) != DDI_SUCCESS) ||
46929e83d4bSgd78059 (mxfe_alloctxring(mxfep) != DDI_SUCCESS)) {
47029e83d4bSgd78059 mxfe_error(dip, "unable to allocate DMA resources");
47129e83d4bSgd78059 goto failed;
47229e83d4bSgd78059 }
47329e83d4bSgd78059
47429e83d4bSgd78059 /* Initialize the chip. */
47529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
47629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
47729e83d4bSgd78059 if (!mxfe_initialize(mxfep)) {
47829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
47929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
48029e83d4bSgd78059 goto failed;
48129e83d4bSgd78059 }
48229e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
48329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
48429e83d4bSgd78059
48529e83d4bSgd78059 /* Determine the number of address bits to our EEPROM. */
48629e83d4bSgd78059 mxfep->mxfe_sromwidth = mxfe_sromwidth(mxfep);
48729e83d4bSgd78059
48829e83d4bSgd78059 /*
48929e83d4bSgd78059 * Get the factory ethernet address. This becomes the current
49029e83d4bSgd78059 * ethernet address (it can be overridden later via ifconfig).
49129e83d4bSgd78059 */
49229e83d4bSgd78059 mxfe_getfactaddr(mxfep, mxfep->mxfe_curraddr);
49329e83d4bSgd78059 mxfep->mxfe_promisc = B_FALSE;
49429e83d4bSgd78059
49529e83d4bSgd78059 /*
49629e83d4bSgd78059 * Establish interrupt handler.
49729e83d4bSgd78059 */
49829e83d4bSgd78059 if (ddi_add_intr(dip, 0, NULL, NULL, mxfe_intr, (caddr_t)mxfep) !=
49929e83d4bSgd78059 DDI_SUCCESS) {
50029e83d4bSgd78059 mxfe_error(dip, "unable to add interrupt");
50129e83d4bSgd78059 goto failed;
50229e83d4bSgd78059 }
50329e83d4bSgd78059
50429e83d4bSgd78059 /* TODO: do the power management stuff */
50529e83d4bSgd78059
50629e83d4bSgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
50729e83d4bSgd78059 mxfe_error(dip, "mac_alloc failed");
50829e83d4bSgd78059 goto failed;
50929e83d4bSgd78059 }
51029e83d4bSgd78059
51129e83d4bSgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
51229e83d4bSgd78059 macp->m_driver = mxfep;
51329e83d4bSgd78059 macp->m_dip = dip;
51429e83d4bSgd78059 macp->m_src_addr = mxfep->mxfe_curraddr;
51529e83d4bSgd78059 macp->m_callbacks = &mxfe_m_callbacks;
51629e83d4bSgd78059 macp->m_min_sdu = 0;
51729e83d4bSgd78059 macp->m_max_sdu = ETHERMTU;
518d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ;
51929e83d4bSgd78059
52029e83d4bSgd78059 if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) {
52129e83d4bSgd78059 mac_free(macp);
52229e83d4bSgd78059 return (DDI_SUCCESS);
52329e83d4bSgd78059 }
52429e83d4bSgd78059
52529e83d4bSgd78059 /* failed to register with MAC */
52629e83d4bSgd78059 mac_free(macp);
52729e83d4bSgd78059 failed:
52829e83d4bSgd78059 if (mxfep->mxfe_icookie != NULL) {
52929e83d4bSgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
53029e83d4bSgd78059 }
53129e83d4bSgd78059 if (mxfep->mxfe_intrstat) {
53229e83d4bSgd78059 kstat_delete(mxfep->mxfe_intrstat);
53329e83d4bSgd78059 }
53429e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_intrlock);
53529e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_xmtlock);
53629e83d4bSgd78059
53729e83d4bSgd78059 mxfe_freerxring(mxfep);
53829e83d4bSgd78059 mxfe_freetxring(mxfep);
53929e83d4bSgd78059
54029e83d4bSgd78059 if (mxfep->mxfe_regshandle != NULL) {
54129e83d4bSgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle);
54229e83d4bSgd78059 }
54329e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t));
54429e83d4bSgd78059 return (DDI_FAILURE);
54529e83d4bSgd78059 }
54629e83d4bSgd78059
54729e83d4bSgd78059 int
mxfe_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)54829e83d4bSgd78059 mxfe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
54929e83d4bSgd78059 {
55029e83d4bSgd78059 mxfe_t *mxfep;
55129e83d4bSgd78059
55229e83d4bSgd78059 mxfep = ddi_get_driver_private(dip);
55329e83d4bSgd78059 if (mxfep == NULL) {
55429e83d4bSgd78059 mxfe_error(dip, "no soft state in detach!");
55529e83d4bSgd78059 return (DDI_FAILURE);
55629e83d4bSgd78059 }
55729e83d4bSgd78059
55829e83d4bSgd78059 switch (cmd) {
55929e83d4bSgd78059 case DDI_DETACH:
56029e83d4bSgd78059
56129e83d4bSgd78059 if (mac_unregister(mxfep->mxfe_mh) != 0) {
56229e83d4bSgd78059 return (DDI_FAILURE);
56329e83d4bSgd78059 }
56429e83d4bSgd78059
56529e83d4bSgd78059 /* make sure hardware is quiesced */
56629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
56729e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
56829e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING;
56929e83d4bSgd78059 mxfe_stopall(mxfep);
57029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
57129e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
57229e83d4bSgd78059
57329e83d4bSgd78059 /* clean up and shut down device */
57429e83d4bSgd78059 ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
57529e83d4bSgd78059
57629e83d4bSgd78059 /* clean up kstats */
57729e83d4bSgd78059 kstat_delete(mxfep->mxfe_intrstat);
57829e83d4bSgd78059
57929e83d4bSgd78059 ddi_prop_remove_all(dip);
58029e83d4bSgd78059
58129e83d4bSgd78059 /* free up any left over buffers or DMA resources */
58229e83d4bSgd78059 mxfe_freerxring(mxfep);
58329e83d4bSgd78059 mxfe_freetxring(mxfep);
58429e83d4bSgd78059
58529e83d4bSgd78059 ddi_regs_map_free(&mxfep->mxfe_regshandle);
58629e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_intrlock);
58729e83d4bSgd78059 mutex_destroy(&mxfep->mxfe_xmtlock);
58829e83d4bSgd78059
58929e83d4bSgd78059 kmem_free(mxfep, sizeof (mxfe_t));
59029e83d4bSgd78059 return (DDI_SUCCESS);
59129e83d4bSgd78059
59229e83d4bSgd78059 case DDI_SUSPEND:
59329e83d4bSgd78059 /* quiesce the hardware */
59429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
59529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
59629e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED;
59729e83d4bSgd78059 mxfe_stopall(mxfep);
59829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
59929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
60029e83d4bSgd78059 return (DDI_SUCCESS);
60129e83d4bSgd78059 default:
60229e83d4bSgd78059 return (DDI_FAILURE);
60329e83d4bSgd78059 }
60429e83d4bSgd78059 }
60529e83d4bSgd78059
60629e83d4bSgd78059 int
mxfe_resume(dev_info_t * dip)60729e83d4bSgd78059 mxfe_resume(dev_info_t *dip)
60829e83d4bSgd78059 {
60929e83d4bSgd78059 mxfe_t *mxfep;
61029e83d4bSgd78059
61129e83d4bSgd78059 if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
61229e83d4bSgd78059 return (DDI_FAILURE);
61329e83d4bSgd78059 }
61429e83d4bSgd78059
61529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
61629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
61729e83d4bSgd78059
61829e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_SUSPENDED;
61929e83d4bSgd78059
62029e83d4bSgd78059 /* re-initialize chip */
62129e83d4bSgd78059 if (!mxfe_initialize(mxfep)) {
62229e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "unable to resume chip!");
62329e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_SUSPENDED;
62429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
62529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
62629e83d4bSgd78059 return (DDI_SUCCESS);
62729e83d4bSgd78059 }
62829e83d4bSgd78059
62929e83d4bSgd78059 /* start the chip */
63029e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING) {
63129e83d4bSgd78059 mxfe_startall(mxfep);
63229e83d4bSgd78059 }
63329e83d4bSgd78059
63429e83d4bSgd78059 /* drop locks */
63529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
63629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
63729e83d4bSgd78059
63829e83d4bSgd78059 return (DDI_SUCCESS);
63929e83d4bSgd78059 }
64029e83d4bSgd78059
64177860f66SGarrett D'Amore int
mxfe_quiesce(dev_info_t * dip)64277860f66SGarrett D'Amore mxfe_quiesce(dev_info_t *dip)
64377860f66SGarrett D'Amore {
64477860f66SGarrett D'Amore mxfe_t *mxfep;
64577860f66SGarrett D'Amore
64677860f66SGarrett D'Amore if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
64777860f66SGarrett D'Amore return (DDI_FAILURE);
64877860f66SGarrett D'Amore }
64977860f66SGarrett D'Amore
65077860f66SGarrett D'Amore /* just do a hard reset of everything */
65177860f66SGarrett D'Amore SETBIT(mxfep, CSR_PAR, PAR_RESET);
65277860f66SGarrett D'Amore
65377860f66SGarrett D'Amore return (DDI_SUCCESS);
65477860f66SGarrett D'Amore }
65577860f66SGarrett D'Amore
65629e83d4bSgd78059 /*ARGSUSED*/
65729e83d4bSgd78059 int
mxfe_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)65829e83d4bSgd78059 mxfe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
65929e83d4bSgd78059 {
66029e83d4bSgd78059 /* we already receive all multicast frames */
66129e83d4bSgd78059 return (0);
66229e83d4bSgd78059 }
66329e83d4bSgd78059
66429e83d4bSgd78059 int
mxfe_m_promisc(void * arg,boolean_t on)66529e83d4bSgd78059 mxfe_m_promisc(void *arg, boolean_t on)
66629e83d4bSgd78059 {
66729e83d4bSgd78059 mxfe_t *mxfep = arg;
66829e83d4bSgd78059
66929e83d4bSgd78059 /* exclusive access to the card while we reprogram it */
67029e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
67129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
67229e83d4bSgd78059 /* save current promiscuous mode state for replay in resume */
67329e83d4bSgd78059 mxfep->mxfe_promisc = on;
67429e83d4bSgd78059
67529e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
67629e83d4bSgd78059 MXFE_RUNNING) {
67729e83d4bSgd78059 if (on)
67829e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
67929e83d4bSgd78059 else
68029e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
68129e83d4bSgd78059 }
68229e83d4bSgd78059
68329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
68429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
68529e83d4bSgd78059
68629e83d4bSgd78059 return (0);
68729e83d4bSgd78059 }
68829e83d4bSgd78059
68929e83d4bSgd78059 int
mxfe_m_unicst(void * arg,const uint8_t * macaddr)69029e83d4bSgd78059 mxfe_m_unicst(void *arg, const uint8_t *macaddr)
69129e83d4bSgd78059 {
69229e83d4bSgd78059 mxfe_t *mxfep = arg;
69329e83d4bSgd78059
69429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
69529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
69629e83d4bSgd78059 bcopy(macaddr, mxfep->mxfe_curraddr, ETHERADDRL);
69729e83d4bSgd78059
69829e83d4bSgd78059 mxfe_resetall(mxfep);
69929e83d4bSgd78059
70029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
70129e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
70229e83d4bSgd78059
70329e83d4bSgd78059 return (0);
70429e83d4bSgd78059 }
70529e83d4bSgd78059
70629e83d4bSgd78059 mblk_t *
mxfe_m_tx(void * arg,mblk_t * mp)70729e83d4bSgd78059 mxfe_m_tx(void *arg, mblk_t *mp)
70829e83d4bSgd78059 {
70929e83d4bSgd78059 mxfe_t *mxfep = arg;
71029e83d4bSgd78059 mblk_t *nmp;
71129e83d4bSgd78059
71229e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
71329e83d4bSgd78059
71429e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
71529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
71629e83d4bSgd78059 return (mp);
71729e83d4bSgd78059 }
71829e83d4bSgd78059
71929e83d4bSgd78059 while (mp != NULL) {
72029e83d4bSgd78059 nmp = mp->b_next;
72129e83d4bSgd78059 mp->b_next = NULL;
72229e83d4bSgd78059
72329e83d4bSgd78059 if (!mxfe_send(mxfep, mp)) {
72429e83d4bSgd78059 mp->b_next = nmp;
72529e83d4bSgd78059 break;
72629e83d4bSgd78059 }
72729e83d4bSgd78059 mp = nmp;
72829e83d4bSgd78059 }
72929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
73029e83d4bSgd78059
73129e83d4bSgd78059 return (mp);
73229e83d4bSgd78059 }
73329e83d4bSgd78059
73429e83d4bSgd78059 /*
73529e83d4bSgd78059 * Hardware management.
73629e83d4bSgd78059 */
73729e83d4bSgd78059 boolean_t
mxfe_initialize(mxfe_t * mxfep)73829e83d4bSgd78059 mxfe_initialize(mxfe_t *mxfep)
73929e83d4bSgd78059 {
74029e83d4bSgd78059 int i;
74129e83d4bSgd78059 unsigned val;
74229e83d4bSgd78059 uint32_t par, nar;
74329e83d4bSgd78059
74429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
74529e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
74629e83d4bSgd78059
74729e83d4bSgd78059 DBG(DCHATTY, "resetting!");
74829e83d4bSgd78059 SETBIT(mxfep, CSR_PAR, PAR_RESET);
74929e83d4bSgd78059 for (i = 1; i < 10; i++) {
75029e83d4bSgd78059 drv_usecwait(5);
75129e83d4bSgd78059 val = GETCSR(mxfep, CSR_PAR);
75229e83d4bSgd78059 if (!(val & PAR_RESET)) {
75329e83d4bSgd78059 break;
75429e83d4bSgd78059 }
75529e83d4bSgd78059 }
75629e83d4bSgd78059 if (i == 10) {
75729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "timed out waiting for reset!");
75829e83d4bSgd78059 return (B_FALSE);
75929e83d4bSgd78059 }
76029e83d4bSgd78059
76129e83d4bSgd78059 /* initialize busctl register */
76229e83d4bSgd78059 par = PAR_BAR | PAR_MRME | PAR_MRLE | PAR_MWIE;
76329e83d4bSgd78059
76429e83d4bSgd78059 /* set the cache alignment if its supported */
76529e83d4bSgd78059 switch (mxfep->mxfe_cachesize) {
76629e83d4bSgd78059 case 8:
76729e83d4bSgd78059 par |= PAR_CALIGN_8;
76829e83d4bSgd78059 break;
76929e83d4bSgd78059 case 16:
77029e83d4bSgd78059 par |= PAR_CALIGN_16;
77129e83d4bSgd78059 break;
77229e83d4bSgd78059 case 32:
77329e83d4bSgd78059 par |= PAR_CALIGN_32;
77429e83d4bSgd78059 break;
77529e83d4bSgd78059 default:
77629e83d4bSgd78059 par &= ~(PAR_MWIE | PAR_MRME | PAR_MRLE);
77729e83d4bSgd78059 }
77829e83d4bSgd78059
77929e83d4bSgd78059 /* leave the burst length at zero, indicating infinite burst */
78029e83d4bSgd78059 PUTCSR(mxfep, CSR_PAR, par);
78129e83d4bSgd78059
78229e83d4bSgd78059 mxfe_resetrings(mxfep);
78329e83d4bSgd78059
78429e83d4bSgd78059 /* clear the lost packet counter (cleared on read) */
78529e83d4bSgd78059 (void) GETCSR(mxfep, CSR_LPC);
78629e83d4bSgd78059
78729e83d4bSgd78059 /* a few other NAR bits */
78829e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
78929e83d4bSgd78059 nar &= ~NAR_RX_HO; /* disable hash only filtering */
79029e83d4bSgd78059 nar |= NAR_RX_HP; /* hash perfect forwarding */
79129e83d4bSgd78059 nar |= NAR_RX_MULTI; /* receive all multicast */
79229e83d4bSgd78059 nar |= NAR_SF; /* store-and-forward */
79329e83d4bSgd78059
79429e83d4bSgd78059 if (mxfep->mxfe_promisc) {
79529e83d4bSgd78059 nar |= NAR_RX_PROMISC;
79629e83d4bSgd78059 } else {
79729e83d4bSgd78059 nar &= ~NAR_RX_PROMISC;
79829e83d4bSgd78059 }
79929e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
80029e83d4bSgd78059
80129e83d4bSgd78059 mxfe_send_setup(mxfep);
80229e83d4bSgd78059
80329e83d4bSgd78059 return (B_TRUE);
80429e83d4bSgd78059 }
80529e83d4bSgd78059
80629e83d4bSgd78059 /*
80729e83d4bSgd78059 * Serial EEPROM access - inspired by the FreeBSD implementation.
80829e83d4bSgd78059 */
80929e83d4bSgd78059
81029e83d4bSgd78059 uint8_t
mxfe_sromwidth(mxfe_t * mxfep)81129e83d4bSgd78059 mxfe_sromwidth(mxfe_t *mxfep)
81229e83d4bSgd78059 {
81329e83d4bSgd78059 int i;
81429e83d4bSgd78059 int eeread;
81529e83d4bSgd78059 uint8_t addrlen = 8;
81629e83d4bSgd78059
81729e83d4bSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
81829e83d4bSgd78059
81929e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
82029e83d4bSgd78059 drv_usecwait(1);
82129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
82229e83d4bSgd78059
82329e83d4bSgd78059 /* command bits first */
82429e83d4bSgd78059 for (i = 4; i != 0; i >>= 1) {
82529e83d4bSgd78059 unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0;
82629e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val);
82729e83d4bSgd78059 drv_usecwait(1);
82829e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
82929e83d4bSgd78059 drv_usecwait(1);
83029e83d4bSgd78059 }
83129e83d4bSgd78059
83229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
83329e83d4bSgd78059
83429e83d4bSgd78059 for (addrlen = 1; addrlen <= 12; addrlen++) {
83529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
83629e83d4bSgd78059 drv_usecwait(1);
83729e83d4bSgd78059 if (!(GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT)) {
83829e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
83929e83d4bSgd78059 drv_usecwait(1);
84029e83d4bSgd78059 break;
84129e83d4bSgd78059 }
84229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
84329e83d4bSgd78059 drv_usecwait(1);
84429e83d4bSgd78059 }
84529e83d4bSgd78059
84629e83d4bSgd78059 /* turn off accesses to the EEPROM */
84729e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
84829e83d4bSgd78059
84929e83d4bSgd78059 DBG(DSROM, "detected srom width = %d bits", addrlen);
85029e83d4bSgd78059
85129e83d4bSgd78059 return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen);
85229e83d4bSgd78059 }
85329e83d4bSgd78059
85429e83d4bSgd78059 /*
85529e83d4bSgd78059 * The words in EEPROM are stored in little endian order. We
85629e83d4bSgd78059 * shift bits out in big endian order, though. This requires
85729e83d4bSgd78059 * a byte swap on some platforms.
85829e83d4bSgd78059 */
85929e83d4bSgd78059 uint16_t
mxfe_readsromword(mxfe_t * mxfep,unsigned romaddr)86029e83d4bSgd78059 mxfe_readsromword(mxfe_t *mxfep, unsigned romaddr)
86129e83d4bSgd78059 {
86229e83d4bSgd78059 int i;
86329e83d4bSgd78059 uint16_t word = 0;
86429e83d4bSgd78059 uint16_t retval;
86529e83d4bSgd78059 int eeread;
86629e83d4bSgd78059 uint8_t addrlen;
86729e83d4bSgd78059 int readcmd;
86829e83d4bSgd78059 uchar_t *ptr;
86929e83d4bSgd78059
87029e83d4bSgd78059 eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
87129e83d4bSgd78059 addrlen = mxfep->mxfe_sromwidth;
87229e83d4bSgd78059 readcmd = (SROM_READCMD << addrlen) | romaddr;
87329e83d4bSgd78059
87429e83d4bSgd78059 if (romaddr >= (1 << addrlen)) {
87529e83d4bSgd78059 /* too big to fit! */
87629e83d4bSgd78059 return (0);
87729e83d4bSgd78059 }
87829e83d4bSgd78059
87929e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
88029e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
88129e83d4bSgd78059
88229e83d4bSgd78059 /* command and address bits */
88329e83d4bSgd78059 for (i = 4 + addrlen; i >= 0; i--) {
88429e83d4bSgd78059 short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0;
88529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val);
88629e83d4bSgd78059 drv_usecwait(1);
88729e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
88829e83d4bSgd78059 drv_usecwait(1);
88929e83d4bSgd78059 }
89029e83d4bSgd78059
89129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
89229e83d4bSgd78059
89329e83d4bSgd78059 for (i = 0; i < 16; i++) {
89429e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
89529e83d4bSgd78059 drv_usecwait(1);
89629e83d4bSgd78059 word <<= 1;
89729e83d4bSgd78059 if (GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT) {
89829e83d4bSgd78059 word |= 1;
89929e83d4bSgd78059 }
90029e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread);
90129e83d4bSgd78059 drv_usecwait(1);
90229e83d4bSgd78059 }
90329e83d4bSgd78059
90429e83d4bSgd78059 /* turn off accesses to the EEPROM */
90529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
90629e83d4bSgd78059
90729e83d4bSgd78059 /*
90829e83d4bSgd78059 * Fix up the endianness thing. Note that the values
90929e83d4bSgd78059 * are stored in little endian format on the SROM.
91029e83d4bSgd78059 */
91129e83d4bSgd78059 DBG(DSROM, "got value %d from SROM (before swap)", word);
91229e83d4bSgd78059 ptr = (uchar_t *)&word;
91329e83d4bSgd78059 retval = (ptr[1] << 8) | ptr[0];
91429e83d4bSgd78059 return (retval);
91529e83d4bSgd78059 }
91629e83d4bSgd78059
91729e83d4bSgd78059 void
mxfe_readsrom(mxfe_t * mxfep,unsigned romaddr,unsigned len,void * dest)91829e83d4bSgd78059 mxfe_readsrom(mxfe_t *mxfep, unsigned romaddr, unsigned len, void *dest)
91929e83d4bSgd78059 {
92029e83d4bSgd78059 char *ptr = dest;
92129e83d4bSgd78059 int i;
92229e83d4bSgd78059 uint16_t word;
92329e83d4bSgd78059
92429e83d4bSgd78059 for (i = 0; i < len; i++) {
92529e83d4bSgd78059 word = mxfe_readsromword(mxfep, romaddr + i);
92629e83d4bSgd78059 bcopy(&word, ptr, 2);
92729e83d4bSgd78059 ptr += 2;
92829e83d4bSgd78059 DBG(DSROM, "word at %d is 0x%x", romaddr + i, word);
92929e83d4bSgd78059 }
93029e83d4bSgd78059 }
93129e83d4bSgd78059
93229e83d4bSgd78059 void
mxfe_getfactaddr(mxfe_t * mxfep,uchar_t * eaddr)93329e83d4bSgd78059 mxfe_getfactaddr(mxfe_t *mxfep, uchar_t *eaddr)
93429e83d4bSgd78059 {
93529e83d4bSgd78059 uint16_t word;
93629e83d4bSgd78059 uchar_t *ptr;
93729e83d4bSgd78059
93829e83d4bSgd78059 /* first read to get the location of mac address in srom */
93929e83d4bSgd78059 word = mxfe_readsromword(mxfep, SROM_ENADDR / 2);
94029e83d4bSgd78059 ptr = (uchar_t *)&word;
94129e83d4bSgd78059 word = (ptr[1] << 8) | ptr[0];
94229e83d4bSgd78059
94329e83d4bSgd78059 /* then read the actual mac address */
94429e83d4bSgd78059 mxfe_readsrom(mxfep, word / 2, ETHERADDRL / 2, eaddr);
94529e83d4bSgd78059 DBG(DMACID,
94629e83d4bSgd78059 "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x",
94729e83d4bSgd78059 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
94829e83d4bSgd78059 }
94929e83d4bSgd78059
95029e83d4bSgd78059 void
mxfe_startphy(mxfe_t * mxfep)95129e83d4bSgd78059 mxfe_startphy(mxfe_t *mxfep)
95229e83d4bSgd78059 {
95329e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) {
95429e83d4bSgd78059 case MXFE_98713A:
95529e83d4bSgd78059 mxfe_startphymii(mxfep);
95629e83d4bSgd78059 break;
95729e83d4bSgd78059 default:
95829e83d4bSgd78059 mxfe_startphynway(mxfep);
95929e83d4bSgd78059 break;
96029e83d4bSgd78059 }
96129e83d4bSgd78059 }
96229e83d4bSgd78059
96329e83d4bSgd78059 void
mxfe_stopphy(mxfe_t * mxfep)96429e83d4bSgd78059 mxfe_stopphy(mxfe_t *mxfep)
96529e83d4bSgd78059 {
96629e83d4bSgd78059 uint32_t nar;
96729e83d4bSgd78059 int i;
96829e83d4bSgd78059
96929e83d4bSgd78059 /* stop the phy timer */
97029e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, 0);
97129e83d4bSgd78059
97229e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) {
97329e83d4bSgd78059 case MXFE_98713A:
97429e83d4bSgd78059 for (i = 0; i < 32; i++) {
97529e83d4bSgd78059 mxfe_miiwrite(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL,
97629e83d4bSgd78059 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
97729e83d4bSgd78059 }
97829e83d4bSgd78059 break;
97929e83d4bSgd78059 default:
98029e83d4bSgd78059 DBG(DPHY, "resetting SIA");
98129e83d4bSgd78059 PUTCSR(mxfep, CSR_SIA, SIA_RESET);
98229e83d4bSgd78059 drv_usecwait(500);
98329e83d4bSgd78059 CLRBIT(mxfep, CSR_TCTL, TCTL_PWR | TCTL_ANE);
98429e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
98529e83d4bSgd78059 nar &= ~(NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX);
98629e83d4bSgd78059 nar |= NAR_SPEED;
98729e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
98829e83d4bSgd78059 break;
98929e83d4bSgd78059 }
99029e83d4bSgd78059
99129e83d4bSgd78059 /*
99229e83d4bSgd78059 * mark the link state unknown
99329e83d4bSgd78059 */
99429e83d4bSgd78059 if (!mxfep->mxfe_resetting) {
99529e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UNKNOWN;
99629e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
99729e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
99829e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
99929e83d4bSgd78059 mxfe_reportlink(mxfep);
100029e83d4bSgd78059 }
100129e83d4bSgd78059 }
100229e83d4bSgd78059
100329e83d4bSgd78059 /*
100429e83d4bSgd78059 * NWay support.
100529e83d4bSgd78059 */
100629e83d4bSgd78059 void
mxfe_startnway(mxfe_t * mxfep)100729e83d4bSgd78059 mxfe_startnway(mxfe_t *mxfep)
100829e83d4bSgd78059 {
100929e83d4bSgd78059 unsigned nar;
101029e83d4bSgd78059 unsigned tctl;
101129e83d4bSgd78059 unsigned restart;
101229e83d4bSgd78059
101329e83d4bSgd78059 /* this should not happen in a healthy system */
101496fb08b9Sgd78059 if (mxfep->mxfe_nwaystate != MXFE_NOLINK) {
101529e83d4bSgd78059 DBG(DWARN, "link start called out of state (%x)",
101696fb08b9Sgd78059 mxfep->mxfe_nwaystate);
101729e83d4bSgd78059 return;
101829e83d4bSgd78059 }
101929e83d4bSgd78059
102029e83d4bSgd78059 if (mxfep->mxfe_adv_aneg == 0) {
102129e83d4bSgd78059 /* not done for forced mode */
102229e83d4bSgd78059 return;
102329e83d4bSgd78059 }
102429e83d4bSgd78059
102529e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
102629e83d4bSgd78059 restart = nar & (NAR_TX_ENABLE | NAR_RX_ENABLE);
102729e83d4bSgd78059 nar &= ~restart;
102829e83d4bSgd78059
102929e83d4bSgd78059 if (restart != 0)
103029e83d4bSgd78059 mxfe_stopmac(mxfep);
103129e83d4bSgd78059
103229e83d4bSgd78059 nar |= NAR_SCR | NAR_PCS | NAR_HBD;
103329e83d4bSgd78059 nar &= ~(NAR_FDX);
103429e83d4bSgd78059
103529e83d4bSgd78059 tctl = GETCSR(mxfep, CSR_TCTL);
103629e83d4bSgd78059 tctl &= ~(TCTL_100FDX | TCTL_100HDX | TCTL_HDX);
103729e83d4bSgd78059
103829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) {
103929e83d4bSgd78059 tctl |= TCTL_100FDX;
104029e83d4bSgd78059 }
104129e83d4bSgd78059 if (mxfep->mxfe_adv_100hdx) {
104229e83d4bSgd78059 tctl |= TCTL_100HDX;
104329e83d4bSgd78059 }
104429e83d4bSgd78059 if (mxfep->mxfe_adv_10fdx) {
104529e83d4bSgd78059 nar |= NAR_FDX;
104629e83d4bSgd78059 }
104729e83d4bSgd78059 if (mxfep->mxfe_adv_10hdx) {
104829e83d4bSgd78059 tctl |= TCTL_HDX;
104929e83d4bSgd78059 }
105029e83d4bSgd78059 tctl |= TCTL_PWR | TCTL_ANE | TCTL_LTE | TCTL_RSQ;
105129e83d4bSgd78059
105229e83d4bSgd78059 /* possibly we should add in support for PAUSE frames */
105329e83d4bSgd78059 DBG(DPHY, "writing nar = 0x%x", nar);
105429e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
105529e83d4bSgd78059
105629e83d4bSgd78059 DBG(DPHY, "writing tctl = 0x%x", tctl);
105729e83d4bSgd78059 PUTCSR(mxfep, CSR_TCTL, tctl);
105829e83d4bSgd78059
105929e83d4bSgd78059 /* restart autonegotation */
106029e83d4bSgd78059 DBG(DPHY, "writing tstat = 0x%x", TSTAT_ANS_START);
106129e83d4bSgd78059 PUTCSR(mxfep, CSR_TSTAT, TSTAT_ANS_START);
106229e83d4bSgd78059
106329e83d4bSgd78059 /* restart tx/rx processes... */
106429e83d4bSgd78059 if (restart != 0)
106529e83d4bSgd78059 mxfe_startmac(mxfep);
106629e83d4bSgd78059
106729e83d4bSgd78059 /* Macronix initializations from Bolo Tsai */
106829e83d4bSgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
106929e83d4bSgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000);
107029e83d4bSgd78059
107196fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NWAYCHECK;
107229e83d4bSgd78059 }
107329e83d4bSgd78059
107429e83d4bSgd78059 void
mxfe_checklinknway(mxfe_t * mxfep)107529e83d4bSgd78059 mxfe_checklinknway(mxfe_t *mxfep)
107629e83d4bSgd78059 {
107796fb08b9Sgd78059 unsigned tstat;
107896fb08b9Sgd78059 uint16_t lpar;
107929e83d4bSgd78059
108096fb08b9Sgd78059 DBG(DPHY, "NWay check, state %x", mxfep->mxfe_nwaystate);
108129e83d4bSgd78059 tstat = GETCSR(mxfep, CSR_TSTAT);
108229e83d4bSgd78059 lpar = TSTAT_LPAR(tstat);
108329e83d4bSgd78059
108429e83d4bSgd78059 mxfep->mxfe_anlpar = lpar;
108529e83d4bSgd78059 if (tstat & TSTAT_LPN) {
108629e83d4bSgd78059 mxfep->mxfe_aner |= MII_AN_EXP_LPCANAN;
108729e83d4bSgd78059 } else {
108829e83d4bSgd78059 mxfep->mxfe_aner &= ~(MII_AN_EXP_LPCANAN);
108929e83d4bSgd78059 }
109029e83d4bSgd78059
109129e83d4bSgd78059 DBG(DPHY, "tstat(CSR12) = 0x%x", tstat);
109229e83d4bSgd78059 DBG(DPHY, "ANEG state = 0x%x", (tstat & TSTAT_ANS) >> 12);
109329e83d4bSgd78059
109429e83d4bSgd78059 if ((tstat & TSTAT_ANS) != TSTAT_ANS_OK) {
109529e83d4bSgd78059 /* autoneg did not complete */
109629e83d4bSgd78059 mxfep->mxfe_bmsr &= ~MII_STATUS_ANDONE;
109729e83d4bSgd78059 } else {
109829e83d4bSgd78059 mxfep->mxfe_bmsr |= ~MII_STATUS_ANDONE;
109929e83d4bSgd78059 }
110029e83d4bSgd78059
110129e83d4bSgd78059 if ((tstat & TSTAT_100F) && (tstat & TSTAT_10F)) {
110229e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
110329e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
110429e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
110596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK;
110629e83d4bSgd78059 mxfe_reportlink(mxfep);
110729e83d4bSgd78059 mxfe_startnway(mxfep);
110829e83d4bSgd78059 return;
110929e83d4bSgd78059 }
111029e83d4bSgd78059
111129e83d4bSgd78059 /*
111229e83d4bSgd78059 * if the link is newly up, then we might need to set various
111329e83d4bSgd78059 * mode bits, or negotiate for parameters, etc.
111429e83d4bSgd78059 */
111529e83d4bSgd78059 if (mxfep->mxfe_adv_aneg) {
111629e83d4bSgd78059
111729e83d4bSgd78059 uint16_t anlpar;
111829e83d4bSgd78059
111929e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
112029e83d4bSgd78059 anlpar = mxfep->mxfe_anlpar;
112129e83d4bSgd78059
112229e83d4bSgd78059 if (tstat & TSTAT_LPN) {
112329e83d4bSgd78059 /* partner has NWay */
112429e83d4bSgd78059
112529e83d4bSgd78059 if ((anlpar & MII_ABILITY_100BASE_TX_FD) &&
112629e83d4bSgd78059 mxfep->mxfe_adv_100fdx) {
112729e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
112829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
112929e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_100BASE_TX) &&
113029e83d4bSgd78059 mxfep->mxfe_adv_100hdx) {
113129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
113229e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
113329e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T_FD) &&
113429e83d4bSgd78059 mxfep->mxfe_adv_10fdx) {
113529e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
113629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
113729e83d4bSgd78059 } else if ((anlpar & MII_ABILITY_10BASE_T) &&
113829e83d4bSgd78059 mxfep->mxfe_adv_10hdx) {
113929e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
114029e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
114129e83d4bSgd78059 } else {
114229e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
114329e83d4bSgd78059 }
114429e83d4bSgd78059 } else {
114529e83d4bSgd78059 /* link partner does not have NWay */
114629e83d4bSgd78059 /* just assume half duplex, since we can't detect */
114729e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
114829e83d4bSgd78059 if (!(tstat & TSTAT_100F)) {
114929e83d4bSgd78059 DBG(DPHY, "Partner doesn't have NWAY");
115029e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
115129e83d4bSgd78059 } else {
115229e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
115329e83d4bSgd78059 }
115429e83d4bSgd78059 }
115529e83d4bSgd78059 } else {
115629e83d4bSgd78059 /* forced modes */
115729e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
115829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) {
115929e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
116029e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
116129e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) {
116229e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
116329e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
116429e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) {
116529e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
116629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
116729e83d4bSgd78059 } else if (mxfep->mxfe_adv_10hdx) {
116829e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
116929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
117029e83d4bSgd78059 } else {
117129e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
117229e83d4bSgd78059 }
117329e83d4bSgd78059 }
117429e83d4bSgd78059 mxfe_reportlink(mxfep);
117596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_GOODLINK;
117629e83d4bSgd78059 }
117729e83d4bSgd78059
117829e83d4bSgd78059 void
mxfe_startphynway(mxfe_t * mxfep)117929e83d4bSgd78059 mxfe_startphynway(mxfe_t *mxfep)
118029e83d4bSgd78059 {
118129e83d4bSgd78059 /* take NWay and PHY out of reset */
118229e83d4bSgd78059 PUTCSR(mxfep, CSR_SIA, SIA_NRESET);
118329e83d4bSgd78059 drv_usecwait(500);
118429e83d4bSgd78059
118596fb08b9Sgd78059 mxfep->mxfe_nwaystate = MXFE_NOLINK;
118629e83d4bSgd78059 mxfep->mxfe_bmsr = MII_STATUS_CANAUTONEG |
118729e83d4bSgd78059 MII_STATUS_100_BASEX_FD | MII_STATUS_100_BASEX |
118829e83d4bSgd78059 MII_STATUS_10_FD | MII_STATUS_10;
118996fb08b9Sgd78059 mxfep->mxfe_cap_aneg =
119096fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
119196fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
119229e83d4bSgd78059
119329e83d4bSgd78059 /* lie about the transceiver... its not really 802.3u compliant */
119429e83d4bSgd78059 mxfep->mxfe_phyaddr = 0;
119529e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100X;
119629e83d4bSgd78059 mxfep->mxfe_phyid = 0;
119729e83d4bSgd78059
119829e83d4bSgd78059 /* 100-T4 not supported with NWay */
119929e83d4bSgd78059 mxfep->mxfe_adv_100T4 = 0;
120096fb08b9Sgd78059 mxfep->mxfe_cap_100T4 = 0;
120129e83d4bSgd78059
120229e83d4bSgd78059 /* make sure at least one valid mode is selected */
120329e83d4bSgd78059 if ((!mxfep->mxfe_adv_100fdx) &&
120429e83d4bSgd78059 (!mxfep->mxfe_adv_100hdx) &&
120529e83d4bSgd78059 (!mxfep->mxfe_adv_10fdx) &&
120629e83d4bSgd78059 (!mxfep->mxfe_adv_10hdx)) {
120729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
120829e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
120929e83d4bSgd78059 mxfe_stopphy(mxfep);
121029e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
121129e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
121229e83d4bSgd78059 mxfe_reportlink(mxfep);
121329e83d4bSgd78059 return;
121429e83d4bSgd78059 }
121529e83d4bSgd78059
121629e83d4bSgd78059 if (mxfep->mxfe_adv_aneg == 0) {
121729e83d4bSgd78059 /* forced mode */
121829e83d4bSgd78059 unsigned nar;
121929e83d4bSgd78059 unsigned tctl;
122029e83d4bSgd78059
122129e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
122229e83d4bSgd78059 tctl = GETCSR(mxfep, CSR_TCTL);
122329e83d4bSgd78059
122429e83d4bSgd78059 ASSERT((nar & (NAR_TX_ENABLE | NAR_RX_ENABLE)) == 0);
122529e83d4bSgd78059
122629e83d4bSgd78059 nar &= ~(NAR_FDX | NAR_PORTSEL | NAR_SCR | NAR_SPEED);
122729e83d4bSgd78059 tctl &= ~TCTL_ANE;
122829e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) {
122929e83d4bSgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX;
123029e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) {
123129e83d4bSgd78059 nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR;
123229e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) {
123329e83d4bSgd78059 nar |= NAR_FDX | NAR_SPEED;
123429e83d4bSgd78059 } else { /* mxfep->mxfe_adv_10hdx */
123529e83d4bSgd78059 nar |= NAR_SPEED;
123629e83d4bSgd78059 }
123729e83d4bSgd78059
123829e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
123929e83d4bSgd78059 PUTCSR(mxfep, CSR_TCTL, tctl);
124029e83d4bSgd78059
124129e83d4bSgd78059 /* Macronix initializations from Bolo Tsai */
124229e83d4bSgd78059 PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
124329e83d4bSgd78059 PUTCSR(mxfep, CSR_ACOMP, 0x11000);
124429e83d4bSgd78059 } else {
124529e83d4bSgd78059 mxfe_startnway(mxfep);
124629e83d4bSgd78059 }
124729e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
124829e83d4bSgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC));
124929e83d4bSgd78059 }
125029e83d4bSgd78059
125129e83d4bSgd78059 /*
125229e83d4bSgd78059 * MII management.
125329e83d4bSgd78059 */
125429e83d4bSgd78059 void
mxfe_startphymii(mxfe_t * mxfep)125529e83d4bSgd78059 mxfe_startphymii(mxfe_t *mxfep)
125629e83d4bSgd78059 {
125729e83d4bSgd78059 unsigned phyaddr;
125829e83d4bSgd78059 unsigned bmcr;
125929e83d4bSgd78059 unsigned bmsr;
126029e83d4bSgd78059 unsigned anar;
126129e83d4bSgd78059 unsigned phyidr1;
126229e83d4bSgd78059 unsigned phyidr2;
126329e83d4bSgd78059 int retries;
126429e83d4bSgd78059 int cnt;
126529e83d4bSgd78059
126629e83d4bSgd78059 mxfep->mxfe_phyaddr = -1;
126729e83d4bSgd78059
126829e83d4bSgd78059 /* search for first PHY we can find */
126929e83d4bSgd78059 for (phyaddr = 0; phyaddr < 32; phyaddr++) {
127029e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
127129e83d4bSgd78059 if ((bmsr != 0) && (bmsr != 0xffff)) {
127229e83d4bSgd78059 mxfep->mxfe_phyaddr = phyaddr;
127329e83d4bSgd78059 break;
127429e83d4bSgd78059 }
127529e83d4bSgd78059 }
127629e83d4bSgd78059
127729e83d4bSgd78059 phyidr1 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDH);
127829e83d4bSgd78059 phyidr2 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDL);
127929e83d4bSgd78059 mxfep->mxfe_phyid = (phyidr1 << 16) | (phyidr2);
128029e83d4bSgd78059
128129e83d4bSgd78059 /*
128229e83d4bSgd78059 * Generally, all Macronix based devices use an internal
128329e83d4bSgd78059 * 100BASE-TX internal transceiver. If we ever run into a
128429e83d4bSgd78059 * variation on this, then the following logic will need to be
128529e83d4bSgd78059 * enhanced.
128629e83d4bSgd78059 *
128729e83d4bSgd78059 * One could question the value of the XCVR_INUSE field in the
128829e83d4bSgd78059 * MII statistics.
128929e83d4bSgd78059 */
129029e83d4bSgd78059 if (bmsr & MII_STATUS_100_BASE_T4) {
129129e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100T4;
129229e83d4bSgd78059 } else {
129329e83d4bSgd78059 mxfep->mxfe_phyinuse = XCVR_100X;
129429e83d4bSgd78059 }
129529e83d4bSgd78059
129696fb08b9Sgd78059 /* assume we support everything to start */
129796fb08b9Sgd78059 mxfep->mxfe_cap_aneg = mxfep->mxfe_cap_100T4 =
129896fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
129996fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
130096fb08b9Sgd78059
130129e83d4bSgd78059 DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2);
130229e83d4bSgd78059 DBG(DPHY, "bmsr = %x", mxfe_miiread(mxfep,
130329e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_STATUS));
130429e83d4bSgd78059 DBG(DPHY, "anar = %x", mxfe_miiread(mxfep,
130529e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_ADVERT));
130629e83d4bSgd78059 DBG(DPHY, "anlpar = %x", mxfe_miiread(mxfep,
130729e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_LPABLE));
130829e83d4bSgd78059 DBG(DPHY, "aner = %x", mxfe_miiread(mxfep,
130929e83d4bSgd78059 mxfep->mxfe_phyaddr, MII_AN_EXPANSION));
131029e83d4bSgd78059
131129e83d4bSgd78059 DBG(DPHY, "resetting phy");
131229e83d4bSgd78059
131329e83d4bSgd78059 /* we reset the phy block */
131429e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
131529e83d4bSgd78059 /*
131629e83d4bSgd78059 * wait for it to complete -- 500usec is still to short to
131729e83d4bSgd78059 * bother getting the system clock involved.
131829e83d4bSgd78059 */
131929e83d4bSgd78059 drv_usecwait(500);
132029e83d4bSgd78059 for (retries = 0; retries < 10; retries++) {
132129e83d4bSgd78059 if (mxfe_miiread(mxfep, phyaddr, MII_CONTROL) &
132229e83d4bSgd78059 MII_CONTROL_RESET) {
132329e83d4bSgd78059 drv_usecwait(500);
132429e83d4bSgd78059 continue;
132529e83d4bSgd78059 }
132629e83d4bSgd78059 break;
132729e83d4bSgd78059 }
132829e83d4bSgd78059 if (retries == 100) {
132929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "timeout waiting on phy to reset");
133029e83d4bSgd78059 return;
133129e83d4bSgd78059 }
133229e83d4bSgd78059
133329e83d4bSgd78059 DBG(DPHY, "phy reset complete");
133429e83d4bSgd78059
133529e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
133629e83d4bSgd78059 bmcr = mxfe_miiread(mxfep, phyaddr, MII_CONTROL);
133729e83d4bSgd78059 anar = mxfe_miiread(mxfep, phyaddr, MII_AN_ADVERT);
133829e83d4bSgd78059
133929e83d4bSgd78059 anar &= ~(MII_ABILITY_100BASE_T4 |
134029e83d4bSgd78059 MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
134129e83d4bSgd78059 MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
134229e83d4bSgd78059
134329e83d4bSgd78059 /* disable modes not supported in hardware */
134429e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASE_T4)) {
134529e83d4bSgd78059 mxfep->mxfe_adv_100T4 = 0;
134696fb08b9Sgd78059 mxfep->mxfe_cap_100T4 = 0;
134729e83d4bSgd78059 }
134829e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASEX_FD)) {
134929e83d4bSgd78059 mxfep->mxfe_adv_100fdx = 0;
135096fb08b9Sgd78059 mxfep->mxfe_cap_100fdx = 0;
135129e83d4bSgd78059 }
135229e83d4bSgd78059 if (!(bmsr & MII_STATUS_100_BASEX)) {
135329e83d4bSgd78059 mxfep->mxfe_adv_100hdx = 0;
135496fb08b9Sgd78059 mxfep->mxfe_cap_100hdx = 0;
135529e83d4bSgd78059 }
135629e83d4bSgd78059 if (!(bmsr & MII_STATUS_10_FD)) {
135729e83d4bSgd78059 mxfep->mxfe_adv_10fdx = 0;
135896fb08b9Sgd78059 mxfep->mxfe_cap_10fdx = 0;
135929e83d4bSgd78059 }
136029e83d4bSgd78059 if (!(bmsr & MII_STATUS_10)) {
136129e83d4bSgd78059 mxfep->mxfe_adv_10hdx = 0;
136296fb08b9Sgd78059 mxfep->mxfe_cap_10hdx = 0;
136329e83d4bSgd78059 }
136429e83d4bSgd78059 if (!(bmsr & MII_STATUS_CANAUTONEG)) {
136529e83d4bSgd78059 mxfep->mxfe_adv_aneg = 0;
136696fb08b9Sgd78059 mxfep->mxfe_cap_aneg = 0;
136729e83d4bSgd78059 }
136829e83d4bSgd78059
136929e83d4bSgd78059 cnt = 0;
137029e83d4bSgd78059 if (mxfep->mxfe_adv_100T4) {
137129e83d4bSgd78059 anar |= MII_ABILITY_100BASE_T4;
137229e83d4bSgd78059 cnt++;
137329e83d4bSgd78059 }
137429e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) {
137529e83d4bSgd78059 anar |= MII_ABILITY_100BASE_TX_FD;
137629e83d4bSgd78059 cnt++;
137729e83d4bSgd78059 }
137829e83d4bSgd78059 if (mxfep->mxfe_adv_100hdx) {
137929e83d4bSgd78059 anar |= MII_ABILITY_100BASE_TX;
138029e83d4bSgd78059 cnt++;
138129e83d4bSgd78059 }
138229e83d4bSgd78059 if (mxfep->mxfe_adv_10fdx) {
138329e83d4bSgd78059 anar |= MII_ABILITY_10BASE_T_FD;
138429e83d4bSgd78059 cnt++;
138529e83d4bSgd78059 }
138629e83d4bSgd78059 if (mxfep->mxfe_adv_10hdx) {
138729e83d4bSgd78059 anar |= MII_ABILITY_10BASE_T;
138829e83d4bSgd78059 cnt++;
138929e83d4bSgd78059 }
139029e83d4bSgd78059
139129e83d4bSgd78059 /*
139229e83d4bSgd78059 * Make certain at least one valid link mode is selected.
139329e83d4bSgd78059 */
139429e83d4bSgd78059 if (!cnt) {
139529e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
139629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
139729e83d4bSgd78059 mxfe_stopphy(mxfep);
139829e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
139929e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
140029e83d4bSgd78059 mxfe_reportlink(mxfep);
140129e83d4bSgd78059 return;
140229e83d4bSgd78059 }
140329e83d4bSgd78059
140429e83d4bSgd78059 if ((mxfep->mxfe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) {
140529e83d4bSgd78059 DBG(DPHY, "using autoneg mode");
140629e83d4bSgd78059 bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
140729e83d4bSgd78059 } else {
140829e83d4bSgd78059 DBG(DPHY, "using forced mode");
140929e83d4bSgd78059 if (mxfep->mxfe_adv_100fdx) {
141029e83d4bSgd78059 bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
141129e83d4bSgd78059 } else if (mxfep->mxfe_adv_100hdx) {
141229e83d4bSgd78059 bmcr = MII_CONTROL_100MB;
141329e83d4bSgd78059 } else if (mxfep->mxfe_adv_10fdx) {
141429e83d4bSgd78059 bmcr = MII_CONTROL_FDUPLEX;
141529e83d4bSgd78059 } else {
141629e83d4bSgd78059 /* 10HDX */
141729e83d4bSgd78059 bmcr = 0;
141829e83d4bSgd78059 }
141929e83d4bSgd78059 }
142029e83d4bSgd78059
142129e83d4bSgd78059 DBG(DPHY, "programming anar to 0x%x", anar);
142229e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_AN_ADVERT, anar);
142329e83d4bSgd78059 DBG(DPHY, "programming bmcr to 0x%x", bmcr);
142429e83d4bSgd78059 mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, bmcr);
142529e83d4bSgd78059
142629e83d4bSgd78059 /*
142729e83d4bSgd78059 * schedule a query of the link status
142829e83d4bSgd78059 */
142929e83d4bSgd78059 PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
143029e83d4bSgd78059 (MXFE_LINKTIMER * 1000 / TIMER_USEC));
143129e83d4bSgd78059 }
143229e83d4bSgd78059
143329e83d4bSgd78059 void
mxfe_reportlink(mxfe_t * mxfep)143429e83d4bSgd78059 mxfe_reportlink(mxfe_t *mxfep)
143529e83d4bSgd78059 {
143629e83d4bSgd78059 int changed = 0;
143729e83d4bSgd78059
143829e83d4bSgd78059 if (mxfep->mxfe_ifspeed != mxfep->mxfe_lastifspeed) {
143929e83d4bSgd78059 mxfep->mxfe_lastifspeed = mxfep->mxfe_ifspeed;
144029e83d4bSgd78059 changed++;
144129e83d4bSgd78059 }
144229e83d4bSgd78059 if (mxfep->mxfe_duplex != mxfep->mxfe_lastduplex) {
144329e83d4bSgd78059 mxfep->mxfe_lastduplex = mxfep->mxfe_duplex;
144429e83d4bSgd78059 changed++;
144529e83d4bSgd78059 }
144629e83d4bSgd78059 if (mxfep->mxfe_linkup != mxfep->mxfe_lastlinkup) {
144729e83d4bSgd78059 mxfep->mxfe_lastlinkup = mxfep->mxfe_linkup;
144829e83d4bSgd78059 changed++;
144929e83d4bSgd78059 }
145029e83d4bSgd78059 if (changed)
145129e83d4bSgd78059 mac_link_update(mxfep->mxfe_mh, mxfep->mxfe_linkup);
145229e83d4bSgd78059 }
145329e83d4bSgd78059
145429e83d4bSgd78059 void
mxfe_checklink(mxfe_t * mxfep)145529e83d4bSgd78059 mxfe_checklink(mxfe_t *mxfep)
145629e83d4bSgd78059 {
145729e83d4bSgd78059 if ((mxfep->mxfe_flags & MXFE_RUNNING) == 0)
145829e83d4bSgd78059 return;
145929e83d4bSgd78059
146029e83d4bSgd78059 if ((mxfep->mxfe_txstall_time != 0) &&
146129e83d4bSgd78059 (gethrtime() > mxfep->mxfe_txstall_time) &&
146229e83d4bSgd78059 (mxfep->mxfe_txavail != MXFE_TXRING)) {
146329e83d4bSgd78059 mxfep->mxfe_txstall_time = 0;
146429e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "TX stall detected!");
146529e83d4bSgd78059 mxfe_resetall(mxfep);
146629e83d4bSgd78059 return;
146729e83d4bSgd78059 }
146829e83d4bSgd78059
146929e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) {
147029e83d4bSgd78059 case MXFE_98713A:
147129e83d4bSgd78059 mxfe_checklinkmii(mxfep);
147229e83d4bSgd78059 break;
147329e83d4bSgd78059 default:
147429e83d4bSgd78059 mxfe_checklinknway(mxfep);
147529e83d4bSgd78059 }
147629e83d4bSgd78059 }
147729e83d4bSgd78059
147829e83d4bSgd78059 void
mxfe_checklinkmii(mxfe_t * mxfep)147929e83d4bSgd78059 mxfe_checklinkmii(mxfe_t *mxfep)
148029e83d4bSgd78059 {
148129e83d4bSgd78059 /* read MII state registers */
148229e83d4bSgd78059 uint16_t bmsr;
148329e83d4bSgd78059 uint16_t bmcr;
148429e83d4bSgd78059 uint16_t anar;
148529e83d4bSgd78059 uint16_t anlpar;
148629e83d4bSgd78059 uint16_t aner;
148729e83d4bSgd78059
148829e83d4bSgd78059 /* read this twice, to clear latched link state */
148929e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
149029e83d4bSgd78059 bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
149129e83d4bSgd78059 bmcr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL);
149229e83d4bSgd78059 anar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_ADVERT);
149329e83d4bSgd78059 anlpar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_LPABLE);
149429e83d4bSgd78059 aner = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_EXPANSION);
149529e83d4bSgd78059
149629e83d4bSgd78059 mxfep->mxfe_bmsr = bmsr;
149729e83d4bSgd78059 mxfep->mxfe_anlpar = anlpar;
149829e83d4bSgd78059 mxfep->mxfe_aner = aner;
149929e83d4bSgd78059
150029e83d4bSgd78059 if (bmsr & MII_STATUS_REMFAULT) {
150129e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Remote fault detected.");
150229e83d4bSgd78059 }
150329e83d4bSgd78059 if (bmsr & MII_STATUS_JABBERING) {
150429e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Jabber condition detected.");
150529e83d4bSgd78059 }
150629e83d4bSgd78059 if ((bmsr & MII_STATUS_LINKUP) == 0) {
150729e83d4bSgd78059 /* no link */
150829e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
150929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
151029e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_DOWN;
151129e83d4bSgd78059 mxfe_reportlink(mxfep);
151229e83d4bSgd78059 return;
151329e83d4bSgd78059 }
151429e83d4bSgd78059
151529e83d4bSgd78059 DBG(DCHATTY, "link up!");
151629e83d4bSgd78059 mxfep->mxfe_linkup = LINK_STATE_UP;
151729e83d4bSgd78059
151829e83d4bSgd78059 if (!(bmcr & MII_CONTROL_ANE)) {
151929e83d4bSgd78059 /* forced mode */
152029e83d4bSgd78059 if (bmcr & MII_CONTROL_100MB) {
152129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
152229e83d4bSgd78059 } else {
152329e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
152429e83d4bSgd78059 }
152529e83d4bSgd78059 if (bmcr & MII_CONTROL_FDUPLEX) {
152629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
152729e83d4bSgd78059 } else {
152829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
152929e83d4bSgd78059 }
153029e83d4bSgd78059 } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
153129e83d4bSgd78059 (!(bmsr & MII_STATUS_ANDONE))) {
153229e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
153329e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
153429e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
153529e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
153629e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
153729e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
153829e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
153929e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
154029e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
154129e83d4bSgd78059 mxfep->mxfe_ifspeed = 100000000;
154229e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
154329e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
154429e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
154529e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
154629e83d4bSgd78059 } else if (anar & anlpar & MII_ABILITY_10BASE_T) {
154729e83d4bSgd78059 mxfep->mxfe_ifspeed = 10000000;
154829e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
154929e83d4bSgd78059 } else {
155029e83d4bSgd78059 mxfep->mxfe_ifspeed = 0;
155129e83d4bSgd78059 mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
155229e83d4bSgd78059 }
155329e83d4bSgd78059
155429e83d4bSgd78059 mxfe_reportlink(mxfep);
155529e83d4bSgd78059 }
155629e83d4bSgd78059
155729e83d4bSgd78059 void
mxfe_miitristate(mxfe_t * mxfep)155829e83d4bSgd78059 mxfe_miitristate(mxfe_t *mxfep)
155929e83d4bSgd78059 {
156029e83d4bSgd78059 unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL;
156129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val);
156229e83d4bSgd78059 drv_usecwait(1);
156329e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
156429e83d4bSgd78059 drv_usecwait(1);
156529e83d4bSgd78059 }
156629e83d4bSgd78059
156729e83d4bSgd78059 void
mxfe_miiwritebit(mxfe_t * mxfep,uint8_t bit)156896fb08b9Sgd78059 mxfe_miiwritebit(mxfe_t *mxfep, uint8_t bit)
156929e83d4bSgd78059 {
157029e83d4bSgd78059 unsigned val = bit ? SPR_MII_DOUT : 0;
157129e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val);
157229e83d4bSgd78059 drv_usecwait(1);
157329e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
157429e83d4bSgd78059 drv_usecwait(1);
157529e83d4bSgd78059 }
157629e83d4bSgd78059
157796fb08b9Sgd78059 uint8_t
mxfe_miireadbit(mxfe_t * mxfep)157829e83d4bSgd78059 mxfe_miireadbit(mxfe_t *mxfep)
157929e83d4bSgd78059 {
158029e83d4bSgd78059 unsigned val = SPR_MII_CTRL | SPR_SROM_READ;
158196fb08b9Sgd78059 uint8_t bit;
158229e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val);
158329e83d4bSgd78059 drv_usecwait(1);
158429e83d4bSgd78059 bit = (GETCSR(mxfep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0;
158529e83d4bSgd78059 PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
158629e83d4bSgd78059 drv_usecwait(1);
158729e83d4bSgd78059 return (bit);
158829e83d4bSgd78059 }
158929e83d4bSgd78059
159096fb08b9Sgd78059 uint16_t
mxfe_miiread(mxfe_t * mxfep,int phy,int reg)159129e83d4bSgd78059 mxfe_miiread(mxfe_t *mxfep, int phy, int reg)
159229e83d4bSgd78059 {
159329e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) {
159429e83d4bSgd78059 case MXFE_98713A:
159529e83d4bSgd78059 return (mxfe_miiread98713(mxfep, phy, reg));
159629e83d4bSgd78059 default:
159729e83d4bSgd78059 return (0xffff);
159829e83d4bSgd78059 }
159929e83d4bSgd78059 }
160029e83d4bSgd78059
160196fb08b9Sgd78059 uint16_t
mxfe_miireadgeneral(mxfe_t * mxfep,int phy,int reg)160229e83d4bSgd78059 mxfe_miireadgeneral(mxfe_t *mxfep, int phy, int reg)
160329e83d4bSgd78059 {
160496fb08b9Sgd78059 uint16_t value = 0;
160529e83d4bSgd78059 int i;
160629e83d4bSgd78059
160729e83d4bSgd78059 /* send the 32 bit preamble */
160829e83d4bSgd78059 for (i = 0; i < 32; i++) {
160929e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
161029e83d4bSgd78059 }
161129e83d4bSgd78059
161229e83d4bSgd78059 /* send the start code - 01b */
161329e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
161429e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
161529e83d4bSgd78059
161629e83d4bSgd78059 /* send the opcode for read, - 10b */
161729e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
161829e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
161929e83d4bSgd78059
162029e83d4bSgd78059 /* next we send the 5 bit phy address */
162129e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) {
162229e83d4bSgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
162329e83d4bSgd78059 }
162429e83d4bSgd78059
162529e83d4bSgd78059 /* the 5 bit register address goes next */
162629e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) {
162729e83d4bSgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
162829e83d4bSgd78059 }
162929e83d4bSgd78059
163029e83d4bSgd78059 /* turnaround - tristate followed by logic 0 */
163129e83d4bSgd78059 mxfe_miitristate(mxfep);
163229e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
163329e83d4bSgd78059
163429e83d4bSgd78059 /* read the 16 bit register value */
163529e83d4bSgd78059 for (i = 0x8000; i > 0; i >>= 1) {
163629e83d4bSgd78059 value <<= 1;
163729e83d4bSgd78059 value |= mxfe_miireadbit(mxfep);
163829e83d4bSgd78059 }
163929e83d4bSgd78059 mxfe_miitristate(mxfep);
164029e83d4bSgd78059 return (value);
164129e83d4bSgd78059 }
164229e83d4bSgd78059
164396fb08b9Sgd78059 uint16_t
mxfe_miiread98713(mxfe_t * mxfep,int phy,int reg)164429e83d4bSgd78059 mxfe_miiread98713(mxfe_t *mxfep, int phy, int reg)
164529e83d4bSgd78059 {
164629e83d4bSgd78059 unsigned nar;
164796fb08b9Sgd78059 uint16_t retval;
164829e83d4bSgd78059 /*
164929e83d4bSgd78059 * like an ordinary MII, but we have to turn off portsel while
165029e83d4bSgd78059 * we read it.
165129e83d4bSgd78059 */
165229e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
165329e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
165429e83d4bSgd78059 retval = mxfe_miireadgeneral(mxfep, phy, reg);
165529e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
165629e83d4bSgd78059 return (retval);
165729e83d4bSgd78059 }
165829e83d4bSgd78059
165929e83d4bSgd78059 void
mxfe_miiwrite(mxfe_t * mxfep,int phy,int reg,uint16_t val)166029e83d4bSgd78059 mxfe_miiwrite(mxfe_t *mxfep, int phy, int reg, uint16_t val)
166129e83d4bSgd78059 {
166229e83d4bSgd78059 switch (MXFE_MODEL(mxfep)) {
166329e83d4bSgd78059 case MXFE_98713A:
166429e83d4bSgd78059 mxfe_miiwrite98713(mxfep, phy, reg, val);
166529e83d4bSgd78059 break;
166629e83d4bSgd78059 default:
166729e83d4bSgd78059 break;
166829e83d4bSgd78059 }
166929e83d4bSgd78059 }
167029e83d4bSgd78059
167129e83d4bSgd78059 void
mxfe_miiwritegeneral(mxfe_t * mxfep,int phy,int reg,uint16_t val)167229e83d4bSgd78059 mxfe_miiwritegeneral(mxfe_t *mxfep, int phy, int reg, uint16_t val)
167329e83d4bSgd78059 {
167429e83d4bSgd78059 int i;
167529e83d4bSgd78059
167629e83d4bSgd78059 /* send the 32 bit preamble */
167729e83d4bSgd78059 for (i = 0; i < 32; i++) {
167829e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
167929e83d4bSgd78059 }
168029e83d4bSgd78059
168129e83d4bSgd78059 /* send the start code - 01b */
168229e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
168329e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
168429e83d4bSgd78059
168529e83d4bSgd78059 /* send the opcode for write, - 01b */
168629e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
168729e83d4bSgd78059 mxfe_miiwritebit(mxfep, 1);
168829e83d4bSgd78059
168929e83d4bSgd78059 /* next we send the 5 bit phy address */
169029e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) {
169129e83d4bSgd78059 mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
169229e83d4bSgd78059 }
169329e83d4bSgd78059
169429e83d4bSgd78059 /* the 5 bit register address goes next */
169529e83d4bSgd78059 for (i = 0x10; i > 0; i >>= 1) {
169629e83d4bSgd78059 mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
169729e83d4bSgd78059 }
169829e83d4bSgd78059
169929e83d4bSgd78059 /* turnaround - tristate followed by logic 0 */
170029e83d4bSgd78059 mxfe_miitristate(mxfep);
170129e83d4bSgd78059 mxfe_miiwritebit(mxfep, 0);
170229e83d4bSgd78059
170329e83d4bSgd78059 /* now write out our data (16 bits) */
170429e83d4bSgd78059 for (i = 0x8000; i > 0; i >>= 1) {
170529e83d4bSgd78059 mxfe_miiwritebit(mxfep, (val & i) ? 1 : 0);
170629e83d4bSgd78059 }
170729e83d4bSgd78059
170829e83d4bSgd78059 /* idle mode */
170929e83d4bSgd78059 mxfe_miitristate(mxfep);
171029e83d4bSgd78059 }
171129e83d4bSgd78059
171229e83d4bSgd78059 void
mxfe_miiwrite98713(mxfe_t * mxfep,int phy,int reg,uint16_t val)171329e83d4bSgd78059 mxfe_miiwrite98713(mxfe_t *mxfep, int phy, int reg, uint16_t val)
171429e83d4bSgd78059 {
171529e83d4bSgd78059 unsigned nar;
171629e83d4bSgd78059 /*
171729e83d4bSgd78059 * like an ordinary MII, but we have to turn off portsel while
171829e83d4bSgd78059 * we read it.
171929e83d4bSgd78059 */
172029e83d4bSgd78059 nar = GETCSR(mxfep, CSR_NAR);
172129e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
172229e83d4bSgd78059 mxfe_miiwritegeneral(mxfep, phy, reg, val);
172329e83d4bSgd78059 PUTCSR(mxfep, CSR_NAR, nar);
172429e83d4bSgd78059 }
172529e83d4bSgd78059
172629e83d4bSgd78059 int
mxfe_m_start(void * arg)172729e83d4bSgd78059 mxfe_m_start(void *arg)
172829e83d4bSgd78059 {
172929e83d4bSgd78059 mxfe_t *mxfep = arg;
173029e83d4bSgd78059
173129e83d4bSgd78059 /* grab exclusive access to the card */
173229e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
173329e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
173429e83d4bSgd78059
173529e83d4bSgd78059 mxfe_startall(mxfep);
173629e83d4bSgd78059 mxfep->mxfe_flags |= MXFE_RUNNING;
173729e83d4bSgd78059
173829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
173929e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
174029e83d4bSgd78059 return (0);
174129e83d4bSgd78059 }
174229e83d4bSgd78059
174329e83d4bSgd78059 void
mxfe_m_stop(void * arg)174429e83d4bSgd78059 mxfe_m_stop(void *arg)
174529e83d4bSgd78059 {
174629e83d4bSgd78059 mxfe_t *mxfep = arg;
174729e83d4bSgd78059
174829e83d4bSgd78059 /* exclusive access to the hardware! */
174929e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
175029e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
175129e83d4bSgd78059
175229e83d4bSgd78059 mxfe_stopall(mxfep);
175329e83d4bSgd78059 mxfep->mxfe_flags &= ~MXFE_RUNNING;
175429e83d4bSgd78059
175529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
175629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
175729e83d4bSgd78059 }
175829e83d4bSgd78059
175929e83d4bSgd78059 void
mxfe_startmac(mxfe_t * mxfep)176029e83d4bSgd78059 mxfe_startmac(mxfe_t *mxfep)
176129e83d4bSgd78059 {
176229e83d4bSgd78059 /* verify exclusive access to the card */
176329e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
176429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
176529e83d4bSgd78059
176629e83d4bSgd78059 /* start the card */
176729e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
176829e83d4bSgd78059
176929e83d4bSgd78059 if (mxfep->mxfe_txavail != MXFE_TXRING)
177029e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0);
177129e83d4bSgd78059
177229e83d4bSgd78059 /* tell the mac that we are ready to go! */
177329e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_RUNNING)
177429e83d4bSgd78059 mac_tx_update(mxfep->mxfe_mh);
177529e83d4bSgd78059 }
177629e83d4bSgd78059
177729e83d4bSgd78059 void
mxfe_stopmac(mxfe_t * mxfep)177829e83d4bSgd78059 mxfe_stopmac(mxfe_t *mxfep)
177929e83d4bSgd78059 {
178029e83d4bSgd78059 int i;
178129e83d4bSgd78059
178229e83d4bSgd78059 /* exclusive access to the hardware! */
178329e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
178429e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
178529e83d4bSgd78059
178629e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
178729e83d4bSgd78059
178829e83d4bSgd78059 /*
178929e83d4bSgd78059 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
179029e83d4bSgd78059 * We just add up to the nearest msec (2), which should be
179129e83d4bSgd78059 * plenty to complete.
179229e83d4bSgd78059 *
179329e83d4bSgd78059 * Note that some chips never seem to indicate the transition to
179429e83d4bSgd78059 * the stopped state properly. Experience shows that we can safely
179529e83d4bSgd78059 * proceed anyway, after waiting the requisite timeout.
179629e83d4bSgd78059 */
179729e83d4bSgd78059 for (i = 2000; i != 0; i -= 10) {
179829e83d4bSgd78059 if ((GETCSR(mxfep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
179929e83d4bSgd78059 break;
180029e83d4bSgd78059 drv_usecwait(10);
180129e83d4bSgd78059 }
180229e83d4bSgd78059
180329e83d4bSgd78059 /* prevent an interrupt */
180429e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, INT_RXSTOPPED | INT_TXSTOPPED);
180529e83d4bSgd78059 }
180629e83d4bSgd78059
180729e83d4bSgd78059 void
mxfe_resetrings(mxfe_t * mxfep)180829e83d4bSgd78059 mxfe_resetrings(mxfe_t *mxfep)
180929e83d4bSgd78059 {
181029e83d4bSgd78059 int i;
181129e83d4bSgd78059
181229e83d4bSgd78059 /* now we need to reset the pointers... */
181329e83d4bSgd78059 PUTCSR(mxfep, CSR_RDB, 0);
181429e83d4bSgd78059 PUTCSR(mxfep, CSR_TDB, 0);
181529e83d4bSgd78059
181629e83d4bSgd78059 /* reset the descriptor ring pointers */
181729e83d4bSgd78059 mxfep->mxfe_rxhead = 0;
181829e83d4bSgd78059 mxfep->mxfe_txreclaim = 0;
181929e83d4bSgd78059 mxfep->mxfe_txsend = 0;
182029e83d4bSgd78059 mxfep->mxfe_txavail = MXFE_TXRING;
182129e83d4bSgd78059
182229e83d4bSgd78059 /* set up transmit descriptor ring */
182329e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) {
182429e83d4bSgd78059 mxfe_desc_t *tmdp = &mxfep->mxfe_txdescp[i];
182529e83d4bSgd78059 unsigned control = 0;
182629e83d4bSgd78059 if (i == (MXFE_TXRING - 1)) {
182729e83d4bSgd78059 control |= TXCTL_ENDRING;
182829e83d4bSgd78059 }
182929e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_status, 0);
183029e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_control, control);
183129e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, 0);
183229e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
183329e83d4bSgd78059 SYNCTXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
183429e83d4bSgd78059 }
183529e83d4bSgd78059 PUTCSR(mxfep, CSR_TDB, mxfep->mxfe_txdesc_paddr);
183629e83d4bSgd78059
183729e83d4bSgd78059 /* make the receive buffers available */
183829e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) {
183929e83d4bSgd78059 mxfe_rxbuf_t *rxb = mxfep->mxfe_rxbufs[i];
184029e83d4bSgd78059 mxfe_desc_t *rmdp = &mxfep->mxfe_rxdescp[i];
184129e83d4bSgd78059 unsigned control;
184229e83d4bSgd78059
184329e83d4bSgd78059 control = MXFE_BUFSZ & RXCTL_BUFLEN1;
184429e83d4bSgd78059 if (i == (MXFE_RXRING - 1)) {
184529e83d4bSgd78059 control |= RXCTL_ENDRING;
184629e83d4bSgd78059 }
184729e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer1, rxb->rxb_paddr);
184829e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_buffer2, 0);
184929e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_control, control);
185029e83d4bSgd78059 PUTRXDESC(mxfep, rmdp->desc_status, RXSTAT_OWN);
185129e83d4bSgd78059 SYNCRXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
185229e83d4bSgd78059 }
185329e83d4bSgd78059 PUTCSR(mxfep, CSR_RDB, mxfep->mxfe_rxdesc_paddr);
185429e83d4bSgd78059 }
185529e83d4bSgd78059
185629e83d4bSgd78059 void
mxfe_stopall(mxfe_t * mxfep)185729e83d4bSgd78059 mxfe_stopall(mxfe_t *mxfep)
185829e83d4bSgd78059 {
185929e83d4bSgd78059 mxfe_disableinterrupts(mxfep);
186029e83d4bSgd78059
186129e83d4bSgd78059 mxfe_stopmac(mxfep);
186229e83d4bSgd78059
186329e83d4bSgd78059 /* stop the phy */
186429e83d4bSgd78059 mxfe_stopphy(mxfep);
186529e83d4bSgd78059 }
186629e83d4bSgd78059
186729e83d4bSgd78059 void
mxfe_startall(mxfe_t * mxfep)186829e83d4bSgd78059 mxfe_startall(mxfe_t *mxfep)
186929e83d4bSgd78059 {
187029e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
187129e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
187229e83d4bSgd78059
187329e83d4bSgd78059 /* make sure interrupts are disabled to begin */
187429e83d4bSgd78059 mxfe_disableinterrupts(mxfep);
187529e83d4bSgd78059
187629e83d4bSgd78059 /* initialize the chip */
187729e83d4bSgd78059 (void) mxfe_initialize(mxfep);
187829e83d4bSgd78059
187929e83d4bSgd78059 /* now we can enable interrupts */
188029e83d4bSgd78059 mxfe_enableinterrupts(mxfep);
188129e83d4bSgd78059
188229e83d4bSgd78059 /* start up the phy */
188329e83d4bSgd78059 mxfe_startphy(mxfep);
188429e83d4bSgd78059
188529e83d4bSgd78059 /* start up the mac */
188629e83d4bSgd78059 mxfe_startmac(mxfep);
188729e83d4bSgd78059 }
188829e83d4bSgd78059
188929e83d4bSgd78059 void
mxfe_resetall(mxfe_t * mxfep)189029e83d4bSgd78059 mxfe_resetall(mxfe_t *mxfep)
189129e83d4bSgd78059 {
189229e83d4bSgd78059 mxfep->mxfe_resetting = B_TRUE;
189329e83d4bSgd78059 mxfe_stopall(mxfep);
189429e83d4bSgd78059 mxfep->mxfe_resetting = B_FALSE;
189529e83d4bSgd78059 mxfe_startall(mxfep);
189629e83d4bSgd78059 }
189729e83d4bSgd78059
189829e83d4bSgd78059 mxfe_txbuf_t *
mxfe_alloctxbuf(mxfe_t * mxfep)189929e83d4bSgd78059 mxfe_alloctxbuf(mxfe_t *mxfep)
190029e83d4bSgd78059 {
190129e83d4bSgd78059 ddi_dma_cookie_t dmac;
190229e83d4bSgd78059 unsigned ncookies;
190329e83d4bSgd78059 mxfe_txbuf_t *txb;
190429e83d4bSgd78059 size_t len;
190529e83d4bSgd78059
190629e83d4bSgd78059 txb = kmem_zalloc(sizeof (*txb), KM_SLEEP);
190729e83d4bSgd78059
190829e83d4bSgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_txattr,
190929e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) {
191029e83d4bSgd78059 return (NULL);
191129e83d4bSgd78059 }
191229e83d4bSgd78059
191329e83d4bSgd78059 if (ddi_dma_mem_alloc(txb->txb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
191429e83d4bSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf,
191529e83d4bSgd78059 &len, &txb->txb_acch) != DDI_SUCCESS) {
191629e83d4bSgd78059 return (NULL);
191729e83d4bSgd78059 }
191829e83d4bSgd78059 if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
191929e83d4bSgd78059 len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
192029e83d4bSgd78059 &dmac, &ncookies) != DDI_DMA_MAPPED) {
192129e83d4bSgd78059 return (NULL);
192229e83d4bSgd78059 }
192329e83d4bSgd78059 txb->txb_paddr = dmac.dmac_address;
192429e83d4bSgd78059
192529e83d4bSgd78059 return (txb);
192629e83d4bSgd78059 }
192729e83d4bSgd78059
192829e83d4bSgd78059 void
mxfe_destroytxbuf(mxfe_txbuf_t * txb)192929e83d4bSgd78059 mxfe_destroytxbuf(mxfe_txbuf_t *txb)
193029e83d4bSgd78059 {
193129e83d4bSgd78059 if (txb != NULL) {
193229e83d4bSgd78059 if (txb->txb_paddr)
193329e83d4bSgd78059 (void) ddi_dma_unbind_handle(txb->txb_dmah);
193429e83d4bSgd78059 if (txb->txb_acch)
193529e83d4bSgd78059 ddi_dma_mem_free(&txb->txb_acch);
193629e83d4bSgd78059 if (txb->txb_dmah)
193729e83d4bSgd78059 ddi_dma_free_handle(&txb->txb_dmah);
193829e83d4bSgd78059 kmem_free(txb, sizeof (*txb));
193929e83d4bSgd78059 }
194029e83d4bSgd78059 }
194129e83d4bSgd78059
194229e83d4bSgd78059 mxfe_rxbuf_t *
mxfe_allocrxbuf(mxfe_t * mxfep)194329e83d4bSgd78059 mxfe_allocrxbuf(mxfe_t *mxfep)
194429e83d4bSgd78059 {
194529e83d4bSgd78059 mxfe_rxbuf_t *rxb;
194629e83d4bSgd78059 size_t len;
194729e83d4bSgd78059 unsigned ccnt;
194829e83d4bSgd78059 ddi_dma_cookie_t dmac;
194929e83d4bSgd78059
195029e83d4bSgd78059 rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP);
195129e83d4bSgd78059
195229e83d4bSgd78059 if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
195329e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) {
195429e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb));
195529e83d4bSgd78059 return (NULL);
195629e83d4bSgd78059 }
195729e83d4bSgd78059 if (ddi_dma_mem_alloc(rxb->rxb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
195829e83d4bSgd78059 DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
195929e83d4bSgd78059 &rxb->rxb_buf, &len, &rxb->rxb_acch) != DDI_SUCCESS) {
196029e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
196129e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb));
196229e83d4bSgd78059 return (NULL);
196329e83d4bSgd78059 }
196429e83d4bSgd78059 if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
196529e83d4bSgd78059 DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
196629e83d4bSgd78059 &ccnt) != DDI_DMA_MAPPED) {
196729e83d4bSgd78059 ddi_dma_mem_free(&rxb->rxb_acch);
196829e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
196929e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb));
197029e83d4bSgd78059 return (NULL);
197129e83d4bSgd78059 }
197229e83d4bSgd78059 rxb->rxb_paddr = dmac.dmac_address;
197329e83d4bSgd78059
197429e83d4bSgd78059 return (rxb);
197529e83d4bSgd78059 }
197629e83d4bSgd78059
197729e83d4bSgd78059 void
mxfe_destroyrxbuf(mxfe_rxbuf_t * rxb)197829e83d4bSgd78059 mxfe_destroyrxbuf(mxfe_rxbuf_t *rxb)
197929e83d4bSgd78059 {
198029e83d4bSgd78059 if (rxb != NULL) {
198129e83d4bSgd78059 (void) ddi_dma_unbind_handle(rxb->rxb_dmah);
198229e83d4bSgd78059 ddi_dma_mem_free(&rxb->rxb_acch);
198329e83d4bSgd78059 ddi_dma_free_handle(&rxb->rxb_dmah);
198429e83d4bSgd78059 kmem_free(rxb, sizeof (*rxb));
198529e83d4bSgd78059 }
198629e83d4bSgd78059 }
198729e83d4bSgd78059
198829e83d4bSgd78059 /*
198929e83d4bSgd78059 * Allocate receive resources.
199029e83d4bSgd78059 */
199129e83d4bSgd78059 int
mxfe_allocrxring(mxfe_t * mxfep)199229e83d4bSgd78059 mxfe_allocrxring(mxfe_t *mxfep)
199329e83d4bSgd78059 {
199429e83d4bSgd78059 int rval;
199529e83d4bSgd78059 int i;
199629e83d4bSgd78059 size_t size;
199729e83d4bSgd78059 size_t len;
199829e83d4bSgd78059 ddi_dma_cookie_t dmac;
199929e83d4bSgd78059 unsigned ncookies;
200029e83d4bSgd78059 caddr_t kaddr;
200129e83d4bSgd78059
200229e83d4bSgd78059 size = MXFE_RXRING * sizeof (mxfe_desc_t);
200329e83d4bSgd78059
200429e83d4bSgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
200529e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_rxdesc_dmah);
200629e83d4bSgd78059 if (rval != DDI_SUCCESS) {
200729e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
200829e83d4bSgd78059 "unable to allocate DMA handle for rx descriptors");
200929e83d4bSgd78059 return (DDI_FAILURE);
201029e83d4bSgd78059 }
201129e83d4bSgd78059
201229e83d4bSgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_rxdesc_dmah, size, &mxfe_devattr,
201329e83d4bSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
201429e83d4bSgd78059 &mxfep->mxfe_rxdesc_acch);
201529e83d4bSgd78059 if (rval != DDI_SUCCESS) {
201629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
201729e83d4bSgd78059 "unable to allocate DMA memory for rx descriptors");
201829e83d4bSgd78059 return (DDI_FAILURE);
201929e83d4bSgd78059 }
202029e83d4bSgd78059
202129e83d4bSgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_rxdesc_dmah, NULL, kaddr,
202229e83d4bSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
202329e83d4bSgd78059 &dmac, &ncookies);
202429e83d4bSgd78059 if (rval != DDI_DMA_MAPPED) {
202529e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
202629e83d4bSgd78059 "unable to bind DMA for rx descriptors");
202729e83d4bSgd78059 return (DDI_FAILURE);
202829e83d4bSgd78059 }
202929e83d4bSgd78059
203029e83d4bSgd78059 /* because of mxfe_dma_attr */
203129e83d4bSgd78059 ASSERT(ncookies == 1);
203229e83d4bSgd78059
203329e83d4bSgd78059 /* we take the 32-bit physical address out of the cookie */
203429e83d4bSgd78059 mxfep->mxfe_rxdesc_paddr = dmac.dmac_address;
203529e83d4bSgd78059 mxfep->mxfe_rxdescp = (void *)kaddr;
203629e83d4bSgd78059
203729e83d4bSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */
203829e83d4bSgd78059 mxfep->mxfe_rxbufs = kmem_zalloc(MXFE_RXRING * sizeof (mxfe_rxbuf_t *),
203929e83d4bSgd78059 KM_SLEEP);
204029e83d4bSgd78059
204129e83d4bSgd78059 /* now allocate rx buffers */
204229e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) {
204329e83d4bSgd78059 mxfe_rxbuf_t *rxb = mxfe_allocrxbuf(mxfep);
204429e83d4bSgd78059 if (rxb == NULL)
204529e83d4bSgd78059 return (DDI_FAILURE);
204629e83d4bSgd78059 mxfep->mxfe_rxbufs[i] = rxb;
204729e83d4bSgd78059 }
204829e83d4bSgd78059
204929e83d4bSgd78059 return (DDI_SUCCESS);
205029e83d4bSgd78059 }
205129e83d4bSgd78059
205229e83d4bSgd78059 /*
205329e83d4bSgd78059 * Allocate transmit resources.
205429e83d4bSgd78059 */
205529e83d4bSgd78059 int
mxfe_alloctxring(mxfe_t * mxfep)205629e83d4bSgd78059 mxfe_alloctxring(mxfe_t *mxfep)
205729e83d4bSgd78059 {
205829e83d4bSgd78059 int rval;
205929e83d4bSgd78059 int i;
206029e83d4bSgd78059 size_t size;
206129e83d4bSgd78059 size_t len;
206229e83d4bSgd78059 ddi_dma_cookie_t dmac;
206329e83d4bSgd78059 unsigned ncookies;
206429e83d4bSgd78059 caddr_t kaddr;
206529e83d4bSgd78059
206629e83d4bSgd78059 size = MXFE_TXRING * sizeof (mxfe_desc_t);
206729e83d4bSgd78059
206829e83d4bSgd78059 rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
206929e83d4bSgd78059 DDI_DMA_SLEEP, NULL, &mxfep->mxfe_txdesc_dmah);
207029e83d4bSgd78059 if (rval != DDI_SUCCESS) {
207129e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
207229e83d4bSgd78059 "unable to allocate DMA handle for tx descriptors");
207329e83d4bSgd78059 return (DDI_FAILURE);
207429e83d4bSgd78059 }
207529e83d4bSgd78059
207629e83d4bSgd78059 rval = ddi_dma_mem_alloc(mxfep->mxfe_txdesc_dmah, size, &mxfe_devattr,
207729e83d4bSgd78059 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
207829e83d4bSgd78059 &mxfep->mxfe_txdesc_acch);
207929e83d4bSgd78059 if (rval != DDI_SUCCESS) {
208029e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
208129e83d4bSgd78059 "unable to allocate DMA memory for tx descriptors");
208229e83d4bSgd78059 return (DDI_FAILURE);
208329e83d4bSgd78059 }
208429e83d4bSgd78059
208529e83d4bSgd78059 rval = ddi_dma_addr_bind_handle(mxfep->mxfe_txdesc_dmah, NULL, kaddr,
208629e83d4bSgd78059 size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
208729e83d4bSgd78059 &dmac, &ncookies);
208829e83d4bSgd78059 if (rval != DDI_DMA_MAPPED) {
208929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip,
209029e83d4bSgd78059 "unable to bind DMA for tx descriptors");
209129e83d4bSgd78059 return (DDI_FAILURE);
209229e83d4bSgd78059 }
209329e83d4bSgd78059
209429e83d4bSgd78059 /* because of mxfe_dma_attr */
209529e83d4bSgd78059 ASSERT(ncookies == 1);
209629e83d4bSgd78059
209729e83d4bSgd78059 /* we take the 32-bit physical address out of the cookie */
209829e83d4bSgd78059 mxfep->mxfe_txdesc_paddr = dmac.dmac_address;
209929e83d4bSgd78059 mxfep->mxfe_txdescp = (void *)kaddr;
210029e83d4bSgd78059
210129e83d4bSgd78059 /* allocate buffer pointers (not the buffers themselves, yet) */
210229e83d4bSgd78059 mxfep->mxfe_txbufs = kmem_zalloc(MXFE_TXRING * sizeof (mxfe_txbuf_t *),
210329e83d4bSgd78059 KM_SLEEP);
210429e83d4bSgd78059
210529e83d4bSgd78059 /* now allocate tx buffers */
210629e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) {
210729e83d4bSgd78059 mxfe_txbuf_t *txb = mxfe_alloctxbuf(mxfep);
210829e83d4bSgd78059 if (txb == NULL)
210929e83d4bSgd78059 return (DDI_FAILURE);
211029e83d4bSgd78059 /* stick it in the stack */
211129e83d4bSgd78059 mxfep->mxfe_txbufs[i] = txb;
211229e83d4bSgd78059 }
211329e83d4bSgd78059
211429e83d4bSgd78059 return (DDI_SUCCESS);
211529e83d4bSgd78059 }
211629e83d4bSgd78059
211729e83d4bSgd78059 void
mxfe_freerxring(mxfe_t * mxfep)211829e83d4bSgd78059 mxfe_freerxring(mxfe_t *mxfep)
211929e83d4bSgd78059 {
212029e83d4bSgd78059 int i;
212129e83d4bSgd78059
212229e83d4bSgd78059 for (i = 0; i < MXFE_RXRING; i++) {
212329e83d4bSgd78059 mxfe_destroyrxbuf(mxfep->mxfe_rxbufs[i]);
212429e83d4bSgd78059 }
212529e83d4bSgd78059
212629e83d4bSgd78059 if (mxfep->mxfe_rxbufs) {
212729e83d4bSgd78059 kmem_free(mxfep->mxfe_rxbufs,
212829e83d4bSgd78059 MXFE_RXRING * sizeof (mxfe_rxbuf_t *));
212929e83d4bSgd78059 }
213029e83d4bSgd78059
213129e83d4bSgd78059 if (mxfep->mxfe_rxdesc_paddr)
213229e83d4bSgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_rxdesc_dmah);
213329e83d4bSgd78059 if (mxfep->mxfe_rxdesc_acch)
213429e83d4bSgd78059 ddi_dma_mem_free(&mxfep->mxfe_rxdesc_acch);
213529e83d4bSgd78059 if (mxfep->mxfe_rxdesc_dmah)
213629e83d4bSgd78059 ddi_dma_free_handle(&mxfep->mxfe_rxdesc_dmah);
213729e83d4bSgd78059 }
213829e83d4bSgd78059
213929e83d4bSgd78059 void
mxfe_freetxring(mxfe_t * mxfep)214029e83d4bSgd78059 mxfe_freetxring(mxfe_t *mxfep)
214129e83d4bSgd78059 {
214229e83d4bSgd78059 int i;
214329e83d4bSgd78059
214429e83d4bSgd78059 for (i = 0; i < MXFE_TXRING; i++) {
214529e83d4bSgd78059 mxfe_destroytxbuf(mxfep->mxfe_txbufs[i]);
214629e83d4bSgd78059 }
214729e83d4bSgd78059
214829e83d4bSgd78059 if (mxfep->mxfe_txbufs) {
214929e83d4bSgd78059 kmem_free(mxfep->mxfe_txbufs,
215029e83d4bSgd78059 MXFE_TXRING * sizeof (mxfe_txbuf_t *));
215129e83d4bSgd78059 }
215229e83d4bSgd78059 if (mxfep->mxfe_txdesc_paddr)
215329e83d4bSgd78059 (void) ddi_dma_unbind_handle(mxfep->mxfe_txdesc_dmah);
215429e83d4bSgd78059 if (mxfep->mxfe_txdesc_acch)
215529e83d4bSgd78059 ddi_dma_mem_free(&mxfep->mxfe_txdesc_acch);
215629e83d4bSgd78059 if (mxfep->mxfe_txdesc_dmah)
215729e83d4bSgd78059 ddi_dma_free_handle(&mxfep->mxfe_txdesc_dmah);
215829e83d4bSgd78059 }
215929e83d4bSgd78059
216029e83d4bSgd78059 /*
216129e83d4bSgd78059 * Interrupt service routine.
216229e83d4bSgd78059 */
216329e83d4bSgd78059 unsigned
mxfe_intr(caddr_t arg)216429e83d4bSgd78059 mxfe_intr(caddr_t arg)
216529e83d4bSgd78059 {
216629e83d4bSgd78059 mxfe_t *mxfep = (void *)arg;
216729e83d4bSgd78059 uint32_t status;
216829e83d4bSgd78059 mblk_t *mp = NULL;
216977860f66SGarrett D'Amore boolean_t error = B_FALSE;
217029e83d4bSgd78059
217129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
217229e83d4bSgd78059
217329e83d4bSgd78059 if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
217429e83d4bSgd78059 /* we cannot receive interrupts! */
217529e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
217629e83d4bSgd78059 return (DDI_INTR_UNCLAIMED);
217729e83d4bSgd78059 }
217829e83d4bSgd78059
217929e83d4bSgd78059 /* check interrupt status bits, did we interrupt? */
218029e83d4bSgd78059 status = GETCSR(mxfep, CSR_SR) & INT_ALL;
218129e83d4bSgd78059
218229e83d4bSgd78059 if (status == 0) {
218329e83d4bSgd78059 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
218429e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
218529e83d4bSgd78059 return (DDI_INTR_UNCLAIMED);
218629e83d4bSgd78059 }
218729e83d4bSgd78059 /* ack the interrupt */
218829e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, status);
218929e83d4bSgd78059 KIOIP->intrs[KSTAT_INTR_HARD]++;
219029e83d4bSgd78059
219129e83d4bSgd78059 if (!(mxfep->mxfe_flags & MXFE_RUNNING)) {
219229e83d4bSgd78059 /* not running, don't touch anything */
219329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
219429e83d4bSgd78059 return (DDI_INTR_CLAIMED);
219529e83d4bSgd78059 }
219629e83d4bSgd78059
219729e83d4bSgd78059 if (status & INT_RXOK) {
219829e83d4bSgd78059 /* receive packets */
219977860f66SGarrett D'Amore if (mxfe_receive(mxfep, &mp)) {
220077860f66SGarrett D'Amore error = B_TRUE;
220177860f66SGarrett D'Amore }
220229e83d4bSgd78059 }
220329e83d4bSgd78059
220429e83d4bSgd78059 if (status & INT_TXOK) {
220529e83d4bSgd78059 /* transmit completed */
220629e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
220729e83d4bSgd78059 mxfe_reclaim(mxfep);
220829e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
220929e83d4bSgd78059 }
221029e83d4bSgd78059
221129e83d4bSgd78059 if (((status & (INT_TIMER|INT_ANEG)) != 0) ||
221229e83d4bSgd78059 ((mxfep->mxfe_linkup == LINK_STATE_UP) &&
221329e83d4bSgd78059 ((status & (INT_10LINK|INT_100LINK)) != 0))) {
221429e83d4bSgd78059 /* rescan the link */
221529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
221629e83d4bSgd78059 mxfe_checklink(mxfep);
221729e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
221829e83d4bSgd78059 }
221929e83d4bSgd78059
222029e83d4bSgd78059 if (status & (INT_RXSTOPPED|INT_TXSTOPPED|INT_RXNOBUF|
222129e83d4bSgd78059 INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) {
222229e83d4bSgd78059
222329e83d4bSgd78059 if (status & (INT_RXJABBER | INT_TXJABBER)) {
222429e83d4bSgd78059 mxfep->mxfe_jabber++;
222529e83d4bSgd78059 }
222677860f66SGarrett D'Amore DBG(DWARN, "error interrupt: status %x", status);
222777860f66SGarrett D'Amore error = B_TRUE;
222829e83d4bSgd78059 }
222929e83d4bSgd78059
223029e83d4bSgd78059 if (status & INT_BUSERR) {
223129e83d4bSgd78059 switch (status & SR_BERR_TYPE) {
223229e83d4bSgd78059 case SR_BERR_PARITY:
223329e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI parity error");
223429e83d4bSgd78059 break;
223529e83d4bSgd78059 case SR_BERR_TARGET_ABORT:
223629e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI target abort");
223729e83d4bSgd78059 break;
223829e83d4bSgd78059 case SR_BERR_MASTER_ABORT:
223929e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "PCI master abort");
224029e83d4bSgd78059 break;
224129e83d4bSgd78059 default:
224229e83d4bSgd78059 mxfe_error(mxfep->mxfe_dip, "Unknown PCI error");
224329e83d4bSgd78059 break;
224429e83d4bSgd78059 }
224529e83d4bSgd78059
224677860f66SGarrett D'Amore error = B_TRUE;
224777860f66SGarrett D'Amore }
224877860f66SGarrett D'Amore
224977860f66SGarrett D'Amore if (error) {
225029e83d4bSgd78059 /* reset the chip in an attempt to fix things */
225129e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
225229e83d4bSgd78059 mxfe_resetall(mxfep);
225329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
225429e83d4bSgd78059 }
225529e83d4bSgd78059
225629e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
225729e83d4bSgd78059
225829e83d4bSgd78059 /*
225929e83d4bSgd78059 * Send up packets. We do this outside of the intrlock.
226029e83d4bSgd78059 */
226129e83d4bSgd78059 if (mp) {
226229e83d4bSgd78059 mac_rx(mxfep->mxfe_mh, NULL, mp);
226329e83d4bSgd78059 }
226429e83d4bSgd78059
226529e83d4bSgd78059 return (DDI_INTR_CLAIMED);
226629e83d4bSgd78059 }
226729e83d4bSgd78059
226829e83d4bSgd78059 void
mxfe_enableinterrupts(mxfe_t * mxfep)226929e83d4bSgd78059 mxfe_enableinterrupts(mxfe_t *mxfep)
227029e83d4bSgd78059 {
227129e83d4bSgd78059 unsigned mask = INT_WANTED;
227229e83d4bSgd78059
227329e83d4bSgd78059 if (mxfep->mxfe_wantw)
227429e83d4bSgd78059 mask |= INT_TXOK;
227529e83d4bSgd78059
227629e83d4bSgd78059 if (MXFE_MODEL(mxfep) != MXFE_98713A)
227729e83d4bSgd78059 mask |= INT_LINKSTATUS;
227829e83d4bSgd78059
227929e83d4bSgd78059 DBG(DINTR, "setting int mask to 0x%x", mask);
228029e83d4bSgd78059 PUTCSR(mxfep, CSR_IER, mask);
228129e83d4bSgd78059 }
228229e83d4bSgd78059
228329e83d4bSgd78059 void
mxfe_disableinterrupts(mxfe_t * mxfep)228429e83d4bSgd78059 mxfe_disableinterrupts(mxfe_t *mxfep)
228529e83d4bSgd78059 {
228629e83d4bSgd78059 /* disable further interrupts */
228729e83d4bSgd78059 PUTCSR(mxfep, CSR_IER, 0);
228829e83d4bSgd78059
228929e83d4bSgd78059 /* clear any pending interrupts */
229029e83d4bSgd78059 PUTCSR(mxfep, CSR_SR, INT_ALL);
229129e83d4bSgd78059 }
229229e83d4bSgd78059
229329e83d4bSgd78059 void
mxfe_send_setup(mxfe_t * mxfep)229429e83d4bSgd78059 mxfe_send_setup(mxfe_t *mxfep)
229529e83d4bSgd78059 {
229629e83d4bSgd78059 mxfe_txbuf_t *txb;
229729e83d4bSgd78059 mxfe_desc_t *tmdp;
229829e83d4bSgd78059
229929e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
230029e83d4bSgd78059
230129e83d4bSgd78059 /* setup frame -- must be at head of list -- guaranteed by caller! */
230229e83d4bSgd78059 ASSERT(mxfep->mxfe_txsend == 0);
230329e83d4bSgd78059
230429e83d4bSgd78059 txb = mxfep->mxfe_txbufs[0];
230529e83d4bSgd78059 tmdp = &mxfep->mxfe_txdescp[0];
230629e83d4bSgd78059
230729e83d4bSgd78059 bzero(txb->txb_buf, MXFE_SETUP_LEN);
230829e83d4bSgd78059
230929e83d4bSgd78059 /* program the unicast address */
231029e83d4bSgd78059 txb->txb_buf[156] = mxfep->mxfe_curraddr[0];
231129e83d4bSgd78059 txb->txb_buf[157] = mxfep->mxfe_curraddr[1];
231229e83d4bSgd78059 txb->txb_buf[160] = mxfep->mxfe_curraddr[2];
231329e83d4bSgd78059 txb->txb_buf[161] = mxfep->mxfe_curraddr[3];
231429e83d4bSgd78059 txb->txb_buf[164] = mxfep->mxfe_curraddr[4];
231529e83d4bSgd78059 txb->txb_buf[165] = mxfep->mxfe_curraddr[5];
231629e83d4bSgd78059
231729e83d4bSgd78059 /* make sure that the hardware can see it */
231829e83d4bSgd78059 SYNCTXBUF(txb, MXFE_SETUP_LEN, DDI_DMA_SYNC_FORDEV);
231929e83d4bSgd78059
232029e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_control,
232129e83d4bSgd78059 TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE | TXCTL_HASHPERF |
232229e83d4bSgd78059 TXCTL_SETUP | MXFE_SETUP_LEN);
232329e83d4bSgd78059
232429e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer1, txb->txb_paddr);
232529e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
232629e83d4bSgd78059 PUTTXDESC(mxfep, tmdp->desc_status, TXSTAT_OWN);
232729e83d4bSgd78059
232829e83d4bSgd78059 /* sync the descriptor out to the device */
232929e83d4bSgd78059 SYNCTXDESC(mxfep, 0, DDI_DMA_SYNC_FORDEV);
233029e83d4bSgd78059
233129e83d4bSgd78059 /*
233229e83d4bSgd78059 * wake up the chip ... inside the lock to protect against DR suspend,
233329e83d4bSgd78059 * etc.
233429e83d4bSgd78059 */
233529e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0);
233629e83d4bSgd78059 mxfep->mxfe_txsend++;
233729e83d4bSgd78059 mxfep->mxfe_txavail--;
233829e83d4bSgd78059
233929e83d4bSgd78059 /*
234029e83d4bSgd78059 * Program promiscuous mode.
234129e83d4bSgd78059 */
234229e83d4bSgd78059 if (mxfep->mxfe_promisc) {
234329e83d4bSgd78059 SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
234429e83d4bSgd78059 } else {
234529e83d4bSgd78059 CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
234629e83d4bSgd78059 }
234729e83d4bSgd78059 }
234829e83d4bSgd78059
234929e83d4bSgd78059 boolean_t
mxfe_send(mxfe_t * mxfep,mblk_t * mp)235029e83d4bSgd78059 mxfe_send(mxfe_t *mxfep, mblk_t *mp)
235129e83d4bSgd78059 {
235229e83d4bSgd78059 size_t len;
235329e83d4bSgd78059 mxfe_txbuf_t *txb;
235429e83d4bSgd78059 mxfe_desc_t *tmd;
235529e83d4bSgd78059 uint32_t control;
235629e83d4bSgd78059 int txsend;
235729e83d4bSgd78059
235829e83d4bSgd78059 ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
235929e83d4bSgd78059 ASSERT(mp != NULL);
236029e83d4bSgd78059
236129e83d4bSgd78059 len = msgsize(mp);
236229e83d4bSgd78059 if (len > ETHERVLANMTU) {
236329e83d4bSgd78059 DBG(DXMIT, "frame too long: %d", len);
236429e83d4bSgd78059 mxfep->mxfe_macxmt_errors++;
236529e83d4bSgd78059 freemsg(mp);
236629e83d4bSgd78059 return (B_TRUE);
236729e83d4bSgd78059 }
236829e83d4bSgd78059
236929e83d4bSgd78059 if (mxfep->mxfe_txavail < MXFE_TXRECLAIM)
237029e83d4bSgd78059 mxfe_reclaim(mxfep);
237129e83d4bSgd78059
237229e83d4bSgd78059 if (mxfep->mxfe_txavail == 0) {
237329e83d4bSgd78059 /* no more tmds */
237429e83d4bSgd78059 mxfep->mxfe_wantw = B_TRUE;
237529e83d4bSgd78059 /* enable TX interrupt */
237629e83d4bSgd78059 mxfe_enableinterrupts(mxfep);
237729e83d4bSgd78059 return (B_FALSE);
237829e83d4bSgd78059 }
237929e83d4bSgd78059
238029e83d4bSgd78059 txsend = mxfep->mxfe_txsend;
238129e83d4bSgd78059
238229e83d4bSgd78059 /*
238329e83d4bSgd78059 * For simplicity, we just do a copy into a preallocated
238429e83d4bSgd78059 * DMA buffer.
238529e83d4bSgd78059 */
238629e83d4bSgd78059
238729e83d4bSgd78059 txb = mxfep->mxfe_txbufs[txsend];
238829e83d4bSgd78059 mcopymsg(mp, txb->txb_buf); /* frees mp! */
238929e83d4bSgd78059
239029e83d4bSgd78059 /*
239129e83d4bSgd78059 * Statistics.
239229e83d4bSgd78059 */
239329e83d4bSgd78059 mxfep->mxfe_opackets++;
239429e83d4bSgd78059 mxfep->mxfe_obytes += len;
239529e83d4bSgd78059 if (txb->txb_buf[0] & 0x1) {
239629e83d4bSgd78059 if (bcmp(txb->txb_buf, mxfe_broadcast, ETHERADDRL) != 0)
239729e83d4bSgd78059 mxfep->mxfe_multixmt++;
239829e83d4bSgd78059 else
239929e83d4bSgd78059 mxfep->mxfe_brdcstxmt++;
240029e83d4bSgd78059 }
240129e83d4bSgd78059
240229e83d4bSgd78059 /* note len is already known to be a small unsigned */
240329e83d4bSgd78059 control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
240429e83d4bSgd78059
240529e83d4bSgd78059 if (txsend == (MXFE_TXRING - 1))
240629e83d4bSgd78059 control |= TXCTL_ENDRING;
240729e83d4bSgd78059
240829e83d4bSgd78059 tmd = &mxfep->mxfe_txdescp[txsend];
240929e83d4bSgd78059
241029e83d4bSgd78059 SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV);
241129e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_control, control);
241229e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_buffer1, txb->txb_paddr);
241329e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_buffer2, 0);
241429e83d4bSgd78059 PUTTXDESC(mxfep, tmd->desc_status, TXSTAT_OWN);
241529e83d4bSgd78059 /* sync the descriptor out to the device */
241629e83d4bSgd78059 SYNCTXDESC(mxfep, txsend, DDI_DMA_SYNC_FORDEV);
241729e83d4bSgd78059
241829e83d4bSgd78059 /*
241929e83d4bSgd78059 * Note the new values of txavail and txsend.
242029e83d4bSgd78059 */
242129e83d4bSgd78059 mxfep->mxfe_txavail--;
242229e83d4bSgd78059 mxfep->mxfe_txsend = (txsend + 1) % MXFE_TXRING;
242329e83d4bSgd78059
242429e83d4bSgd78059 /*
242529e83d4bSgd78059 * It should never, ever take more than 5 seconds to drain
242629e83d4bSgd78059 * the ring. If it happens, then we are stuck!
242729e83d4bSgd78059 */
242829e83d4bSgd78059 mxfep->mxfe_txstall_time = gethrtime() + (5 * 1000000000ULL);
242929e83d4bSgd78059
243029e83d4bSgd78059 /*
243129e83d4bSgd78059 * wake up the chip ... inside the lock to protect against DR suspend,
243229e83d4bSgd78059 * etc.
243329e83d4bSgd78059 */
243429e83d4bSgd78059 PUTCSR(mxfep, CSR_TDR, 0);
243529e83d4bSgd78059
243629e83d4bSgd78059 return (B_TRUE);
243729e83d4bSgd78059 }
243829e83d4bSgd78059
243929e83d4bSgd78059 /*
244029e83d4bSgd78059 * Reclaim buffers that have completed transmission.
244129e83d4bSgd78059 */
244229e83d4bSgd78059 void
mxfe_reclaim(mxfe_t * mxfep)244329e83d4bSgd78059 mxfe_reclaim(mxfe_t *mxfep)
244429e83d4bSgd78059 {
244529e83d4bSgd78059 mxfe_desc_t *tmdp;
244629e83d4bSgd78059
244729e83d4bSgd78059 while (mxfep->mxfe_txavail != MXFE_TXRING) {
244829e83d4bSgd78059 uint32_t status;
244929e83d4bSgd78059 uint32_t control;
245029e83d4bSgd78059 int index = mxfep->mxfe_txreclaim;
245129e83d4bSgd78059
245229e83d4bSgd78059 tmdp = &mxfep->mxfe_txdescp[index];
245329e83d4bSgd78059
245429e83d4bSgd78059 /* sync it before we read it */
245529e83d4bSgd78059 SYNCTXDESC(mxfep, index, DDI_DMA_SYNC_FORKERNEL);
245629e83d4bSgd78059
245729e83d4bSgd78059 control = GETTXDESC(mxfep, tmdp->desc_control);
245829e83d4bSgd78059 status = GETTXDESC(mxfep, tmdp->desc_status);
245929e83d4bSgd78059
246029e83d4bSgd78059 if (status & TXSTAT_OWN) {
246129e83d4bSgd78059 /* chip is still working on it, we're done */
246229e83d4bSgd78059 break;
246329e83d4bSgd78059 }
246429e83d4bSgd78059
246529e83d4bSgd78059 mxfep->mxfe_txavail++;
246629e83d4bSgd78059 mxfep->mxfe_txreclaim = (index + 1) % MXFE_TXRING;
246729e83d4bSgd78059
246829e83d4bSgd78059 /* in the most common successful case, all bits are clear */
246929e83d4bSgd78059 if (status == 0)
247029e83d4bSgd78059 continue;
247129e83d4bSgd78059
247229e83d4bSgd78059 if (((control & TXCTL_SETUP) != 0) ||
247329e83d4bSgd78059 ((control & TXCTL_LAST) == 0)) {
247429e83d4bSgd78059 /* no interesting statistics here */
247529e83d4bSgd78059 continue;
247629e83d4bSgd78059 }
247729e83d4bSgd78059
247829e83d4bSgd78059 if (status & TXSTAT_TXERR) {
247929e83d4bSgd78059 mxfep->mxfe_errxmt++;
248029e83d4bSgd78059
248129e83d4bSgd78059 if (status & TXSTAT_JABBER) {
248229e83d4bSgd78059 /* transmit jabber timeout */
248329e83d4bSgd78059 mxfep->mxfe_macxmt_errors++;
248429e83d4bSgd78059 }
248529e83d4bSgd78059 if (status & (TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
248629e83d4bSgd78059 mxfep->mxfe_carrier_errors++;
248729e83d4bSgd78059 }
248829e83d4bSgd78059 if (status & TXSTAT_UFLOW) {
248929e83d4bSgd78059 mxfep->mxfe_underflow++;
249029e83d4bSgd78059 }
249129e83d4bSgd78059 if (status & TXSTAT_LATECOL) {
249229e83d4bSgd78059 mxfep->mxfe_tx_late_collisions++;
249329e83d4bSgd78059 }
249429e83d4bSgd78059 if (status & TXSTAT_EXCOLL) {
249529e83d4bSgd78059 mxfep->mxfe_ex_collisions++;
249629e83d4bSgd78059 mxfep->mxfe_collisions += 16;
249729e83d4bSgd78059 }
249829e83d4bSgd78059 }
249929e83d4bSgd78059
250029e83d4bSgd78059 if (status & TXSTAT_DEFER) {
250129e83d4bSgd78059 mxfep->mxfe_defer_xmts++;
250229e83d4bSgd78059 }
250329e83d4bSgd78059
250429e83d4bSgd78059 /* collision counting */
250529e83d4bSgd78059 if (TXCOLLCNT(status) == 1) {
250629e83d4bSgd78059 mxfep->mxfe_collisions++;
250729e83d4bSgd78059 mxfep->mxfe_first_collisions++;
250829e83d4bSgd78059 } else if (TXCOLLCNT(status)) {
250929e83d4bSgd78059 mxfep->mxfe_collisions += TXCOLLCNT(status);
251029e83d4bSgd78059 mxfep->mxfe_multi_collisions += TXCOLLCNT(status);
251129e83d4bSgd78059 }
251229e83d4bSgd78059 }
251329e83d4bSgd78059
251429e83d4bSgd78059 if (mxfep->mxfe_txavail >= MXFE_TXRESCHED) {
251529e83d4bSgd78059 if (mxfep->mxfe_wantw) {
251629e83d4bSgd78059 /*
251729e83d4bSgd78059 * we were able to reclaim some packets, so
251829e83d4bSgd78059 * disable tx interrupts
251929e83d4bSgd78059 */
252029e83d4bSgd78059 mxfep->mxfe_wantw = B_FALSE;
252129e83d4bSgd78059 mxfe_enableinterrupts(mxfep);
252229e83d4bSgd78059 mac_tx_update(mxfep->mxfe_mh);
252329e83d4bSgd78059 }
252429e83d4bSgd78059 }
252529e83d4bSgd78059 }
252629e83d4bSgd78059
252777860f66SGarrett D'Amore boolean_t
mxfe_receive(mxfe_t * mxfep,mblk_t ** rxchain)252877860f66SGarrett D'Amore mxfe_receive(mxfe_t *mxfep, mblk_t **rxchain)
252929e83d4bSgd78059 {
253029e83d4bSgd78059 unsigned len;
253129e83d4bSgd78059 mxfe_rxbuf_t *rxb;
253229e83d4bSgd78059 mxfe_desc_t *rmd;
253329e83d4bSgd78059 uint32_t status;
253429e83d4bSgd78059 mblk_t *mpchain, **mpp, *mp;
253529e83d4bSgd78059 int head, cnt;
253677860f66SGarrett D'Amore boolean_t error = B_FALSE;
253729e83d4bSgd78059
253829e83d4bSgd78059 mpchain = NULL;
253929e83d4bSgd78059 mpp = &mpchain;
254029e83d4bSgd78059 head = mxfep->mxfe_rxhead;
254129e83d4bSgd78059
254229e83d4bSgd78059 /* limit the number of packets we process to a ring size */
254329e83d4bSgd78059 for (cnt = 0; cnt < MXFE_RXRING; cnt++) {
254429e83d4bSgd78059
254529e83d4bSgd78059 DBG(DRECV, "receive at index %d", head);
254629e83d4bSgd78059
254729e83d4bSgd78059 rmd = &mxfep->mxfe_rxdescp[head];
254829e83d4bSgd78059 rxb = mxfep->mxfe_rxbufs[head];
254929e83d4bSgd78059
255029e83d4bSgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORKERNEL);
255129e83d4bSgd78059 status = GETRXDESC(mxfep, rmd->desc_status);
255229e83d4bSgd78059 if (status & RXSTAT_OWN) {
255329e83d4bSgd78059 /* chip is still chewing on it */
255429e83d4bSgd78059 break;
255529e83d4bSgd78059 }
255629e83d4bSgd78059
255729e83d4bSgd78059 /* discard the ethernet frame checksum */
255829e83d4bSgd78059 len = RXLENGTH(status) - ETHERFCSL;
255929e83d4bSgd78059
256029e83d4bSgd78059 DBG(DRECV, "recv length %d, status %x", len, status);
256129e83d4bSgd78059
256229e83d4bSgd78059 if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
256329e83d4bSgd78059 (RXSTAT_FIRST | RXSTAT_LAST)) {
256429e83d4bSgd78059
256529e83d4bSgd78059 mxfep->mxfe_errrcv++;
256629e83d4bSgd78059
256729e83d4bSgd78059 /*
256829e83d4bSgd78059 * Abnormal status bits detected, analyze further.
256929e83d4bSgd78059 */
257029e83d4bSgd78059 if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) !=
257129e83d4bSgd78059 (RXSTAT_LAST|RXSTAT_FIRST)) {
257277860f66SGarrett D'Amore /* someone trying to send jumbo frames? */
257329e83d4bSgd78059 DBG(DRECV, "rx packet overspill");
257429e83d4bSgd78059 if (status & RXSTAT_FIRST) {
257529e83d4bSgd78059 mxfep->mxfe_toolong_errors++;
257629e83d4bSgd78059 }
257729e83d4bSgd78059 } else if (status & RXSTAT_DESCERR) {
257877860f66SGarrett D'Amore /* this should never occur! */
257929e83d4bSgd78059 mxfep->mxfe_macrcv_errors++;
258077860f66SGarrett D'Amore error = B_TRUE;
258129e83d4bSgd78059
258229e83d4bSgd78059 } else if (status & RXSTAT_RUNT) {
258329e83d4bSgd78059 mxfep->mxfe_runt++;
258429e83d4bSgd78059
258529e83d4bSgd78059 } else if (status & RXSTAT_COLLSEEN) {
258629e83d4bSgd78059 /* this should really be rx_late_collisions */
258729e83d4bSgd78059 mxfep->mxfe_macrcv_errors++;
258829e83d4bSgd78059
258929e83d4bSgd78059 } else if (status & RXSTAT_DRIBBLE) {
259029e83d4bSgd78059 mxfep->mxfe_align_errors++;
259129e83d4bSgd78059
259229e83d4bSgd78059 } else if (status & RXSTAT_CRCERR) {
259329e83d4bSgd78059 mxfep->mxfe_fcs_errors++;
259429e83d4bSgd78059
259529e83d4bSgd78059 } else if (status & RXSTAT_OFLOW) {
259677860f66SGarrett D'Amore /* this is a MAC FIFO error, need to reset */
259729e83d4bSgd78059 mxfep->mxfe_overflow++;
259877860f66SGarrett D'Amore error = B_TRUE;
259929e83d4bSgd78059 }
260029e83d4bSgd78059 }
260129e83d4bSgd78059
260229e83d4bSgd78059 else if (len > ETHERVLANMTU) {
260329e83d4bSgd78059 mxfep->mxfe_errrcv++;
260429e83d4bSgd78059 mxfep->mxfe_toolong_errors++;
260529e83d4bSgd78059 }
260629e83d4bSgd78059
260729e83d4bSgd78059 /*
260829e83d4bSgd78059 * At this point, the chip thinks the packet is OK.
260929e83d4bSgd78059 */
261029e83d4bSgd78059 else {
261129e83d4bSgd78059 mp = allocb(len + MXFE_HEADROOM, 0);
261229e83d4bSgd78059 if (mp == NULL) {
261329e83d4bSgd78059 mxfep->mxfe_errrcv++;
261429e83d4bSgd78059 mxfep->mxfe_norcvbuf++;
261529e83d4bSgd78059 goto skip;
261629e83d4bSgd78059 }
261729e83d4bSgd78059
261829e83d4bSgd78059 /* sync the buffer before we look at it */
261929e83d4bSgd78059 SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
262029e83d4bSgd78059 mp->b_rptr += MXFE_HEADROOM;
262129e83d4bSgd78059 mp->b_wptr = mp->b_rptr + len;
262229e83d4bSgd78059 bcopy((char *)rxb->rxb_buf, mp->b_rptr, len);
262329e83d4bSgd78059
262429e83d4bSgd78059 mxfep->mxfe_ipackets++;
262529e83d4bSgd78059 mxfep->mxfe_rbytes += len;
262629e83d4bSgd78059 if (status & RXSTAT_GROUP) {
262729e83d4bSgd78059 if (bcmp(mp->b_rptr, mxfe_broadcast,
262829e83d4bSgd78059 ETHERADDRL) == 0)
262929e83d4bSgd78059 mxfep->mxfe_brdcstrcv++;
263029e83d4bSgd78059 else
263129e83d4bSgd78059 mxfep->mxfe_multircv++;
263229e83d4bSgd78059 }
263329e83d4bSgd78059 *mpp = mp;
263429e83d4bSgd78059 mpp = &mp->b_next;
263529e83d4bSgd78059 }
263629e83d4bSgd78059
263729e83d4bSgd78059 skip:
263829e83d4bSgd78059 /* return ring entry to the hardware */
263929e83d4bSgd78059 PUTRXDESC(mxfep, rmd->desc_status, RXSTAT_OWN);
264029e83d4bSgd78059 SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORDEV);
264129e83d4bSgd78059
264229e83d4bSgd78059 /* advance to next RMD */
264329e83d4bSgd78059 head = (head + 1) % MXFE_RXRING;
264429e83d4bSgd78059 }
264529e83d4bSgd78059
264629e83d4bSgd78059 mxfep->mxfe_rxhead = head;
264729e83d4bSgd78059
264877860f66SGarrett D'Amore *rxchain = mpchain;
264977860f66SGarrett D'Amore return (error);
265029e83d4bSgd78059 }
265129e83d4bSgd78059
265229e83d4bSgd78059 int
mxfe_m_stat(void * arg,uint_t stat,uint64_t * val)265329e83d4bSgd78059 mxfe_m_stat(void *arg, uint_t stat, uint64_t *val)
265429e83d4bSgd78059 {
265529e83d4bSgd78059 mxfe_t *mxfep = arg;
265629e83d4bSgd78059
265729e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
265829e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == MXFE_RUNNING)
265929e83d4bSgd78059 mxfe_reclaim(mxfep);
266029e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
266129e83d4bSgd78059
266229e83d4bSgd78059 switch (stat) {
266329e83d4bSgd78059 case MAC_STAT_IFSPEED:
266429e83d4bSgd78059 *val = mxfep->mxfe_ifspeed;
266529e83d4bSgd78059 break;
266629e83d4bSgd78059
266729e83d4bSgd78059 case MAC_STAT_MULTIRCV:
266829e83d4bSgd78059 *val = mxfep->mxfe_multircv;
266929e83d4bSgd78059 break;
267029e83d4bSgd78059
267129e83d4bSgd78059 case MAC_STAT_BRDCSTRCV:
267229e83d4bSgd78059 *val = mxfep->mxfe_brdcstrcv;
267329e83d4bSgd78059 break;
267429e83d4bSgd78059
267529e83d4bSgd78059 case MAC_STAT_MULTIXMT:
267629e83d4bSgd78059 *val = mxfep->mxfe_multixmt;
267729e83d4bSgd78059 break;
267829e83d4bSgd78059
267929e83d4bSgd78059 case MAC_STAT_BRDCSTXMT:
268029e83d4bSgd78059 *val = mxfep->mxfe_brdcstxmt;
268129e83d4bSgd78059 break;
268229e83d4bSgd78059
268329e83d4bSgd78059 case MAC_STAT_IPACKETS:
268429e83d4bSgd78059 *val = mxfep->mxfe_ipackets;
268529e83d4bSgd78059 break;
268629e83d4bSgd78059
268729e83d4bSgd78059 case MAC_STAT_RBYTES:
268829e83d4bSgd78059 *val = mxfep->mxfe_rbytes;
268929e83d4bSgd78059 break;
269029e83d4bSgd78059
269129e83d4bSgd78059 case MAC_STAT_OPACKETS:
269229e83d4bSgd78059 *val = mxfep->mxfe_opackets;
269329e83d4bSgd78059 break;
269429e83d4bSgd78059
269529e83d4bSgd78059 case MAC_STAT_OBYTES:
269629e83d4bSgd78059 *val = mxfep->mxfe_obytes;
269729e83d4bSgd78059 break;
269829e83d4bSgd78059
269929e83d4bSgd78059 case MAC_STAT_NORCVBUF:
270029e83d4bSgd78059 *val = mxfep->mxfe_norcvbuf;
270129e83d4bSgd78059 break;
270229e83d4bSgd78059
270329e83d4bSgd78059 case MAC_STAT_NOXMTBUF:
270429e83d4bSgd78059 *val = mxfep->mxfe_noxmtbuf;
270529e83d4bSgd78059 break;
270629e83d4bSgd78059
270729e83d4bSgd78059 case MAC_STAT_COLLISIONS:
270829e83d4bSgd78059 *val = mxfep->mxfe_collisions;
270929e83d4bSgd78059 break;
271029e83d4bSgd78059
271129e83d4bSgd78059 case MAC_STAT_IERRORS:
271229e83d4bSgd78059 *val = mxfep->mxfe_errrcv;
271329e83d4bSgd78059 break;
271429e83d4bSgd78059
271529e83d4bSgd78059 case MAC_STAT_OERRORS:
271629e83d4bSgd78059 *val = mxfep->mxfe_errxmt;
271729e83d4bSgd78059 break;
271829e83d4bSgd78059
271929e83d4bSgd78059 case ETHER_STAT_LINK_DUPLEX:
272029e83d4bSgd78059 *val = mxfep->mxfe_duplex;
272129e83d4bSgd78059 break;
272229e83d4bSgd78059
272329e83d4bSgd78059 case ETHER_STAT_ALIGN_ERRORS:
272429e83d4bSgd78059 *val = mxfep->mxfe_align_errors;
272529e83d4bSgd78059 break;
272629e83d4bSgd78059
272729e83d4bSgd78059 case ETHER_STAT_FCS_ERRORS:
272829e83d4bSgd78059 *val = mxfep->mxfe_fcs_errors;
272929e83d4bSgd78059 break;
273029e83d4bSgd78059
273129e83d4bSgd78059 case ETHER_STAT_SQE_ERRORS:
273229e83d4bSgd78059 *val = mxfep->mxfe_sqe_errors;
273329e83d4bSgd78059 break;
273429e83d4bSgd78059
273529e83d4bSgd78059 case ETHER_STAT_DEFER_XMTS:
273629e83d4bSgd78059 *val = mxfep->mxfe_defer_xmts;
273729e83d4bSgd78059 break;
273829e83d4bSgd78059
273929e83d4bSgd78059 case ETHER_STAT_FIRST_COLLISIONS:
274029e83d4bSgd78059 *val = mxfep->mxfe_first_collisions;
274129e83d4bSgd78059 break;
274229e83d4bSgd78059
274329e83d4bSgd78059 case ETHER_STAT_MULTI_COLLISIONS:
274429e83d4bSgd78059 *val = mxfep->mxfe_multi_collisions;
274529e83d4bSgd78059 break;
274629e83d4bSgd78059
274729e83d4bSgd78059 case ETHER_STAT_TX_LATE_COLLISIONS:
274829e83d4bSgd78059 *val = mxfep->mxfe_tx_late_collisions;
274929e83d4bSgd78059 break;
275029e83d4bSgd78059
275129e83d4bSgd78059 case ETHER_STAT_EX_COLLISIONS:
275229e83d4bSgd78059 *val = mxfep->mxfe_ex_collisions;
275329e83d4bSgd78059 break;
275429e83d4bSgd78059
275529e83d4bSgd78059 case ETHER_STAT_MACXMT_ERRORS:
275629e83d4bSgd78059 *val = mxfep->mxfe_macxmt_errors;
275729e83d4bSgd78059 break;
275829e83d4bSgd78059
275929e83d4bSgd78059 case ETHER_STAT_CARRIER_ERRORS:
276029e83d4bSgd78059 *val = mxfep->mxfe_carrier_errors;
276129e83d4bSgd78059 break;
276229e83d4bSgd78059
276329e83d4bSgd78059 case ETHER_STAT_TOOLONG_ERRORS:
276429e83d4bSgd78059 *val = mxfep->mxfe_toolong_errors;
276529e83d4bSgd78059 break;
276629e83d4bSgd78059
276729e83d4bSgd78059 case ETHER_STAT_MACRCV_ERRORS:
276829e83d4bSgd78059 *val = mxfep->mxfe_macrcv_errors;
276929e83d4bSgd78059 break;
277029e83d4bSgd78059
277129e83d4bSgd78059 case MAC_STAT_OVERFLOWS:
277229e83d4bSgd78059 *val = mxfep->mxfe_overflow;
277329e83d4bSgd78059 break;
277429e83d4bSgd78059
277529e83d4bSgd78059 case MAC_STAT_UNDERFLOWS:
277629e83d4bSgd78059 *val = mxfep->mxfe_underflow;
277729e83d4bSgd78059 break;
277829e83d4bSgd78059
277929e83d4bSgd78059 case ETHER_STAT_TOOSHORT_ERRORS:
278029e83d4bSgd78059 *val = mxfep->mxfe_runt;
278129e83d4bSgd78059 break;
278229e83d4bSgd78059
278329e83d4bSgd78059 case ETHER_STAT_JABBER_ERRORS:
278429e83d4bSgd78059 *val = mxfep->mxfe_jabber;
278529e83d4bSgd78059 break;
278629e83d4bSgd78059
278729e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100T4:
278829e83d4bSgd78059 *val = mxfep->mxfe_adv_100T4;
278929e83d4bSgd78059 break;
279029e83d4bSgd78059
279129e83d4bSgd78059 case ETHER_STAT_LP_CAP_100T4:
279229e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_T4) ? 1 : 0;
279329e83d4bSgd78059 break;
279429e83d4bSgd78059
279596fb08b9Sgd78059 case ETHER_STAT_CAP_100T4:
279696fb08b9Sgd78059 *val = mxfep->mxfe_cap_100T4;
279796fb08b9Sgd78059 break;
279896fb08b9Sgd78059
279929e83d4bSgd78059 case ETHER_STAT_CAP_100FDX:
280096fb08b9Sgd78059 *val = mxfep->mxfe_cap_100fdx;
280129e83d4bSgd78059 break;
280229e83d4bSgd78059
280329e83d4bSgd78059 case ETHER_STAT_CAP_100HDX:
280496fb08b9Sgd78059 *val = mxfep->mxfe_cap_100hdx;
280529e83d4bSgd78059 break;
280629e83d4bSgd78059
280729e83d4bSgd78059 case ETHER_STAT_CAP_10FDX:
280896fb08b9Sgd78059 *val = mxfep->mxfe_cap_10fdx;
280929e83d4bSgd78059 break;
281029e83d4bSgd78059
281129e83d4bSgd78059 case ETHER_STAT_CAP_10HDX:
281296fb08b9Sgd78059 *val = mxfep->mxfe_cap_10hdx;
281329e83d4bSgd78059 break;
281429e83d4bSgd78059
281529e83d4bSgd78059 case ETHER_STAT_CAP_AUTONEG:
281696fb08b9Sgd78059 *val = mxfep->mxfe_cap_aneg;
281729e83d4bSgd78059 break;
281829e83d4bSgd78059
281929e83d4bSgd78059 case ETHER_STAT_LINK_AUTONEG:
282029e83d4bSgd78059 *val = ((mxfep->mxfe_adv_aneg != 0) &&
282129e83d4bSgd78059 ((mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) != 0));
282229e83d4bSgd78059 break;
282329e83d4bSgd78059
282429e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100FDX:
282529e83d4bSgd78059 *val = mxfep->mxfe_adv_100fdx;
282629e83d4bSgd78059 break;
282729e83d4bSgd78059
282829e83d4bSgd78059 case ETHER_STAT_ADV_CAP_100HDX:
282929e83d4bSgd78059 *val = mxfep->mxfe_adv_100hdx;
283029e83d4bSgd78059 break;
283129e83d4bSgd78059
283229e83d4bSgd78059 case ETHER_STAT_ADV_CAP_10FDX:
283329e83d4bSgd78059 *val = mxfep->mxfe_adv_10fdx;
283429e83d4bSgd78059 break;
283529e83d4bSgd78059
283629e83d4bSgd78059 case ETHER_STAT_ADV_CAP_10HDX:
283729e83d4bSgd78059 *val = mxfep->mxfe_adv_10hdx;
283829e83d4bSgd78059 break;
283929e83d4bSgd78059
284029e83d4bSgd78059 case ETHER_STAT_ADV_CAP_AUTONEG:
284129e83d4bSgd78059 *val = mxfep->mxfe_adv_aneg;
284229e83d4bSgd78059 break;
284329e83d4bSgd78059
284429e83d4bSgd78059 case ETHER_STAT_LP_CAP_100FDX:
284529e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX_FD) ? 1 : 0;
284629e83d4bSgd78059 break;
284729e83d4bSgd78059
284829e83d4bSgd78059 case ETHER_STAT_LP_CAP_100HDX:
284929e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX) ? 1 : 0;
285029e83d4bSgd78059 break;
285129e83d4bSgd78059
285229e83d4bSgd78059 case ETHER_STAT_LP_CAP_10FDX:
285329e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T_FD) ? 1 : 0;
285429e83d4bSgd78059 break;
285529e83d4bSgd78059
285629e83d4bSgd78059 case ETHER_STAT_LP_CAP_10HDX:
285729e83d4bSgd78059 *val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T) ? 1 : 0;
285829e83d4bSgd78059 break;
285929e83d4bSgd78059
286029e83d4bSgd78059 case ETHER_STAT_LP_CAP_AUTONEG:
286129e83d4bSgd78059 *val = (mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) ? 1 : 0;
286229e83d4bSgd78059 break;
286329e83d4bSgd78059
286429e83d4bSgd78059 case ETHER_STAT_XCVR_ADDR:
286529e83d4bSgd78059 *val = mxfep->mxfe_phyaddr;
286629e83d4bSgd78059 break;
286729e83d4bSgd78059
286829e83d4bSgd78059 case ETHER_STAT_XCVR_ID:
286929e83d4bSgd78059 *val = mxfep->mxfe_phyid;
287029e83d4bSgd78059 break;
287129e83d4bSgd78059
287229e83d4bSgd78059 case ETHER_STAT_XCVR_INUSE:
287329e83d4bSgd78059 *val = mxfep->mxfe_phyinuse;
287429e83d4bSgd78059 break;
287529e83d4bSgd78059
287629e83d4bSgd78059 default:
287729e83d4bSgd78059 return (ENOTSUP);
287829e83d4bSgd78059 }
287929e83d4bSgd78059 return (0);
288029e83d4bSgd78059 }
288129e83d4bSgd78059
288296fb08b9Sgd78059 /*ARGSUSED*/
288396fb08b9Sgd78059 int
mxfe_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)2884*0dc2366fSVenugopal Iyer mxfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2885*0dc2366fSVenugopal Iyer void *val)
288629e83d4bSgd78059 {
288796fb08b9Sgd78059 mxfe_t *mxfep = arg;
288896fb08b9Sgd78059 int err = 0;
288929e83d4bSgd78059
289096fb08b9Sgd78059 switch (num) {
28913fd94f8cSam223141 case MAC_PROP_DUPLEX:
2892*0dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (link_duplex_t));
2893*0dc2366fSVenugopal Iyer bcopy(&mxfep->mxfe_duplex, val, sizeof (link_duplex_t));
289429e83d4bSgd78059 break;
289529e83d4bSgd78059
28963fd94f8cSam223141 case MAC_PROP_SPEED:
2897*0dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (uint64_t));
289896fb08b9Sgd78059 bcopy(&mxfep->mxfe_ifspeed, val, sizeof (uint64_t));
289929e83d4bSgd78059 break;
290096fb08b9Sgd78059
29013fd94f8cSam223141 case MAC_PROP_AUTONEG:
2902*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_aneg;
290396fb08b9Sgd78059 break;
290496fb08b9Sgd78059
29053fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP:
29063fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP:
2907*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100fdx;
290896fb08b9Sgd78059 break;
290996fb08b9Sgd78059
29103fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP:
29113fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP:
2912*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100hdx;
291396fb08b9Sgd78059 break;
291496fb08b9Sgd78059
29153fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP:
29163fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP:
2917*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_10fdx;
291896fb08b9Sgd78059 break;
291996fb08b9Sgd78059
29203fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP:
29213fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP:
2922*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_10hdx;
292396fb08b9Sgd78059 break;
292496fb08b9Sgd78059
29253fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP:
29263fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP:
2927*0dc2366fSVenugopal Iyer *(uint8_t *)val = mxfep->mxfe_adv_100T4;
292896fb08b9Sgd78059 break;
292996fb08b9Sgd78059
293096fb08b9Sgd78059 default:
293196fb08b9Sgd78059 err = ENOTSUP;
293229e83d4bSgd78059 }
293329e83d4bSgd78059
293496fb08b9Sgd78059 return (err);
293529e83d4bSgd78059 }
293629e83d4bSgd78059
293729e83d4bSgd78059 /*ARGSUSED*/
293829e83d4bSgd78059 int
mxfe_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)293996fb08b9Sgd78059 mxfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
294096fb08b9Sgd78059 const void *val)
294129e83d4bSgd78059 {
294296fb08b9Sgd78059 mxfe_t *mxfep = arg;
294396fb08b9Sgd78059 uint8_t *advp;
294496fb08b9Sgd78059 uint8_t *capp;
294529e83d4bSgd78059
294696fb08b9Sgd78059 switch (num) {
29473fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP:
294896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100fdx;
294996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100fdx;
295096fb08b9Sgd78059 break;
295129e83d4bSgd78059
29523fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP:
295396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100hdx;
295496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100hdx;
295596fb08b9Sgd78059 break;
295696fb08b9Sgd78059
29573fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP:
295896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_10fdx;
295996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_10fdx;
296096fb08b9Sgd78059 break;
296196fb08b9Sgd78059
29623fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP:
296396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_10hdx;
296496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_10hdx;
296596fb08b9Sgd78059 break;
296696fb08b9Sgd78059
29673fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP:
296896fb08b9Sgd78059 advp = &mxfep->mxfe_adv_100T4;
296996fb08b9Sgd78059 capp = &mxfep->mxfe_cap_100T4;
297096fb08b9Sgd78059 break;
297196fb08b9Sgd78059
29723fd94f8cSam223141 case MAC_PROP_AUTONEG:
297396fb08b9Sgd78059 advp = &mxfep->mxfe_adv_aneg;
297496fb08b9Sgd78059 capp = &mxfep->mxfe_cap_aneg;
297596fb08b9Sgd78059 break;
297696fb08b9Sgd78059
297796fb08b9Sgd78059 default:
297896fb08b9Sgd78059 return (ENOTSUP);
297929e83d4bSgd78059 }
298029e83d4bSgd78059
298196fb08b9Sgd78059 if (*capp == 0) /* ensure phy can support value */
298296fb08b9Sgd78059 return (ENOTSUP);
298329e83d4bSgd78059
298429e83d4bSgd78059 mutex_enter(&mxfep->mxfe_intrlock);
298529e83d4bSgd78059 mutex_enter(&mxfep->mxfe_xmtlock);
298629e83d4bSgd78059
298796fb08b9Sgd78059 if (*advp != *(const uint8_t *)val) {
298896fb08b9Sgd78059 *advp = *(const uint8_t *)val;
298996fb08b9Sgd78059
299029e83d4bSgd78059 if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
299129e83d4bSgd78059 MXFE_RUNNING) {
299229e83d4bSgd78059 /*
299329e83d4bSgd78059 * This re-initializes the phy, but it also
299429e83d4bSgd78059 * restarts transmit and receive rings.
299529e83d4bSgd78059 * Needless to say, changing the link
299629e83d4bSgd78059 * parameters is destructive to traffic in
299729e83d4bSgd78059 * progress.
299829e83d4bSgd78059 */
299929e83d4bSgd78059 mxfe_resetall(mxfep);
300029e83d4bSgd78059 }
300129e83d4bSgd78059 }
300229e83d4bSgd78059 mutex_exit(&mxfep->mxfe_xmtlock);
300329e83d4bSgd78059 mutex_exit(&mxfep->mxfe_intrlock);
300429e83d4bSgd78059
300529e83d4bSgd78059 return (0);
300629e83d4bSgd78059 }
300729e83d4bSgd78059
3008*0dc2366fSVenugopal Iyer static void
mxfe_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t mph)3009*0dc2366fSVenugopal Iyer mxfe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
3010*0dc2366fSVenugopal Iyer mac_prop_info_handle_t mph)
3011*0dc2366fSVenugopal Iyer {
3012*0dc2366fSVenugopal Iyer mxfe_t *mxfep = arg;
3013*0dc2366fSVenugopal Iyer
3014*0dc2366fSVenugopal Iyer _NOTE(ARGUNUSED(name));
3015*0dc2366fSVenugopal Iyer
3016*0dc2366fSVenugopal Iyer switch (num) {
3017*0dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX:
3018*0dc2366fSVenugopal Iyer case MAC_PROP_SPEED:
3019*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP:
3020*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP:
3021*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP:
3022*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP:
3023*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP:
3024*0dc2366fSVenugopal Iyer mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
3025*0dc2366fSVenugopal Iyer break;
3026*0dc2366fSVenugopal Iyer
3027*0dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG:
3028*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_aneg);
3029*0dc2366fSVenugopal Iyer break;
3030*0dc2366fSVenugopal Iyer
3031*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP:
3032*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100fdx);
3033*0dc2366fSVenugopal Iyer break;
3034*0dc2366fSVenugopal Iyer
3035*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP:
3036*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100hdx);
3037*0dc2366fSVenugopal Iyer break;
3038*0dc2366fSVenugopal Iyer
3039*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP:
3040*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10fdx);
3041*0dc2366fSVenugopal Iyer break;
3042*0dc2366fSVenugopal Iyer
3043*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP:
3044*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10hdx);
3045*0dc2366fSVenugopal Iyer break;
3046*0dc2366fSVenugopal Iyer
3047*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP:
3048*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100T4);
3049*0dc2366fSVenugopal Iyer break;
3050*0dc2366fSVenugopal Iyer }
3051*0dc2366fSVenugopal Iyer }
3052*0dc2366fSVenugopal Iyer
305329e83d4bSgd78059 /*
305429e83d4bSgd78059 * Debugging and error reporting.
305529e83d4bSgd78059 */
305629e83d4bSgd78059 void
mxfe_error(dev_info_t * dip,char * fmt,...)305729e83d4bSgd78059 mxfe_error(dev_info_t *dip, char *fmt, ...)
305829e83d4bSgd78059 {
305929e83d4bSgd78059 va_list ap;
306029e83d4bSgd78059 char buf[256];
306129e83d4bSgd78059
306229e83d4bSgd78059 va_start(ap, fmt);
306329e83d4bSgd78059 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
306429e83d4bSgd78059 va_end(ap);
306529e83d4bSgd78059
306629e83d4bSgd78059 if (dip) {
306729e83d4bSgd78059 cmn_err(CE_WARN, "%s%d: %s",
306829e83d4bSgd78059 ddi_driver_name(dip), ddi_get_instance(dip), buf);
306929e83d4bSgd78059 } else {
307029e83d4bSgd78059 cmn_err(CE_WARN, "mxfe: %s", buf);
307129e83d4bSgd78059 }
307229e83d4bSgd78059 }
307329e83d4bSgd78059
307429e83d4bSgd78059 #ifdef DEBUG
307529e83d4bSgd78059
307629e83d4bSgd78059 void
mxfe_dprintf(mxfe_t * mxfep,const char * func,int level,char * fmt,...)307729e83d4bSgd78059 mxfe_dprintf(mxfe_t *mxfep, const char *func, int level, char *fmt, ...)
307829e83d4bSgd78059 {
307929e83d4bSgd78059 va_list ap;
308029e83d4bSgd78059
308129e83d4bSgd78059 va_start(ap, fmt);
308229e83d4bSgd78059 if (mxfe_debug & level) {
308329e83d4bSgd78059 char tag[64];
308429e83d4bSgd78059 char buf[256];
308529e83d4bSgd78059
308629e83d4bSgd78059 if (mxfep && mxfep->mxfe_dip) {
308729e83d4bSgd78059 (void) snprintf(tag, sizeof (tag),
308829e83d4bSgd78059 "%s%d", ddi_driver_name(mxfep->mxfe_dip),
308929e83d4bSgd78059 ddi_get_instance(mxfep->mxfe_dip));
309029e83d4bSgd78059 } else {
309129e83d4bSgd78059 (void) snprintf(tag, sizeof (tag), "mxfe");
309229e83d4bSgd78059 }
309329e83d4bSgd78059
309429e83d4bSgd78059 (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", tag,
309529e83d4bSgd78059 func, fmt);
309629e83d4bSgd78059
309729e83d4bSgd78059 vcmn_err(CE_CONT, buf, ap);
309829e83d4bSgd78059 }
309929e83d4bSgd78059 va_end(ap);
310029e83d4bSgd78059 }
310129e83d4bSgd78059
310229e83d4bSgd78059 #endif
3103