2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1998 The NetBSD Foundation, Inc.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Frank van der Linden.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/varargs.h>
36 #include <sys/types.h>
37 #include <sys/modctl.h>
39 #include <sys/devops.h>
40 #include <sys/stream.h>
41 #include <sys/strsun.h>
42 #include <sys/cmn_err.h>
43 #include <sys/ethernet.h>
48 #include <sys/miiregs.h>
49 #include <sys/mac_ether.h>
50 #include <sys/mac_provider.h>
51 #include <sys/strsubr.h>
52 #include <sys/pattr.h>
55 #include <sys/sunddi.h>
61 static boolean_t
elxl_add_intr(elxl_t
*);
62 static void elxl_probe_media(elxl_t
*);
63 static void elxl_set_rxfilter(elxl_t
*);
64 static void elxl_set_media(elxl_t
*);
65 static uint16_t elxl_read_eeprom(elxl_t
*, int);
66 static void elxl_init(elxl_t
*);
67 static void elxl_stop(elxl_t
*);
68 static void elxl_reset(elxl_t
*);
69 static void elxl_getstats(elxl_t
*);
71 static int elxl_eeprom_busy(elxl_t
*);
73 static void elxl_setup_tx(elxl_t
*);
75 static uint16_t elxl_mii_read(void *, uint8_t, uint8_t);
76 static void elxl_mii_write(void *, uint8_t, uint8_t, uint16_t);
77 static void elxl_mii_notify(void *, link_state_t
);
79 static int elxl_m_stat(void *, uint_t
, uint64_t *);
80 static int elxl_m_start(void *);
81 static void elxl_m_stop(void *);
82 static mblk_t
*elxl_m_tx(void *, mblk_t
*);
83 static int elxl_m_promisc(void *, boolean_t
);
84 static int elxl_m_multicst(void *, boolean_t
, const uint8_t *);
85 static int elxl_m_unicst(void *, const uint8_t *);
86 static int elxl_m_getprop(void *, const char *, mac_prop_id_t
, uint_t
,
88 static int elxl_m_setprop(void *, const char *, mac_prop_id_t
, uint_t
,
90 static void elxl_m_propinfo(void *, const char *, mac_prop_id_t
,
91 mac_prop_info_handle_t
);
92 static boolean_t
elxl_m_getcapab(void *, mac_capab_t cap
, void *);
93 static uint_t
elxl_intr(caddr_t
, caddr_t
);
94 static void elxl_error(elxl_t
*, char *, ...);
95 static void elxl_linkcheck(void *);
96 static int elxl_attach(dev_info_t
*);
97 static void elxl_detach(elxl_t
*);
98 static void elxl_suspend(elxl_t
*);
99 static void elxl_resume(dev_info_t
*);
100 static int elxl_ddi_attach(dev_info_t
*, ddi_attach_cmd_t
);
101 static int elxl_ddi_detach(dev_info_t
*, ddi_detach_cmd_t
);
102 static int elxl_ddi_quiesce(dev_info_t
*);
104 static ddi_device_acc_attr_t ex_dev_acc_attr
= {
106 DDI_STRUCTURE_LE_ACC
,
110 static ddi_device_acc_attr_t ex_buf_acc_attr
= {
113 DDI_STORECACHING_OK_ACC
117 * In theory buffers can have more flexible DMA attributes, but since
118 * we're just using a preallocated region with bcopy, there is little
119 * reason to allow for rougher alignment. (Further, the 8-byte
120 * alignment can allow for more efficient bcopy and similar operations
123 static ddi_dma_attr_t ex_dma_attr
= {
124 DMA_ATTR_V0
, /* dma_attr_version */
125 0, /* dma_attr_addr_lo */
126 0xFFFFFFFFU
, /* dma_attr_addr_hi */
127 0x00FFFFFFU
, /* dma_attr_count_max */
128 8, /* dma_attr_align */
129 0x7F, /* dma_attr_burstsizes */
130 1, /* dma_attr_minxfer */
131 0xFFFFFFFFU
, /* dma_attr_maxxfer */
132 0xFFFFFFFFU
, /* dma_attr_seg */
133 1, /* dma_attr_sgllen */
134 1, /* dma_attr_granular */
135 0 /* dma_attr_flags */
138 static uint8_t ex_broadcast
[6] = {
139 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
143 * Structure to map media-present bits in boards to ifmedia codes and
144 * printable media names. Used for table-driven ifmedia initialization.
146 typedef struct ex_media
{
147 int exm_mpbit
; /* media present bit */
148 int exm_xcvr
; /* XCVR_SEL_* constant */
152 * Media table for 3c90x chips. Note that chips with MII have no
153 * `native' media. This is sorted in "reverse preference".
155 static ex_media_t ex_native_media
[] = {
156 { MEDIAOPT_AUI
, XCVR_SEL_AUI
},
157 { MEDIAOPT_BNC
, XCVR_SEL_BNC
},
158 { MEDIAOPT_10T
, XCVR_SEL_10T
},
159 { MEDIAOPT_100TX
, XCVR_SEL_AUTO
}, /* only 90XB */
160 { MEDIAOPT_100FX
, XCVR_SEL_100FX
},
161 { MEDIAOPT_MII
, XCVR_SEL_MII
},
162 { MEDIAOPT_100T4
, XCVR_SEL_MII
},
168 * NB: There are lots of other models that *could* be supported.
169 * Specifically there are cardbus and miniPCI variants that could be
170 * easily added here, but they require special hacks and I have no
171 * access to the hardware required to verify them. Especially they
172 * seem to require some extra work in another register window, and I
173 * have no supporting documentation.
175 static const struct ex_product
{
176 uint16_t epp_prodid
; /* PCI product ID */
177 const char *epp_name
; /* device name */
178 unsigned epp_flags
; /* initial softc flags */
180 { 0x4500, "3c450-TX", 0 },
181 { 0x7646, "3cSOHO100-TX", 0 },
182 { 0x9000, "3c900-TPO", 0 },
183 { 0x9001, "3c900-COMBO", 0 },
184 { 0x9004, "3c900B-TPO", 0 },
185 { 0x9005, "3c900B-COMBO", 0 },
186 { 0x9006, "3c900B-TPC", 0 },
187 { 0x900a, "3c900B-FL", 0 },
188 { 0x9050, "3c905-TX", 0 },
189 { 0x9051, "3c905-T4", 0 },
190 { 0x9055, "3c905B-TX", 0 },
191 { 0x9056, "3c905B-T4", 0 },
192 { 0x9058, "3c905B-COMBO", 0 },
193 { 0x905a, "3c905B-FX", 0 },
194 { 0x9200, "3c905C-TX", 0 },
195 { 0x9201, "3c920B-EMB", 0 },
196 { 0x9202, "3c920B-EMB-WNM", 0 },
197 { 0x9800, "3c980", 0 },
198 { 0x9805, "3c980C-TXM", 0 },
203 static char *ex_priv_prop
[] = {
209 static mii_ops_t ex_mii_ops
= {
216 static mac_callbacks_t elxl_m_callbacks
= {
217 MC_GETCAPAB
| MC_PROPERTIES
,
238 DDI_DEFINE_STREAM_OPS(ex_devops
, nulldev
, nulldev
,
239 elxl_ddi_attach
, elxl_ddi_detach
,
240 nodev
, NULL
, D_MP
, NULL
, elxl_ddi_quiesce
);
243 * Module linkage information.
246 static struct modldrv ex_modldrv
= {
247 &mod_driverops
, /* drv_modops */
248 "3Com EtherLink XL", /* drv_linkinfo */
249 &ex_devops
/* drv_dev_ops */
252 static struct modlinkage ex_modlinkage
= {
253 MODREV_1
, /* ml_rev */
254 { &ex_modldrv
, NULL
} /* ml_linkage */
261 mac_init_ops(&ex_devops
, "elxl");
262 if ((rv
= mod_install(&ex_modlinkage
)) != DDI_SUCCESS
) {
263 mac_fini_ops(&ex_devops
);
272 if ((rv
= mod_remove(&ex_modlinkage
)) == DDI_SUCCESS
) {
273 mac_fini_ops(&ex_devops
);
279 _info(struct modinfo
*modinfop
)
281 return (mod_info(&ex_modlinkage
, modinfop
));
285 ex_free_ring(ex_ring_t
*r
)
287 for (int i
= 0; i
< r
->r_count
; i
++) {
288 ex_desc_t
*ed
= &r
->r_desc
[i
];
290 (void) ddi_dma_unbind_handle(ed
->ed_dmah
);
292 ddi_dma_mem_free(&ed
->ed_acch
);
294 ddi_dma_free_handle(&ed
->ed_dmah
);
298 (void) ddi_dma_unbind_handle(r
->r_dmah
);
300 ddi_dma_mem_free(&r
->r_acch
);
302 ddi_dma_free_handle(&r
->r_dmah
);
304 kmem_free(r
->r_desc
, sizeof (ex_desc_t
) * r
->r_count
);
309 elxl_reset_ring(ex_ring_t
*r
, uint_t dir
)
314 if (dir
== DDI_DMA_WRITE
) {
315 /* transmit ring, not linked yet */
316 for (int i
= 0; i
< r
->r_count
; i
++) {
319 PUT_PD(r
, pd
->pd_link
, 0);
320 PUT_PD(r
, pd
->pd_fsh
, 0);
321 PUT_PD(r
, pd
->pd_len
, EX_FR_LAST
);
322 PUT_PD(r
, pd
->pd_addr
, ed
->ed_bufaddr
);
326 r
->r_avail
= r
->r_count
;
328 /* receive is linked into a list */
329 for (int i
= 0; i
< r
->r_count
; i
++) {
332 PUT_PD(r
, pd
->pd_link
, ed
->ed_next
->ed_descaddr
);
333 PUT_PD(r
, pd
->pd_status
, 0);
334 PUT_PD(r
, pd
->pd_len
, EX_BUFSZ
| EX_FR_LAST
);
335 PUT_PD(r
, pd
->pd_addr
, ed
->ed_bufaddr
);
337 r
->r_head
= &r
->r_desc
[0];
341 (void) ddi_dma_sync(r
->r_dmah
, 0, 0, DDI_DMA_SYNC_FORDEV
);
345 ex_alloc_ring(elxl_t
*sc
, int count
, ex_ring_t
*r
, uint_t dir
)
347 dev_info_t
*dip
= sc
->ex_dip
;
351 ddi_dma_cookie_t dmac
;
355 r
->r_desc
= kmem_zalloc(sizeof (ex_desc_t
) * count
, KM_SLEEP
);
357 rv
= ddi_dma_alloc_handle(dip
, &ex_dma_attr
, DDI_DMA_DONTWAIT
,
359 if (rv
!= DDI_SUCCESS
) {
360 elxl_error(sc
, "unable to allocate descriptor dma handle");
364 rv
= ddi_dma_mem_alloc(r
->r_dmah
, count
* sizeof (struct ex_pd
),
365 &ex_dev_acc_attr
, DDI_DMA_CONSISTENT
, DDI_DMA_DONTWAIT
, NULL
,
366 (caddr_t
*)&r
->r_pd
, &len
, &r
->r_acch
);
367 if (rv
!= DDI_SUCCESS
) {
368 elxl_error(sc
, "unable to allocate descriptor memory");
373 rv
= ddi_dma_addr_bind_handle(r
->r_dmah
, NULL
,
374 (caddr_t
)r
->r_pd
, len
, DDI_DMA_RDWR
| DDI_DMA_CONSISTENT
,
375 DDI_DMA_DONTWAIT
, NULL
, &dmac
, &ndmac
);
376 if (rv
!= DDI_DMA_MAPPED
) {
377 elxl_error(sc
, "unable to map descriptor memory");
380 r
->r_paddr
= dmac
.dmac_address
;
382 for (i
= 0; i
< count
; i
++) {
383 ex_desc_t
*ed
= &r
->r_desc
[i
];
384 ex_pd_t
*pd
= &r
->r_pd
[i
];
387 ed
->ed_off
= (i
* sizeof (ex_pd_t
));
388 ed
->ed_descaddr
= r
->r_paddr
+ (i
* sizeof (ex_pd_t
));
390 /* Link the high level descriptors into a ring. */
391 ed
->ed_next
= &r
->r_desc
[(i
+ 1) % count
];
392 ed
->ed_next
->ed_prev
= ed
;
394 rv
= ddi_dma_alloc_handle(dip
, &ex_dma_attr
,
395 DDI_DMA_DONTWAIT
, NULL
, &ed
->ed_dmah
);
397 elxl_error(sc
, "can't allocate buf dma handle");
400 rv
= ddi_dma_mem_alloc(ed
->ed_dmah
, EX_BUFSZ
, &ex_buf_acc_attr
,
401 DDI_DMA_STREAMING
, DDI_DMA_DONTWAIT
, NULL
, &ed
->ed_buf
,
403 if (rv
!= DDI_SUCCESS
) {
404 elxl_error(sc
, "unable to allocate buf memory");
407 bzero(ed
->ed_buf
, len
);
409 rv
= ddi_dma_addr_bind_handle(ed
->ed_dmah
, NULL
,
410 ed
->ed_buf
, len
, dir
| DDI_DMA_STREAMING
,
411 DDI_DMA_DONTWAIT
, NULL
, &dmac
, &ndmac
);
412 if (rv
!= DDI_DMA_MAPPED
) {
413 elxl_error(sc
, "unable to map buf memory");
416 ed
->ed_bufaddr
= dmac
.dmac_address
;
419 elxl_reset_ring(r
, dir
);
425 elxl_add_intr(elxl_t
*sc
)
435 rv
= ddi_intr_alloc(dip
, &sc
->ex_intrh
, DDI_INTR_TYPE_FIXED
,
436 0, 1, &actual
, DDI_INTR_ALLOC_STRICT
);
437 if ((rv
!= DDI_SUCCESS
) || (actual
!= 1)) {
438 elxl_error(sc
, "Unable to allocate interrupt, %d, count %d",
443 if (ddi_intr_get_pri(sc
->ex_intrh
, &ipri
) != DDI_SUCCESS
) {
444 elxl_error(sc
, "Unable to get interrupt priority");
448 if (ddi_intr_add_handler(sc
->ex_intrh
, elxl_intr
, sc
, NULL
) !=
450 elxl_error(sc
, "Can't add interrupt handler");
451 (void) ddi_intr_free(sc
->ex_intrh
);
455 mutex_init(&sc
->ex_intrlock
, NULL
, MUTEX_DRIVER
, DDI_INTR_PRI(ipri
));
456 mutex_init(&sc
->ex_txlock
, NULL
, MUTEX_DRIVER
, DDI_INTR_PRI(ipri
));
462 elxl_attach(dev_info_t
*dip
)
465 mac_register_t
*macp
;
471 sc
= kmem_zalloc(sizeof (*sc
), KM_SLEEP
);
472 ddi_set_driver_private(dip
, sc
);
475 if (pci_config_setup(dip
, &sc
->ex_pcih
) != DDI_SUCCESS
) {
476 elxl_error(sc
, "unable to setup PCI config handle");
479 venid
= pci_config_get16(sc
->ex_pcih
, PCI_CONF_VENID
);
480 devid
= pci_config_get16(sc
->ex_pcih
, PCI_CONF_DEVID
);
482 if (venid
!= 0x10b7) {
483 /* Not a 3Com part! */
484 elxl_error(sc
, "Unsupported vendor id (0x%x)", venid
);
487 for (i
= 0; ex_products
[i
].epp_name
; i
++) {
488 if (devid
== ex_products
[i
].epp_prodid
) {
489 cmn_err(CE_CONT
, "?%s%d: 3Com %s",
490 ddi_driver_name(dip
),
491 ddi_get_instance(dip
),
492 ex_products
[i
].epp_name
);
493 sc
->ex_conf
= ex_products
[i
].epp_flags
;
497 if (ex_products
[i
].epp_name
== NULL
) {
498 /* Not a produce we know how to support */
499 elxl_error(sc
, "Unsupported device id (0x%x)", devid
);
500 elxl_error(sc
, "Driver may or may not function.");
503 pci_config_put16(sc
->ex_pcih
, PCI_CONF_COMM
,
504 pci_config_get16(sc
->ex_pcih
, PCI_CONF_COMM
) |
505 PCI_COMM_IO
| PCI_COMM_MAE
| PCI_COMM_ME
);
507 if (ddi_regs_map_setup(dip
, 1, &sc
->ex_regsva
, 0, 0, &ex_dev_acc_attr
,
508 &sc
->ex_regsh
) != DDI_SUCCESS
) {
509 elxl_error(sc
, "Unable to map device registers");
513 if (!elxl_add_intr(sc
)) {
519 val
= elxl_read_eeprom(sc
, EE_OEM_ADDR_0
);
520 sc
->ex_factaddr
[0] = val
>> 8;
521 sc
->ex_factaddr
[1] = val
& 0xff;
522 val
= elxl_read_eeprom(sc
, EE_OEM_ADDR_1
);
523 sc
->ex_factaddr
[2] = val
>> 8;
524 sc
->ex_factaddr
[3] = val
& 0xff;
525 val
= elxl_read_eeprom(sc
, EE_OEM_ADDR_2
);
526 sc
->ex_factaddr
[4] = val
>> 8;
527 sc
->ex_factaddr
[5] = val
& 0xff;
528 bcopy(sc
->ex_factaddr
, sc
->ex_curraddr
, 6);
530 sc
->ex_capab
= elxl_read_eeprom(sc
, EE_CAPABILITIES
);
533 * Is this a 90XB? If bit 2 (supportsLargePackets) is set, or
534 * bit (supportsNoTxLength) is clear, then its a 90X.
535 * Otherwise its a 90XB.
537 if ((sc
->ex_capab
& (1 << 2)) || !(sc
->ex_capab
& (1 << 9))) {
538 sc
->ex_conf
&= ~CONF_90XB
;
540 sc
->ex_conf
|= CONF_90XB
;
543 if (!ex_alloc_ring(sc
, EX_NRX
, &sc
->ex_rxring
, DDI_DMA_READ
)) {
547 if (!ex_alloc_ring(sc
, EX_NTX
, &sc
->ex_txring
, DDI_DMA_WRITE
)) {
551 elxl_probe_media(sc
);
554 * The probe may have indicated MII!
556 if (sc
->ex_mediaopt
& (MEDIAOPT_MII
| MEDIAOPT_100TX
)) {
557 sc
->ex_miih
= mii_alloc(sc
, sc
->ex_dip
, &ex_mii_ops
);
558 if (sc
->ex_miih
== NULL
) {
562 * Note: The 90XB models can in theory support pause,
563 * but we're not enabling now due to lack of units for
564 * testing with. If this is changed, make sure to
565 * update the code in elxl_mii_notify to set the flow
566 * control field in the W3_MAC_CONTROL register.
568 mii_set_pauseable(sc
->ex_miih
, B_FALSE
, B_FALSE
);
570 if ((macp
= mac_alloc(MAC_VERSION
)) == NULL
) {
571 elxl_error(sc
, "MAC register allocation failed");
574 macp
->m_type_ident
= MAC_PLUGIN_IDENT_ETHER
;
577 macp
->m_src_addr
= sc
->ex_curraddr
;
578 macp
->m_callbacks
= &elxl_m_callbacks
;
580 macp
->m_max_sdu
= ETHERMTU
;
581 macp
->m_margin
= VLAN_TAGSZ
;
582 macp
->m_priv_props
= ex_priv_prop
;
584 (void) ddi_intr_enable(sc
->ex_intrh
);
586 if (mac_register(macp
, &sc
->ex_mach
) == DDI_SUCCESS
) {
589 * Note: we don't want to start link checking
590 * until *after* we have added the MAC handle.
592 if (sc
->ex_mediaopt
&
593 (MEDIAOPT_MASK
& ~(MEDIAOPT_MII
| MEDIAOPT_100TX
))) {
595 /* Check non-MII link state once per second. */
597 ddi_periodic_add(elxl_linkcheck
, sc
, 10000000, 0);
601 return (DDI_SUCCESS
);
608 return (DDI_FAILURE
);
612 * Find the media present on non-MII chips, and select the one to use.
615 elxl_probe_media(elxl_t
*sc
)
619 uint32_t default_media
;
620 uint16_t media_options
;
623 config
= GET32(W3_INTERNAL_CONFIG
);
624 media_options
= GET16(W3_MEDIAOPT
);
627 * We modify the media_options field so that we have a
628 * consistent view of the media available, without worrying
629 * about the version of ASIC, etc.
633 * 100BASE-TX is handled differently on 90XB from 90X. Older
634 * parts use the external MII to provide this support.
636 if (sc
->ex_conf
& CONF_90XB
) {
637 if (media_options
& MEDIAOPT_100TX
) {
639 * 3Com advises that we should only ever use the
640 * auto mode. Notably, it seems that there should
641 * never be a 90XB board with the MEDIAOPT_10T bit set
642 * without this bit. If it happens, the driver will
643 * run in compatible 10BASE-T only mode.
645 media_options
&= ~MEDIAOPT_10T
;
648 if (media_options
& MEDIAOPT_100TX
) {
650 * If this occurs, we really want to use it like
651 * an MII device. Generally in this situation we
652 * want to use the MII exclusively, and there ought
653 * not be a 10bT transceiver.
655 media_options
|= MEDIAOPT_MII
;
656 media_options
&= ~MEDIAOPT_100TX
;
657 media_options
&= ~MEDIAOPT_10T
;
660 * Additionally, some of these devices map all
661 * internal PHY register at *every* address, not
662 * just the "allowed" address 24.
664 sc
->ex_conf
|= CONF_INTPHY
;
667 * Early versions didn't have 10FL models, and used this
668 * bit for something else (VCO).
670 media_options
&= ~MEDIAOPT_10FL
;
672 if (media_options
& MEDIAOPT_100T4
) {
673 /* 100BASE-T4 units all use the MII bus. */
674 media_options
|= MEDIAOPT_MII
;
675 media_options
&= ~MEDIAOPT_100T4
;
678 /* Save our media options. */
679 sc
->ex_mediaopt
= media_options
;
681 #define APPEND_MEDIA(str, bit, name) \
682 if (media_options & (bit)) { \
683 (void) strlcat(str, *str ? "," : "", sizeof (str)); \
684 (void) strlcat(str, name, sizeof (str)); \
687 APPEND_MEDIA(sc
->ex_medias
, (MEDIAOPT_MII
|MEDIAOPT_100TX
), "mii");
688 APPEND_MEDIA(sc
->ex_medias
, MEDIAOPT_10T
, "tp-hdx,tp-fdx");
689 APPEND_MEDIA(sc
->ex_medias
, MEDIAOPT_100FX
, "fx-hdx,fx-fdx");
690 APPEND_MEDIA(sc
->ex_medias
, MEDIAOPT_BNC
, "bnc");
691 APPEND_MEDIA(sc
->ex_medias
, MEDIAOPT_AUI
, "aui");
692 APPEND_MEDIA(sc
->ex_medias
, MEDIAOPT_10FL
, "fl-hdx,fl-fdx");
694 if (config
& XCVR_SEL_100TX
) {
695 /* Only found on 90XB. Don't use this, use AUTO instead! */
696 config
|= XCVR_SEL_AUTO
;
697 config
&= ~XCVR_SEL_100TX
;
700 default_media
= (config
& XCVR_SEL_MASK
);
702 /* Sanity check that there are any media! */
703 if ((media_options
& MEDIAOPT_MASK
) == 0) {
705 "No media present? Attempting to use default.");
707 * This "default" may be non-sensical. At worst it should
708 * cause a busted link.
710 sc
->ex_xcvr
= default_media
;
713 for (exm
= ex_native_media
; exm
->exm_mpbit
!= 0; exm
++) {
714 if (media_options
& exm
->exm_mpbit
) {
715 if (exm
->exm_xcvr
== default_media
) {
716 /* preferred default is present, just use it */
717 sc
->ex_xcvr
= default_media
;
721 sc
->ex_xcvr
= exm
->exm_xcvr
;
722 /* but keep trying for other more preferred options */
728 * Setup transmitter parameters.
731 elxl_setup_tx(elxl_t
*sc
)
734 * Disable reclaim threshold for 90xB, set free threshold to
735 * 6 * 256 = 1536 for 90x.
737 if (sc
->ex_conf
& CONF_90XB
)
738 PUT_CMD(CMD_SET_TXRECLAIM
| 255);
740 PUT8(REG_TXFREETHRESH
, 6);
743 * We've seen underflows at the root cause of NIC hangs on
744 * older cards. Use a store-and-forward model to prevent that.
746 PUT_CMD(CMD_SET_TXSTART
| EX_BUFSZ
>> 2);
753 elxl_init(elxl_t
*sc
)
755 if (sc
->ex_suspended
)
761 PUT_CMD(CMD_RX_RESET
);
763 PUT_CMD(CMD_TX_RESET
);
766 /* Load Tx parameters. */
769 PUT32(REG_DMACTRL
, GET32(REG_DMACTRL
) | DMACTRL_UPRXEAREN
);
771 PUT_CMD(CMD_IND_ENABLE
| INT_WATCHED
);
772 PUT_CMD(CMD_INT_ENABLE
| INT_WATCHED
);
774 PUT_CMD(CMD_INT_ACK
| 0xff);
777 elxl_set_rxfilter(sc
);
779 /* Configure for VLAN tag sizing. */
781 if (sc
->ex_conf
& CONF_90XB
) {
782 PUT16(W3_MAX_PKT_SIZE
, EX_BUFSZ
);
784 PUT16(W3_MAC_CONTROL
, GET16(W3_MAC_CONTROL
) |
785 MAC_CONTROL_ALLOW_LARGE
);
788 PUT_CMD(CMD_SET_RXEARLY
| (EX_BUFSZ
>> 2));
790 PUT_CMD(CMD_STATS_ENABLE
);
791 PUT_CMD(CMD_TX_ENABLE
);
792 PUT32(REG_UPLISTPTR
, sc
->ex_rxring
.r_paddr
);
793 PUT_CMD(CMD_RX_ENABLE
);
794 PUT_CMD(CMD_UP_UNSTALL
);
798 * Set multicast receive filter. Also take care of promiscuous mode.
799 * Note that *some* of this hardware is fully capable of either a 256
800 * or 64 bit multicast hash. However, we can't determine what the
801 * size of the hash table is easily, and so we are expected to be able
802 * to resubmit the entire list of addresses each time. This puts an
803 * onerous burden on the driver to maintain its list of multicast
804 * addresses. Since multicast stuff is usually not that performance
805 * sensitive, and since we don't usually have much of it, we are just
806 * going to skip it. We allow the upper layers to filter it, as
807 * needed, by setting the all-multicast bit if the hardware can do it.
808 * This also reduces our test burden.
811 elxl_set_rxfilter(elxl_t
*sc
)
813 uint16_t mask
= FILTER_UNICAST
| FILTER_ALLBCAST
;
815 if (sc
->ex_suspended
)
819 * Set the station address and clear the station mask. The latter
820 * is needed for 90x cards, 0 is the default for 90xB cards.
823 for (int i
= 0; i
< ETHERADDRL
; i
++) {
824 PUT8(W2_STATION_ADDRESS
+ i
, sc
->ex_curraddr
[i
]);
825 PUT8(W2_STATION_MASK
+ i
, 0);
828 if (sc
->ex_mccount
) {
829 mask
|= FILTER_ALLMULTI
;
831 if (sc
->ex_promisc
) {
832 mask
|= FILTER_PROMISC
;
834 PUT_CMD(CMD_SET_FILTER
| mask
);
838 elxl_set_media(elxl_t
*sc
)
843 PUT16(W4_MEDIASTAT
, 0);
844 PUT_CMD(CMD_BNC_DISABLE
);
848 * Now turn on the selected media/transceiver.
850 switch (sc
->ex_xcvr
) {
852 sc
->ex_mii_active
= B_FALSE
;
854 MEDIASTAT_JABGUARD_EN
| MEDIASTAT_LINKBEAT_EN
);
859 sc
->ex_mii_active
= B_FALSE
;
860 PUT_CMD(CMD_BNC_ENABLE
);
865 sc
->ex_mii_active
= B_FALSE
; /* Is this really true? */
866 PUT16(W4_MEDIASTAT
, MEDIASTAT_LINKBEAT_EN
);
871 sc
->ex_mii_active
= B_FALSE
;
872 PUT16(W4_MEDIASTAT
, MEDIASTAT_SQE_EN
);
879 * This is due to paranoia. If a card claims
880 * to default to MII, but doesn't have it set in
881 * media options, then we don't want to leave
882 * the MII active or we'll have problems derferencing
886 sc
->ex_mii_active
= B_TRUE
;
888 sc
->ex_mii_active
= B_FALSE
;
893 sc
->ex_mii_active
= B_FALSE
;
894 elxl_error(sc
, "Impossible media setting!");
899 configreg
= GET32(W3_INTERNAL_CONFIG
);
901 configreg
&= ~(XCVR_SEL_MASK
);
902 configreg
|= (sc
->ex_xcvr
);
904 PUT32(W3_INTERNAL_CONFIG
, configreg
);
907 * If we're not using MII, force the full-duplex setting. MII
908 * based modes handle the full-duplex setting via the MII
911 if (!sc
->ex_mii_active
) {
913 mctl
= GET16(W3_MAC_CONTROL
);
915 mctl
|= MAC_CONTROL_FDX
;
917 mctl
&= ~MAC_CONTROL_FDX
;
919 PUT16(W3_MAC_CONTROL
, mctl
);
924 * Get currently-selected media from card.
925 * (if_media callback, may be called before interface is brought up).
928 elxl_linkcheck(void *arg
)
934 mutex_enter(&sc
->ex_txlock
);
935 if (sc
->ex_mii_active
) {
936 mutex_exit(&sc
->ex_txlock
);
939 if (sc
->ex_running
&& !sc
->ex_suspended
) {
940 switch (sc
->ex_xcvr
) {
942 /* these media we can detect link on */
944 stat
= GET16(W4_MEDIASTAT
);
945 if (stat
& MEDIASTAT_LINKDETECT
) {
946 sc
->ex_link
= LINK_STATE_UP
;
947 sc
->ex_speed
= 100000000;
949 sc
->ex_link
= LINK_STATE_DOWN
;
955 /* these media we can detect link on */
957 stat
= GET16(W4_MEDIASTAT
);
958 if (stat
& MEDIASTAT_LINKDETECT
) {
959 sc
->ex_link
= LINK_STATE_UP
;
960 sc
->ex_speed
= 10000000;
962 sc
->ex_link
= LINK_STATE_DOWN
;
971 * For these we don't really know the answer,
972 * but if we lie then at least it won't cause
973 * ifconfig to turn off the RUNNING flag.
974 * This is necessary because we might
975 * transition from LINK_STATE_DOWN when
978 sc
->ex_speed
= 10000000;
979 sc
->ex_link
= LINK_STATE_UP
;
983 sc
->ex_duplex
= GET16(W3_MAC_CONTROL
) & MAC_CONTROL_FDX
?
984 LINK_DUPLEX_FULL
: LINK_DUPLEX_HALF
;
987 sc
->ex_duplex
= LINK_DUPLEX_UNKNOWN
;
988 sc
->ex_link
= LINK_STATE_UNKNOWN
;
991 mutex_exit(&sc
->ex_txlock
);
993 mac_link_update(sc
->ex_mach
, link
);
997 elxl_m_promisc(void *arg
, boolean_t on
)
1001 mutex_enter(&sc
->ex_intrlock
);
1002 mutex_enter(&sc
->ex_txlock
);
1003 sc
->ex_promisc
= on
;
1004 elxl_set_rxfilter(sc
);
1005 mutex_exit(&sc
->ex_txlock
);
1006 mutex_exit(&sc
->ex_intrlock
);
1011 elxl_m_multicst(void *arg
, boolean_t add
, const uint8_t *addr
)
1015 _NOTE(ARGUNUSED(addr
));
1017 mutex_enter(&sc
->ex_intrlock
);
1018 mutex_enter(&sc
->ex_txlock
);
1021 if (sc
->ex_mccount
== 1) {
1022 elxl_set_rxfilter(sc
);
1026 if (sc
->ex_mccount
== 0) {
1027 elxl_set_rxfilter(sc
);
1030 mutex_exit(&sc
->ex_txlock
);
1031 mutex_exit(&sc
->ex_intrlock
);
1036 elxl_m_unicst(void *arg
, const uint8_t *addr
)
1040 mutex_enter(&sc
->ex_intrlock
);
1041 mutex_enter(&sc
->ex_txlock
);
1042 bcopy(addr
, sc
->ex_curraddr
, ETHERADDRL
);
1043 elxl_set_rxfilter(sc
);
1044 mutex_exit(&sc
->ex_txlock
);
1045 mutex_exit(&sc
->ex_intrlock
);
1051 elxl_m_tx(void *arg
, mblk_t
*mp
)
1062 boolean_t reenable
= B_FALSE
;
1063 boolean_t reset
= B_FALSE
;
1067 mutex_enter(&sc
->ex_txlock
);
1068 if (sc
->ex_suspended
) {
1069 while (mp
!= NULL
) {
1075 mutex_exit(&sc
->ex_txlock
);
1079 for (int limit
= (EX_NTX
* 2); limit
; limit
--) {
1080 uint8_t stat
= GET8(REG_TXSTATUS
);
1081 if ((stat
& TXSTATUS_COMPLETE
) == 0) {
1084 if (stat
& TXSTATUS_MAXCOLLISIONS
) {
1088 if ((stat
& TXSTATUS_ERRS
) != 0) {
1090 if (stat
& TXSTATUS_JABBER
) {
1093 if (stat
& TXSTATUS_RECLAIM_ERR
) {
1096 if (stat
& TXSTATUS_UNDERRUN
) {
1100 PUT8(REG_TXSTATUS
, 0);
1103 if (reset
|| reenable
) {
1104 paddr
= GET32(REG_DNLISTPTR
);
1107 PUT_CMD(CMD_TX_RESET
);
1111 PUT_CMD(CMD_TX_ENABLE
);
1113 PUT32(REG_DNLISTPTR
, paddr
);
1117 /* first reclaim any free descriptors */
1118 while (r
->r_avail
< r
->r_count
) {
1120 paddr
= GET32(REG_DNLISTPTR
);
1122 if (paddr
== txd
->ed_descaddr
) {
1123 /* still processing this one, we're done */
1127 /* done processing the entire list! */
1130 r
->r_avail
= r
->r_count
;
1134 r
->r_head
= txd
->ed_next
;
1137 if ((r
->r_avail
< r
->r_count
) && (GET32(REG_DNLISTPTR
) != 0)) {
1138 PUT_CMD(CMD_DN_STALL
);
1146 * If there is already a tx list, select the next desc on the list.
1147 * Otherwise, just pick the first descriptor.
1149 txd
= tail
? tail
->ed_next
: &r
->r_desc
[0];
1151 while ((mp
!= NULL
) && (r
->r_avail
)) {
1156 if (len
> (ETHERMAX
+ VLAN_TAGSZ
)) {
1164 if ((sc
->ex_conf
& CONF_90XB
) != 0) {
1166 hcksum_retrieve(mp
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1168 if (pflags
& HCK_IPV4_HDRCKSUM
) {
1169 cflags
|= EX_DPD_IPCKSUM
;
1171 if (pflags
& HCK_FULLCKSUM
) {
1172 cflags
|= (EX_DPD_TCPCKSUM
| EX_DPD_UDPCKSUM
);
1176 /* Mark this descriptor is in use. We're committed now. */
1177 mcopymsg(mp
, txd
->ed_buf
); /* frees the mblk! */
1181 /* Accounting stuff. */
1183 sc
->ex_obytes
+= len
;
1184 if (txd
->ed_buf
[0] & 0x1) {
1185 if (bcmp(txd
->ed_buf
, ex_broadcast
, ETHERADDRL
) != 0) {
1196 * Zero pad the frame if its too short. This
1197 * also avoids a checksum offload bug.
1200 bzero(txd
->ed_buf
+ len
, ETHERMIN
- len
);
1205 * If this our first packet so far, record the head
1208 if (first
== NULL
) {
1212 (void) ddi_dma_sync(txd
->ed_dmah
, 0, 0, DDI_DMA_SYNC_FORDEV
);
1214 PUT_PD(r
, pd
->pd_link
, 0);
1215 PUT_PD(r
, pd
->pd_fsh
, len
| cflags
);
1216 PUT_PD(r
, pd
->pd_addr
, txd
->ed_bufaddr
);
1217 PUT_PD(r
, pd
->pd_len
, len
| EX_FR_LAST
);
1220 * Write the link into the previous descriptor. Note that
1221 * if this is the first packet (so no previous queued), this
1222 * will be benign because the previous descriptor won't be
1223 * on any tx list. (Furthermore, we'll clear its link field
1224 * when we do later use it.)
1226 PUT_PD(r
, txd
->ed_prev
->ed_pd
->pd_link
, txd
->ed_descaddr
);
1230 * Are we submitting any packets?
1232 if (first
!= NULL
) {
1233 /* Interrupt on the last packet. */
1234 PUT_PD(r
, pd
->pd_fsh
, len
| cflags
| EX_DPD_DNIND
);
1237 /* No packets pending, so its a new list head! */
1241 /* We've added frames, so don't interrupt mid-list. */
1242 PUT_PD(r
, pd
->pd_fsh
,
1243 GET_PD(r
, pd
->pd_fsh
) & ~(EX_DPD_DNIND
));
1245 /* Record the last descriptor. */
1248 /* flush the entire ring - we're stopped so its safe */
1249 (void) ddi_dma_sync(r
->r_dmah
, 0, 0, DDI_DMA_SYNC_FORDEV
);
1252 /* Restart transmitter. */
1253 if (sc
->ex_txring
.r_head
) {
1254 PUT32(REG_DNLISTPTR
, sc
->ex_txring
.r_head
->ed_descaddr
);
1256 PUT_CMD(CMD_DN_UNSTALL
);
1258 mutex_exit(&sc
->ex_txlock
);
1264 elxl_recv(elxl_t
*sc
, ex_desc_t
*rxd
, uint32_t stat
)
1269 len
= stat
& EX_UPD_PKTLENMASK
;
1270 if (stat
& (EX_UPD_ERR_VLAN
| EX_UPD_OVERFLOW
)) {
1271 if (stat
& EX_UPD_RUNT
) {
1274 if (stat
& EX_UPD_OVERRUN
) {
1277 if (stat
& EX_UPD_CRCERR
) {
1280 if (stat
& EX_UPD_ALIGNERR
) {
1283 if (stat
& EX_UPD_OVERFLOW
) {
1288 if (len
< sizeof (struct ether_header
)) {
1292 if (len
> (ETHERMAX
+ VLAN_TAGSZ
)) {
1293 /* Allow four bytes for the VLAN header */
1297 if ((mp
= allocb(len
+ 14, BPRI_HI
)) == NULL
) {
1298 sc
->ex_allocbfail
++;
1302 (void) ddi_dma_sync(rxd
->ed_dmah
, 0, 0, DDI_DMA_SYNC_FORKERNEL
);
1304 mp
->b_wptr
= mp
->b_rptr
+ len
;
1305 bcopy(rxd
->ed_buf
, mp
->b_rptr
, len
);
1308 sc
->ex_ibytes
+= len
;
1309 if (rxd
->ed_buf
[0] & 0x1) {
1310 if (bcmp(rxd
->ed_buf
, ex_broadcast
, ETHERADDRL
) != 0) {
1318 * Set the incoming checksum information for the packet.
1320 if (((sc
->ex_conf
& CONF_90XB
) != 0) &&
1321 ((stat
& EX_UPD_IPCHECKED
) != 0) &&
1322 ((stat
& (EX_UPD_CKSUMERR
)) == 0)) {
1323 uint32_t pflags
= 0;
1324 if (stat
& EX_UPD_IPCHECKED
) {
1325 pflags
|= HCK_IPV4_HDRCKSUM
;
1327 if (stat
& (EX_UPD_TCPCHECKED
| EX_UPD_UDPCHECKED
)) {
1328 pflags
|= (HCK_FULLCKSUM
| HCK_FULLCKSUM_OK
);
1330 (void) hcksum_assoc(mp
, NULL
, NULL
, 0, 0, 0, 0, pflags
, 0);
1337 elxl_m_start(void *arg
)
1341 mutex_enter(&sc
->ex_intrlock
);
1342 mutex_enter(&sc
->ex_txlock
);
1345 sc
->ex_running
= B_TRUE
;
1347 mutex_exit(&sc
->ex_txlock
);
1348 mutex_exit(&sc
->ex_intrlock
);
1351 mii_start(sc
->ex_miih
);
1357 elxl_m_stop(void *arg
)
1362 mii_stop(sc
->ex_miih
);
1365 mutex_enter(&sc
->ex_intrlock
);
1366 mutex_enter(&sc
->ex_txlock
);
1369 sc
->ex_running
= B_FALSE
;
1371 mutex_exit(&sc
->ex_txlock
);
1372 mutex_exit(&sc
->ex_intrlock
);
1376 elxl_m_getcapab(void *arg
, mac_capab_t cap
, void *data
)
1380 case MAC_CAPAB_HCKSUM
: {
1381 uint32_t *flags
= data
;
1382 if (sc
->ex_conf
& CONF_90XB
) {
1383 *flags
= HCKSUM_IPHDRCKSUM
| HCKSUM_INET_FULL_V4
;
1394 elxl_m_getprop(void *arg
, const char *name
, mac_prop_id_t num
, uint_t sz
,
1400 if (sc
->ex_mii_active
) {
1401 rv
= mii_m_getprop(sc
->ex_miih
, name
, num
, sz
, val
);
1407 case MAC_PROP_DUPLEX
:
1408 *(uint8_t *)val
= sc
->ex_duplex
;
1410 case MAC_PROP_SPEED
:
1411 *(uint8_t *)val
= sc
->ex_speed
;
1413 case MAC_PROP_STATUS
:
1414 bcopy(&sc
->ex_link
, val
, sizeof (link_state_t
));
1417 case MAC_PROP_PRIVATE
:
1418 if (strcmp(name
, "_media") == 0) {
1421 switch (sc
->ex_xcvr
) {
1427 str
= sc
->ex_fdx
? "tp-fdx" : "tp-hdx";
1433 if (sc
->ex_mediaopt
& MEDIAOPT_10FL
) {
1434 str
= sc
->ex_fdx
? "fl-fdx" : "fl-hdx";
1439 case XCVR_SEL_100FX
:
1440 str
= sc
->ex_fdx
? "fx-fdx" : "fx-hdx";
1446 (void) snprintf(val
, sz
, "%s", str
);
1450 * This available media property is a hack, and should
1451 * be removed when we can provide proper support for
1452 * querying it as proposed in PSARC 2009/235. (At the
1453 * moment the implementation lacks support for using
1454 * MAC_PROP_POSSIBLE with private properties.)
1456 if (strcmp(name
, "_available_media") == 0) {
1457 (void) snprintf(val
, sz
, "%s", sc
->ex_medias
);
1466 elxl_m_setprop(void *arg
, const char *name
, mac_prop_id_t num
, uint_t sz
,
1472 if (sc
->ex_mii_active
) {
1473 rv
= mii_m_setprop(sc
->ex_miih
, name
, num
, sz
, val
);
1474 if (rv
!= ENOTSUP
) {
1480 case MAC_PROP_PRIVATE
:
1481 if (strcmp(name
, "_media") == 0) {
1482 uint32_t mopt
= sc
->ex_mediaopt
;
1484 if (strcmp(val
, "mii") == 0) {
1485 if (mopt
& MEDIAOPT_100TX
) {
1486 sc
->ex_xcvr
= XCVR_SEL_AUTO
;
1487 } else if (mopt
& MEDIAOPT_MII
) {
1488 sc
->ex_xcvr
= XCVR_SEL_MII
;
1492 } else if (strcmp(val
, "tp-fdx") == 0) {
1493 /* select media option */
1494 if (mopt
& MEDIAOPT_10T
) {
1495 sc
->ex_xcvr
= XCVR_SEL_10T
;
1496 sc
->ex_fdx
= B_TRUE
;
1500 } else if (strcmp(val
, "tp-hdx") == 0) {
1501 /* select media option */
1502 if (mopt
& MEDIAOPT_10T
) {
1503 sc
->ex_xcvr
= XCVR_SEL_10T
;
1504 sc
->ex_fdx
= B_FALSE
;
1508 } else if (strcmp(val
, "fx-fdx") == 0) {
1509 if (mopt
& MEDIAOPT_100FX
) {
1510 sc
->ex_xcvr
= XCVR_SEL_100FX
;
1511 sc
->ex_fdx
= B_TRUE
;
1515 } else if (strcmp(val
, "fx-hdx") == 0) {
1516 if (mopt
& MEDIAOPT_100FX
) {
1517 sc
->ex_xcvr
= XCVR_SEL_100FX
;
1518 sc
->ex_fdx
= B_FALSE
;
1522 } else if (strcmp(val
, "bnc") == 0) {
1523 if (mopt
& MEDIAOPT_BNC
) {
1524 sc
->ex_xcvr
= XCVR_SEL_BNC
;
1525 sc
->ex_fdx
= B_FALSE
;
1529 } else if (strcmp(val
, "aui") == 0) {
1530 if (mopt
& MEDIAOPT_AUI
) {
1531 sc
->ex_xcvr
= XCVR_SEL_AUI
;
1532 sc
->ex_fdx
= B_FALSE
;
1536 } else if (strcmp(val
, "fl-fdx") == 0) {
1537 if (mopt
& MEDIAOPT_10FL
) {
1538 sc
->ex_xcvr
= XCVR_SEL_AUI
;
1539 sc
->ex_fdx
= B_TRUE
;
1543 } else if (strcmp(val
, "fl-hdx") == 0) {
1544 if (mopt
& MEDIAOPT_10FL
) {
1545 sc
->ex_xcvr
= XCVR_SEL_AUI
;
1546 sc
->ex_fdx
= B_FALSE
;
1564 mutex_enter(&sc
->ex_intrlock
);
1565 mutex_enter(&sc
->ex_txlock
);
1566 if (!sc
->ex_suspended
) {
1568 if (sc
->ex_running
) {
1572 mutex_exit(&sc
->ex_txlock
);
1573 mutex_exit(&sc
->ex_intrlock
);
1578 elxl_m_propinfo(void *arg
, const char *name
, mac_prop_id_t num
,
1579 mac_prop_info_handle_t prh
)
1583 if (sc
->ex_mii_active
)
1584 mii_m_propinfo(sc
->ex_miih
, name
, num
, prh
);
1587 case MAC_PROP_DUPLEX
:
1588 case MAC_PROP_SPEED
:
1589 case MAC_PROP_STATUS
:
1590 mac_prop_info_set_perm(prh
, MAC_PROP_PERM_READ
);
1593 case MAC_PROP_PRIVATE
:
1594 if (strcmp(name
, "_available_media") == 0)
1595 mac_prop_info_set_perm(prh
, MAC_PROP_PERM_READ
);
1601 elxl_m_stat(void *arg
, uint_t stat
, uint64_t *val
)
1605 if (stat
== MAC_STAT_IFSPEED
) {
1609 if ((sc
->ex_mii_active
) &&
1610 (mii_m_getstat(sc
->ex_miih
, stat
, val
) == 0)) {
1615 case MAC_STAT_IFSPEED
:
1616 *val
= sc
->ex_speed
;
1619 case ETHER_STAT_LINK_DUPLEX
:
1620 *val
= sc
->ex_duplex
;
1623 case MAC_STAT_MULTIRCV
:
1624 *val
= sc
->ex_multircv
;
1627 case MAC_STAT_BRDCSTRCV
:
1628 *val
= sc
->ex_brdcstrcv
;
1631 case MAC_STAT_MULTIXMT
:
1632 *val
= sc
->ex_multixmt
;
1635 case MAC_STAT_BRDCSTXMT
:
1636 *val
= sc
->ex_brdcstxmt
;
1639 case MAC_STAT_IPACKETS
:
1640 *val
= sc
->ex_ipackets
;
1643 case MAC_STAT_OPACKETS
:
1644 *val
= sc
->ex_opackets
;
1647 case MAC_STAT_RBYTES
:
1648 *val
= sc
->ex_ibytes
;
1650 case MAC_STAT_OBYTES
:
1651 *val
= sc
->ex_obytes
;
1654 case MAC_STAT_COLLISIONS
:
1655 case ETHER_STAT_FIRST_COLLISIONS
:
1656 *val
= sc
->ex_singlecol
+ sc
->ex_multcol
;
1659 case ETHER_STAT_MULTI_COLLISIONS
:
1660 *val
= sc
->ex_multcol
;
1663 case ETHER_STAT_TX_LATE_COLLISIONS
:
1664 *val
= sc
->ex_latecol
;
1667 case ETHER_STAT_ALIGN_ERRORS
:
1668 *val
= sc
->ex_align
;
1671 case ETHER_STAT_FCS_ERRORS
:
1675 case ETHER_STAT_SQE_ERRORS
:
1679 case ETHER_STAT_DEFER_XMTS
:
1680 *val
= sc
->ex_defer
;
1683 case ETHER_STAT_CARRIER_ERRORS
:
1684 *val
= sc
->ex_nocarrier
;
1687 case ETHER_STAT_TOOLONG_ERRORS
:
1688 *val
= sc
->ex_toolong
;
1691 case ETHER_STAT_EX_COLLISIONS
:
1692 *val
= sc
->ex_excoll
;
1695 case MAC_STAT_OVERFLOWS
:
1699 case MAC_STAT_UNDERFLOWS
:
1703 case ETHER_STAT_TOOSHORT_ERRORS
:
1707 case ETHER_STAT_JABBER_ERRORS
:
1708 *val
= sc
->ex_jabber
;
1711 case MAC_STAT_NORCVBUF
:
1712 *val
= sc
->ex_allocbfail
;
1715 case MAC_STAT_OERRORS
:
1716 *val
= sc
->ex_jabber
+ sc
->ex_latecol
+ sc
->ex_uflo
;
1719 case MAC_STAT_IERRORS
:
1720 *val
= sc
->ex_align
+ sc
->ex_fcs
+ sc
->ex_runt
+
1721 sc
->ex_toolong
+ sc
->ex_oflo
+ sc
->ex_allocbfail
;
1731 elxl_intr(caddr_t arg
, caddr_t dontcare
)
1733 elxl_t
*sc
= (void *)arg
;
1735 mblk_t
*mphead
= NULL
;
1736 mblk_t
**mpp
= &mphead
;
1738 _NOTE(ARGUNUSED(dontcare
));
1740 mutex_enter(&sc
->ex_intrlock
);
1741 if (sc
->ex_suspended
) {
1742 mutex_exit(&sc
->ex_intrlock
);
1743 return (DDI_INTR_UNCLAIMED
);
1746 stat
= GET16(REG_CMD_STAT
);
1748 if ((stat
& INT_LATCH
) == 0) {
1749 mutex_exit(&sc
->ex_intrlock
);
1750 return (DDI_INTR_UNCLAIMED
);
1754 * Acknowledge interrupts.
1756 PUT_CMD(CMD_INT_ACK
| (stat
& INT_WATCHED
) | INT_LATCH
);
1758 if (stat
& INT_HOST_ERROR
) {
1759 /* XXX: Potentially a good spot for FMA */
1760 elxl_error(sc
, "Adapter failure (%x)", stat
);
1761 mutex_enter(&sc
->ex_txlock
);
1765 mutex_exit(&sc
->ex_txlock
);
1766 mutex_exit(&sc
->ex_intrlock
);
1767 return (DDI_INTR_CLAIMED
);
1769 if (stat
& INT_UP_COMPLETE
) {
1782 (void) ddi_dma_sync(r
->r_dmah
, rxd
->ed_off
,
1783 sizeof (ex_pd_t
), DDI_DMA_SYNC_FORKERNEL
);
1785 pktstat
= GET_PD(r
, pd
->pd_status
);
1787 if ((pktstat
& EX_UPD_COMPLETE
) == 0) {
1791 /* Advance head to next packet. */
1792 r
->r_head
= r
->r_head
->ed_next
;
1794 if ((mp
= elxl_recv(sc
, rxd
, pktstat
)) != NULL
) {
1799 /* clear the upComplete status, reset other fields */
1800 PUT_PD(r
, pd
->pd_status
, 0);
1801 PUT_PD(r
, pd
->pd_len
, EX_BUFSZ
| EX_FR_LAST
);
1802 PUT_PD(r
, pd
->pd_addr
, rxd
->ed_bufaddr
);
1803 (void) ddi_dma_sync(r
->r_dmah
, rxd
->ed_off
,
1804 sizeof (ex_pd_t
), DDI_DMA_SYNC_FORDEV
);
1808 * If the engine stalled processing (due to
1809 * insufficient UPDs usually), restart it.
1811 if (GET32(REG_UPLISTPTR
) == 0) {
1813 * This seems that it can happen in an RX overrun
1816 mutex_enter(&sc
->ex_txlock
);
1819 mutex_exit(&sc
->ex_txlock
);
1821 PUT_CMD(CMD_UP_UNSTALL
);
1824 mutex_exit(&sc
->ex_intrlock
);
1827 mac_rx(sc
->ex_mach
, NULL
, mphead
);
1829 if (stat
& INT_STATS
) {
1832 if (stat
& INT_DN_COMPLETE
) {
1833 mac_tx_update(sc
->ex_mach
);
1836 return (DDI_INTR_CLAIMED
);
1840 elxl_getstats(elxl_t
*sc
)
1842 mutex_enter(&sc
->ex_txlock
);
1843 if (sc
->ex_suspended
) {
1844 mutex_exit(&sc
->ex_txlock
);
1850 * We count the packets and bytes elsewhere, but we need to
1851 * read the registers to clear them.
1853 (void) GET8(W6_RX_FRAMES
);
1854 (void) GET8(W6_TX_FRAMES
);
1855 (void) GET8(W6_UPPER_FRAMES
);
1856 (void) GET8(W6_RX_OVERRUNS
); /* counted by elxl_recv */
1857 (void) GET16(W6_RX_BYTES
);
1858 (void) GET16(W6_TX_BYTES
);
1860 sc
->ex_defer
+= GET8(W6_DEFER
);
1861 sc
->ex_latecol
+= GET8(W6_TX_LATE_COL
);
1862 sc
->ex_singlecol
+= GET8(W6_SINGLE_COL
);
1863 sc
->ex_multcol
+= GET8(W6_MULT_COL
);
1864 sc
->ex_sqe
+= GET8(W6_SQE_ERRORS
);
1865 sc
->ex_nocarrier
+= GET8(W6_NO_CARRIER
);
1868 /* Note: we ought to report this somewhere... */
1869 (void) GET8(W4_BADSSD
);
1871 mutex_exit(&sc
->ex_txlock
);
1875 elxl_reset(elxl_t
*sc
)
1877 PUT_CMD(CMD_GLOBAL_RESET
);
1879 * Some ASICs need a longer time (20 ms) to come properly out
1880 * of reset. Do not reduce this value.
1882 * Note that this occurs only during attach and failure recovery,
1883 * so it should be mostly harmless.
1885 drv_usecwait(20000);
1890 elxl_stop(elxl_t
*sc
)
1892 ASSERT(mutex_owned(&sc
->ex_intrlock
));
1893 ASSERT(mutex_owned(&sc
->ex_txlock
));
1895 if (sc
->ex_suspended
)
1898 PUT_CMD(CMD_RX_DISABLE
);
1899 PUT_CMD(CMD_TX_DISABLE
);
1900 PUT_CMD(CMD_BNC_DISABLE
);
1902 elxl_reset_ring(&sc
->ex_rxring
, DDI_DMA_READ
);
1903 elxl_reset_ring(&sc
->ex_txring
, DDI_DMA_WRITE
);
1905 PUT_CMD(CMD_INT_ACK
| INT_LATCH
);
1906 /* Disable all interrupts. (0 means "none".) */
1907 PUT_CMD(CMD_INT_ENABLE
| 0);
1911 elxl_suspend(elxl_t
*sc
)
1914 mii_suspend(sc
->ex_miih
);
1917 mutex_enter(&sc
->ex_intrlock
);
1918 mutex_enter(&sc
->ex_txlock
);
1920 sc
->ex_suspended
= B_TRUE
;
1921 mutex_exit(&sc
->ex_txlock
);
1922 mutex_exit(&sc
->ex_intrlock
);
1926 elxl_resume(dev_info_t
*dip
)
1930 /* This should always succeed. */
1931 sc
= ddi_get_driver_private(dip
);
1934 mutex_enter(&sc
->ex_intrlock
);
1935 mutex_enter(&sc
->ex_txlock
);
1936 sc
->ex_suspended
= B_FALSE
;
1940 mutex_exit(&sc
->ex_txlock
);
1941 mutex_exit(&sc
->ex_intrlock
);
1944 mii_resume(sc
->ex_miih
);
1949 elxl_detach(elxl_t
*sc
)
1952 /* Detach all PHYs */
1953 mii_free(sc
->ex_miih
);
1955 if (sc
->ex_linkcheck
) {
1956 ddi_periodic_delete(sc
->ex_linkcheck
);
1959 if (sc
->ex_intrh
!= NULL
) {
1960 (void) ddi_intr_disable(sc
->ex_intrh
);
1961 (void) ddi_intr_remove_handler(sc
->ex_intrh
);
1962 (void) ddi_intr_free(sc
->ex_intrh
);
1963 mutex_destroy(&sc
->ex_intrlock
);
1964 mutex_destroy(&sc
->ex_txlock
);
1968 pci_config_teardown(&sc
->ex_pcih
);
1971 ddi_regs_map_free(&sc
->ex_regsh
);
1973 ex_free_ring(&sc
->ex_txring
);
1974 ex_free_ring(&sc
->ex_rxring
);
1976 kmem_free(sc
, sizeof (*sc
));
1980 * Read EEPROM data. If we can't unbusy the EEPROM, then zero will be
1981 * returned. This will probably result in a bogus node address.
1984 elxl_read_eeprom(elxl_t
*sc
, int offset
)
1989 if (elxl_eeprom_busy(sc
))
1992 PUT16(W0_EE_CMD
, EE_CMD_READ
| (offset
& 0x3f));
1993 if (elxl_eeprom_busy(sc
))
1995 data
= GET16(W0_EE_DATA
);
2001 elxl_eeprom_busy(elxl_t
*sc
)
2006 if (!(GET16(W0_EE_CMD
) & EE_CMD_BUSY
))
2010 elxl_error(sc
, "Eeprom stays busy.");
2015 ex_mii_send_bits(struct ex_softc
*sc
, uint16_t bits
, int cnt
)
2020 PUT16(W4_PHYSMGMT
, PHYSMGMT_DIR
);
2023 for (int i
= (1 << (cnt
- 1)); i
; i
>>= 1) {
2025 val
= PHYSMGMT_DIR
| PHYSMGMT_DATA
;
2029 PUT16(W4_PHYSMGMT
, val
);
2031 PUT16(W4_PHYSMGMT
, val
| PHYSMGMT_CLK
);
2033 PUT16(W4_PHYSMGMT
, val
);
2039 ex_mii_sync(struct ex_softc
*sc
)
2042 * We set the data bit output, and strobe the clock 32 times.
2044 PUT16(W4_PHYSMGMT
, PHYSMGMT_DATA
| PHYSMGMT_DIR
);
2047 for (int i
= 0; i
< 32; i
++) {
2048 PUT16(W4_PHYSMGMT
, PHYSMGMT_DATA
| PHYSMGMT_DIR
| PHYSMGMT_CLK
);
2050 PUT16(W4_PHYSMGMT
, PHYSMGMT_DATA
| PHYSMGMT_DIR
);
2056 elxl_mii_read(void *arg
, uint8_t phy
, uint8_t reg
)
2062 if ((sc
->ex_conf
& CONF_INTPHY
) && phy
!= INTPHY_ID
)
2065 mutex_enter(&sc
->ex_txlock
);
2070 ex_mii_send_bits(sc
, 1, 2); /* start */
2071 ex_mii_send_bits(sc
, 2, 2); /* read command */
2072 ex_mii_send_bits(sc
, phy
, 5);
2073 ex_mii_send_bits(sc
, reg
, 5);
2075 PUT16(W4_PHYSMGMT
, 0); /* switch to input */
2077 PUT16(W4_PHYSMGMT
, PHYSMGMT_CLK
); /* turnaround time */
2079 PUT16(W4_PHYSMGMT
, 0);
2082 PUT16(W4_PHYSMGMT
, PHYSMGMT_CLK
); /* idle time */
2084 PUT16(W4_PHYSMGMT
, 0);
2087 for (data
= 0, val
= 0x8000; val
; val
>>= 1) {
2088 if (GET16(W4_PHYSMGMT
) & PHYSMGMT_DATA
) {
2091 /* strobe the clock */
2092 PUT16(W4_PHYSMGMT
, PHYSMGMT_CLK
);
2094 PUT16(W4_PHYSMGMT
, 0);
2098 /* return to output mode */
2099 PUT16(W4_PHYSMGMT
, PHYSMGMT_DIR
);
2102 mutex_exit(&sc
->ex_txlock
);
2108 elxl_mii_write(void *arg
, uint8_t phy
, uint8_t reg
, uint16_t data
)
2112 if ((sc
->ex_conf
& CONF_INTPHY
) && phy
!= INTPHY_ID
)
2115 mutex_enter(&sc
->ex_txlock
);
2119 ex_mii_send_bits(sc
, 1, 2); /* start */
2120 ex_mii_send_bits(sc
, 1, 2); /* write */
2121 ex_mii_send_bits(sc
, phy
, 5);
2122 ex_mii_send_bits(sc
, reg
, 5);
2123 ex_mii_send_bits(sc
, 2, 2); /* ack/turnaround */
2124 ex_mii_send_bits(sc
, data
, 16);
2126 /* return to output mode */
2127 PUT16(W4_PHYSMGMT
, PHYSMGMT_DIR
);
2130 mutex_exit(&sc
->ex_txlock
);
2134 elxl_mii_notify(void *arg
, link_state_t link
)
2138 link_duplex_t duplex
;
2140 duplex
= mii_get_duplex(sc
->ex_miih
);
2142 mutex_enter(&sc
->ex_txlock
);
2143 if (!sc
->ex_mii_active
) {
2144 /* If we're using some other legacy media, bail out now */
2145 mutex_exit(&sc
->ex_txlock
);
2148 if (!sc
->ex_suspended
) {
2150 mctl
= GET16(W3_MAC_CONTROL
);
2151 if (duplex
== LINK_DUPLEX_FULL
)
2152 mctl
|= MAC_CONTROL_FDX
;
2154 mctl
&= ~MAC_CONTROL_FDX
;
2155 PUT16(W3_MAC_CONTROL
, mctl
);
2157 mutex_exit(&sc
->ex_txlock
);
2159 mac_link_update(sc
->ex_mach
, link
);
2163 elxl_ddi_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
2167 return (elxl_attach(dip
));
2171 return (DDI_SUCCESS
);
2174 return (DDI_FAILURE
);
2179 elxl_ddi_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
2183 sc
= ddi_get_driver_private(dip
);
2188 if (mac_disable(sc
->ex_mach
) != 0) {
2189 return (DDI_FAILURE
);
2191 (void) mac_unregister(sc
->ex_mach
);
2193 return (DDI_SUCCESS
);
2197 return (DDI_SUCCESS
);
2200 return (DDI_FAILURE
);
2205 elxl_ddi_quiesce(dev_info_t
*dip
)
2209 sc
= ddi_get_driver_private(dip
);
2212 if (!sc
->ex_suspended
)
2214 return (DDI_SUCCESS
);
2218 elxl_error(elxl_t
*sc
, char *fmt
, ...)
2224 (void) vsnprintf(buf
, sizeof (buf
), fmt
, ap
);
2227 cmn_err(CE_WARN
, "%s%d: %s",
2228 ddi_driver_name(sc
->ex_dip
), ddi_get_instance(sc
->ex_dip
), buf
);