1*481d3881Srin /* $NetBSD: epe.c,v 1.51 2024/07/05 04:31:49 rin Exp $ */
24eeab775Sjoff
34eeab775Sjoff /*
44eeab775Sjoff * Copyright (c) 2004 Jesse Off
54eeab775Sjoff * All rights reserved.
64eeab775Sjoff *
74eeab775Sjoff * Redistribution and use in source and binary forms, with or without
84eeab775Sjoff * modification, are permitted provided that the following conditions
94eeab775Sjoff * are met:
104eeab775Sjoff * 1. Redistributions of source code must retain the above copyright
114eeab775Sjoff * notice, this list of conditions and the following disclaimer.
124eeab775Sjoff * 2. Redistributions in binary form must reproduce the above copyright
134eeab775Sjoff * notice, this list of conditions and the following disclaimer in the
144eeab775Sjoff * documentation and/or other materials provided with the distribution.
154eeab775Sjoff *
164eeab775Sjoff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
174eeab775Sjoff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
184eeab775Sjoff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194eeab775Sjoff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
204eeab775Sjoff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214eeab775Sjoff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224eeab775Sjoff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234eeab775Sjoff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244eeab775Sjoff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
254eeab775Sjoff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264eeab775Sjoff * POSSIBILITY OF SUCH DAMAGE.
274eeab775Sjoff */
284eeab775Sjoff
294eeab775Sjoff #include <sys/cdefs.h>
30*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: epe.c,v 1.51 2024/07/05 04:31:49 rin Exp $");
314eeab775Sjoff
324eeab775Sjoff #include <sys/types.h>
334eeab775Sjoff #include <sys/param.h>
344eeab775Sjoff #include <sys/systm.h>
354eeab775Sjoff #include <sys/ioctl.h>
364eeab775Sjoff #include <sys/kernel.h>
374eeab775Sjoff #include <sys/proc.h>
384eeab775Sjoff #include <sys/time.h>
394eeab775Sjoff #include <sys/device.h>
404eeab775Sjoff #include <uvm/uvm_extern.h>
414eeab775Sjoff
42cf10107dSdyoung #include <sys/bus.h>
434eeab775Sjoff #include <machine/intr.h>
444eeab775Sjoff
454eeab775Sjoff #include <arm/cpufunc.h>
464eeab775Sjoff
474eeab775Sjoff #include <arm/ep93xx/epsocvar.h>
484eeab775Sjoff #include <arm/ep93xx/ep93xxvar.h>
494eeab775Sjoff
504eeab775Sjoff #include <net/if.h>
514eeab775Sjoff #include <net/if_dl.h>
524eeab775Sjoff #include <net/if_types.h>
534eeab775Sjoff #include <net/if_media.h>
544eeab775Sjoff #include <net/if_ether.h>
554b508fb1Smsaitoh #include <net/bpf.h>
564eeab775Sjoff
574eeab775Sjoff #include <dev/mii/mii.h>
584eeab775Sjoff #include <dev/mii/miivar.h>
594eeab775Sjoff
604eeab775Sjoff #ifdef INET
614eeab775Sjoff #include <netinet/in.h>
624eeab775Sjoff #include <netinet/in_systm.h>
634eeab775Sjoff #include <netinet/in_var.h>
644eeab775Sjoff #include <netinet/ip.h>
654eeab775Sjoff #include <netinet/if_inarp.h>
664eeab775Sjoff #endif
674eeab775Sjoff
68944e317aSjoff #include <arm/ep93xx/ep93xxreg.h>
694eeab775Sjoff #include <arm/ep93xx/epereg.h>
704eeab775Sjoff #include <arm/ep93xx/epevar.h>
714eeab775Sjoff
727959c31aShamajima #define DEFAULT_MDCDIV 32
737959c31aShamajima
74944e317aSjoff #ifndef EPE_FAST
75944e317aSjoff #define EPE_FAST
76944e317aSjoff #endif
774eeab775Sjoff
78944e317aSjoff #ifndef EPE_FAST
794eeab775Sjoff #define EPE_READ(x) \
804eeab775Sjoff bus_space_read_4(sc->sc_iot, sc->sc_ioh, (EPE_ ## x))
814eeab775Sjoff #define EPE_WRITE(x, y) \
824eeab775Sjoff bus_space_write_4(sc->sc_iot, sc->sc_ioh, (EPE_ ## x), (y))
83944e317aSjoff #define CTRLPAGE_DMASYNC(x, y, z) \
84944e317aSjoff bus_dmamap_sync(sc->sc_dmat, sc->ctrlpage_dmamap, (x), (y), (z))
85944e317aSjoff #else
8608a4aba7Sskrll #define EPE_READ(x) *(volatile uint32_t *) \
87944e317aSjoff (EP93XX_AHB_VBASE + EP93XX_AHB_EPE + (EPE_ ## x))
8808a4aba7Sskrll #define EPE_WRITE(x, y) *(volatile uint32_t *) \
89944e317aSjoff (EP93XX_AHB_VBASE + EP93XX_AHB_EPE + (EPE_ ## x)) = y
90944e317aSjoff #define CTRLPAGE_DMASYNC(x, y, z)
91944e317aSjoff #endif /* ! EPE_FAST */
924eeab775Sjoff
930bc32000Smatt static int epe_match(device_t , cfdata_t, void *);
940bc32000Smatt static void epe_attach(device_t, device_t, void *);
954eeab775Sjoff static void epe_init(struct epe_softc *);
964eeab775Sjoff static int epe_intr(void* arg);
97944e317aSjoff static int epe_gctx(struct epe_softc *);
98a5cdd4b4Smsaitoh int epe_mii_readreg (device_t, int, int, uint16_t *);
99a5cdd4b4Smsaitoh int epe_mii_writereg (device_t, int, int, uint16_t);
1000bc32000Smatt void epe_statchg (struct ifnet *);
1014eeab775Sjoff void epe_tick (void *);
10253524e44Schristos static int epe_ifioctl (struct ifnet *, u_long, void *);
1034eeab775Sjoff static void epe_ifstart (struct ifnet *);
1044eeab775Sjoff static void epe_ifwatchdog (struct ifnet *);
1054eeab775Sjoff static int epe_ifinit (struct ifnet *);
1064eeab775Sjoff static void epe_ifstop (struct ifnet *, int);
1074eeab775Sjoff static void epe_setaddr (struct ifnet *);
1084eeab775Sjoff
109cbab9cadSchs CFATTACH_DECL_NEW(epe, sizeof(struct epe_softc),
1104eeab775Sjoff epe_match, epe_attach, NULL, NULL);
1114eeab775Sjoff
1124eeab775Sjoff static int
epe_match(device_t parent,cfdata_t match,void * aux)1130bc32000Smatt epe_match(device_t parent, cfdata_t match, void *aux)
1144eeab775Sjoff {
1154eeab775Sjoff return 2;
1164eeab775Sjoff }
1174eeab775Sjoff
1184eeab775Sjoff static void
epe_attach(device_t parent,device_t self,void * aux)1190bc32000Smatt epe_attach(device_t parent, device_t self, void *aux)
1204eeab775Sjoff {
1210bc32000Smatt struct epe_softc *sc = device_private(self);
1224eeab775Sjoff struct epsoc_attach_args *sa;
123fb44a857Sthorpej prop_data_t enaddr;
1244eeab775Sjoff
1250bc32000Smatt aprint_normal("\n");
1264eeab775Sjoff sa = aux;
1270bc32000Smatt sc->sc_dev = self;
1284eeab775Sjoff sc->sc_iot = sa->sa_iot;
1294eeab775Sjoff sc->sc_intr = sa->sa_intr;
1304eeab775Sjoff sc->sc_dmat = sa->sa_dmat;
1314eeab775Sjoff
1324eeab775Sjoff if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size,
1334eeab775Sjoff 0, &sc->sc_ioh))
134cbab9cadSchs panic("%s: Cannot map registers", device_xname(self));
1354eeab775Sjoff
1367959c31aShamajima /* Fetch the Ethernet address from property if set. */
137f9e1815aSmartin enaddr = prop_dictionary_get(device_properties(self), "mac-address");
138fb44a857Sthorpej if (enaddr != NULL) {
139fb44a857Sthorpej KASSERT(prop_object_type(enaddr) == PROP_TYPE_DATA);
140fb44a857Sthorpej KASSERT(prop_data_size(enaddr) == ETHER_ADDR_LEN);
141fb44a857Sthorpej memcpy(sc->sc_enaddr, prop_data_data_nocopy(enaddr),
142fb44a857Sthorpej ETHER_ADDR_LEN);
1437959c31aShamajima bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPE_AFP, 0);
1447959c31aShamajima bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
1457959c31aShamajima sc->sc_enaddr, ETHER_ADDR_LEN);
1467959c31aShamajima }
1477959c31aShamajima
1484eeab775Sjoff ep93xx_intr_establish(sc->sc_intr, IPL_NET, epe_intr, sc);
1494eeab775Sjoff epe_init(sc);
1504eeab775Sjoff }
1514eeab775Sjoff
1524eeab775Sjoff static int
epe_gctx(struct epe_softc * sc)153944e317aSjoff epe_gctx(struct epe_softc *sc)
154944e317aSjoff {
155944e317aSjoff struct ifnet * ifp = &sc->sc_ec.ec_if;
15608a4aba7Sskrll uint32_t *cur, ndq = 0;
157944e317aSjoff
158944e317aSjoff /* Handle transmit completions */
15908a4aba7Sskrll cur = (uint32_t *)(EPE_READ(TXStsQCurAdd) -
160bc250f04She sc->ctrlpage_dsaddr + (char*)sc->ctrlpage);
161944e317aSjoff
162944e317aSjoff if (sc->TXStsQ_cur != cur) {
16308a4aba7Sskrll CTRLPAGE_DMASYNC(TX_QLEN * 2 * sizeof(uint32_t),
16408a4aba7Sskrll TX_QLEN * sizeof(uint32_t), BUS_DMASYNC_PREREAD);
1657b055612Smsaitoh } else
166944e317aSjoff return 0;
167944e317aSjoff
168944e317aSjoff do {
16908a4aba7Sskrll uint32_t tbi = *sc->TXStsQ_cur & 0x7fff;
170944e317aSjoff struct mbuf *m = sc->txq[tbi].m;
171944e317aSjoff
1727b055612Smsaitoh if ((*sc->TXStsQ_cur & TXStsQ_TxWE) == 0)
173180f0415Sskrll if_statinc(ifp, if_oerrors);
1747b055612Smsaitoh
175944e317aSjoff bus_dmamap_unload(sc->sc_dmat, sc->txq[tbi].m_dmamap);
176944e317aSjoff m_freem(m);
177944e317aSjoff do {
178944e317aSjoff sc->txq[tbi].m = NULL;
179944e317aSjoff ndq++;
180944e317aSjoff tbi = (tbi + 1) % TX_QLEN;
181944e317aSjoff } while (sc->txq[tbi].m == m);
182944e317aSjoff
183180f0415Sskrll if_statinc(ifp, if_opackets);
184944e317aSjoff sc->TXStsQ_cur++;
185944e317aSjoff if (sc->TXStsQ_cur >= sc->TXStsQ + TX_QLEN) {
186944e317aSjoff sc->TXStsQ_cur = sc->TXStsQ;
187944e317aSjoff }
188944e317aSjoff } while (sc->TXStsQ_cur != cur);
189944e317aSjoff
190944e317aSjoff sc->TXDQ_avail += ndq;
19140db1b6eSthorpej if (sc->tx_busy) {
19240db1b6eSthorpej sc->tx_busy = false;
193944e317aSjoff /* Disable end-of-tx-chain interrupt */
194944e317aSjoff EPE_WRITE(IntEn, IntEn_REOFIE);
195944e317aSjoff }
196944e317aSjoff return ndq;
197944e317aSjoff }
198944e317aSjoff
199944e317aSjoff static int
epe_intr(void * arg)2004eeab775Sjoff epe_intr(void *arg)
2014eeab775Sjoff {
2024eeab775Sjoff struct epe_softc *sc = (struct epe_softc *)arg;
2034eeab775Sjoff struct ifnet * ifp = &sc->sc_ec.ec_if;
20408a4aba7Sskrll uint32_t ndq = 0, irq, *cur;
2054eeab775Sjoff
2064eeab775Sjoff irq = EPE_READ(IntStsC);
2074eeab775Sjoff begin:
20808a4aba7Sskrll cur = (uint32_t *)(EPE_READ(RXStsQCurAdd) -
209bc250f04She sc->ctrlpage_dsaddr + (char*)sc->ctrlpage);
21008a4aba7Sskrll CTRLPAGE_DMASYNC(TX_QLEN * 3 * sizeof(uint32_t),
21108a4aba7Sskrll RX_QLEN * 4 * sizeof(uint32_t),
2124eeab775Sjoff BUS_DMASYNC_PREREAD);
2134eeab775Sjoff while (sc->RXStsQ_cur != cur) {
2147b055612Smsaitoh if ((sc->RXStsQ_cur[0] & (RXStsQ_RWE | RXStsQ_RFP |RXStsQ_EOB))
2157b055612Smsaitoh == (RXStsQ_RWE | RXStsQ_RFP | RXStsQ_EOB)) {
21608a4aba7Sskrll uint32_t bi = (sc->RXStsQ_cur[1] >> 16) & 0x7fff;
21708a4aba7Sskrll uint32_t fl = sc->RXStsQ_cur[1] & 0xffff;
2184eeab775Sjoff struct mbuf *m;
2194eeab775Sjoff
2204eeab775Sjoff MGETHDR(m, M_DONTWAIT, MT_DATA);
2214eeab775Sjoff if (m != NULL) MCLGET(m, M_DONTWAIT);
2224eeab775Sjoff if (m != NULL && (m->m_flags & M_EXT)) {
2234eeab775Sjoff bus_dmamap_unload(sc->sc_dmat,
2244eeab775Sjoff sc->rxq[bi].m_dmamap);
225d938d837Sozaki-r m_set_rcvif(sc->rxq[bi].m, ifp);
2264eeab775Sjoff sc->rxq[bi].m->m_pkthdr.len =
2274eeab775Sjoff sc->rxq[bi].m->m_len = fl;
2289c4cd063Sozaki-r if_percpuq_enqueue(ifp->if_percpuq,
2299c4cd063Sozaki-r sc->rxq[bi].m);
2304eeab775Sjoff sc->rxq[bi].m = m;
2314eeab775Sjoff bus_dmamap_load(sc->sc_dmat,
2324eeab775Sjoff sc->rxq[bi].m_dmamap,
2334eeab775Sjoff m->m_ext.ext_buf, MCLBYTES,
2344eeab775Sjoff NULL, BUS_DMA_NOWAIT);
2354eeab775Sjoff sc->RXDQ[bi * 2] =
2364eeab775Sjoff sc->rxq[bi].m_dmamap->dm_segs[0].ds_addr;
2374eeab775Sjoff } else {
2384eeab775Sjoff /* Drop packets until we can get replacement
2394eeab775Sjoff * empty mbufs for the RXDQ.
2404eeab775Sjoff */
2414eeab775Sjoff m_freem(m);
2427b055612Smsaitoh
243180f0415Sskrll if_statinc(ifp, if_ierrors);
2444eeab775Sjoff }
2457b055612Smsaitoh } else
246180f0415Sskrll if_statinc(ifp, if_ierrors);
2474eeab775Sjoff
2484eeab775Sjoff ndq++;
2494eeab775Sjoff
2504eeab775Sjoff sc->RXStsQ_cur += 2;
2517b055612Smsaitoh if (sc->RXStsQ_cur >= sc->RXStsQ + (RX_QLEN * 2))
2524eeab775Sjoff sc->RXStsQ_cur = sc->RXStsQ;
2534eeab775Sjoff }
2544eeab775Sjoff
2554eeab775Sjoff if (ndq > 0) {
25608a4aba7Sskrll CTRLPAGE_DMASYNC(TX_QLEN * 3 * sizeof(uint32_t),
25708a4aba7Sskrll RX_QLEN * 4 * sizeof(uint32_t),
2584eeab775Sjoff BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
2594eeab775Sjoff EPE_WRITE(RXStsEnq, ndq);
2604eeab775Sjoff EPE_WRITE(RXDEnq, ndq);
2614eeab775Sjoff ndq = 0;
2624eeab775Sjoff }
2634eeab775Sjoff
264944e317aSjoff if (epe_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) {
26530b089e7Snonaka if_schedule_deferred_start(ifp);
2664eeab775Sjoff }
2674eeab775Sjoff
2684eeab775Sjoff irq = EPE_READ(IntStsC);
269944e317aSjoff if ((irq & (IntSts_RxSQ | IntSts_ECI)) != 0)
2704eeab775Sjoff goto begin;
271944e317aSjoff
2727b055612Smsaitoh return 1;
2734eeab775Sjoff }
2744eeab775Sjoff
2754eeab775Sjoff
2764eeab775Sjoff static void
epe_init(struct epe_softc * sc)2774eeab775Sjoff epe_init(struct epe_softc *sc)
2784eeab775Sjoff {
2794eeab775Sjoff bus_dma_segment_t segs;
280bc250f04She char *addr;
2814eeab775Sjoff int rsegs, err, i;
2824eeab775Sjoff struct ifnet * ifp = &sc->sc_ec.ec_if;
2835689358dSmsaitoh struct mii_data *mii = &sc->sc_mii;
2847959c31aShamajima int mdcdiv = DEFAULT_MDCDIV;
2854eeab775Sjoff
28688ab7da9Sad callout_init(&sc->epe_tick_ch, 0);
2874eeab775Sjoff
2884eeab775Sjoff /* Select primary Individual Address in Address Filter Pointer */
2894eeab775Sjoff EPE_WRITE(AFP, 0);
2904eeab775Sjoff /* Read ethernet MAC, should already be set by bootrom */
2914eeab775Sjoff bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
2924eeab775Sjoff sc->sc_enaddr, ETHER_ADDR_LEN);
2930bc32000Smatt aprint_normal_dev(sc->sc_dev, "MAC address %s\n",
2944eeab775Sjoff ether_sprintf(sc->sc_enaddr));
2954eeab775Sjoff
2964eeab775Sjoff /* Soft Reset the MAC */
2974eeab775Sjoff EPE_WRITE(SelfCtl, SelfCtl_RESET);
2987b055612Smsaitoh while (EPE_READ(SelfCtl) & SelfCtl_RESET)
2997b055612Smsaitoh ;
3004eeab775Sjoff
3014eeab775Sjoff /* suggested magic initialization values from datasheet */
3024eeab775Sjoff EPE_WRITE(RXBufThrshld, 0x800040);
3034eeab775Sjoff EPE_WRITE(TXBufThrshld, 0x200010);
3044eeab775Sjoff EPE_WRITE(RXStsThrshld, 0x40002);
3054eeab775Sjoff EPE_WRITE(TXStsThrshld, 0x40002);
3064eeab775Sjoff EPE_WRITE(RXDThrshld, 0x40002);
3074eeab775Sjoff EPE_WRITE(TXDThrshld, 0x40002);
3084eeab775Sjoff
3094eeab775Sjoff /* Allocate a page of memory for descriptor and status queues */
3104eeab775Sjoff err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, 0, PAGE_SIZE,
3114eeab775Sjoff &segs, 1, &rsegs, BUS_DMA_WAITOK);
3124eeab775Sjoff if (err == 0) {
3134eeab775Sjoff err = bus_dmamem_map(sc->sc_dmat, &segs, 1, PAGE_SIZE,
314944e317aSjoff &sc->ctrlpage, (BUS_DMA_WAITOK | BUS_DMA_COHERENT));
3154eeab775Sjoff }
3164eeab775Sjoff if (err == 0) {
3174eeab775Sjoff err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
3184eeab775Sjoff 0, BUS_DMA_WAITOK, &sc->ctrlpage_dmamap);
3194eeab775Sjoff }
3204eeab775Sjoff if (err == 0) {
3214eeab775Sjoff err = bus_dmamap_load(sc->sc_dmat, sc->ctrlpage_dmamap,
3224eeab775Sjoff sc->ctrlpage, PAGE_SIZE, NULL, BUS_DMA_WAITOK);
3234eeab775Sjoff }
3244eeab775Sjoff if (err != 0) {
3250bc32000Smatt panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev));
3264eeab775Sjoff }
327944e317aSjoff sc->ctrlpage_dsaddr = sc->ctrlpage_dmamap->dm_segs[0].ds_addr;
328c363a9cbScegger memset(sc->ctrlpage, 0, PAGE_SIZE);
3294eeab775Sjoff
3304eeab775Sjoff /* Set up pointers to start of each queue in kernel addr space.
3314eeab775Sjoff * Each descriptor queue or status queue entry uses 2 words
3324eeab775Sjoff */
33308a4aba7Sskrll sc->TXDQ = (uint32_t *)sc->ctrlpage;
3344eeab775Sjoff sc->TXDQ_cur = sc->TXDQ;
3354eeab775Sjoff sc->TXDQ_avail = TX_QLEN - 1;
3364eeab775Sjoff sc->TXStsQ = &sc->TXDQ[TX_QLEN * 2];
3374eeab775Sjoff sc->TXStsQ_cur = sc->TXStsQ;
3384eeab775Sjoff sc->RXDQ = &sc->TXStsQ[TX_QLEN];
3394eeab775Sjoff sc->RXStsQ = &sc->RXDQ[RX_QLEN * 2];
3404eeab775Sjoff sc->RXStsQ_cur = sc->RXStsQ;
3414eeab775Sjoff
3424eeab775Sjoff /* Program each queue's start addr, cur addr, and len registers
3434eeab775Sjoff * with the physical addresses.
3444eeab775Sjoff */
345bc250f04She addr = (char *)sc->ctrlpage_dmamap->dm_segs[0].ds_addr;
34608a4aba7Sskrll EPE_WRITE(TXDQBAdd, (uint32_t)addr);
34708a4aba7Sskrll EPE_WRITE(TXDQCurAdd, (uint32_t)addr);
34808a4aba7Sskrll EPE_WRITE(TXDQBLen, TX_QLEN * 2 * sizeof(uint32_t));
3494eeab775Sjoff
35008a4aba7Sskrll addr += (sc->TXStsQ - sc->TXDQ) * sizeof(uint32_t);
35108a4aba7Sskrll EPE_WRITE(TXStsQBAdd, (uint32_t)addr);
35208a4aba7Sskrll EPE_WRITE(TXStsQCurAdd, (uint32_t)addr);
35308a4aba7Sskrll EPE_WRITE(TXStsQBLen, TX_QLEN * sizeof(uint32_t));
3544eeab775Sjoff
35508a4aba7Sskrll addr += (sc->RXDQ - sc->TXStsQ) * sizeof(uint32_t);
35608a4aba7Sskrll EPE_WRITE(RXDQBAdd, (uint32_t)addr);
35708a4aba7Sskrll EPE_WRITE(RXDCurAdd, (uint32_t)addr);
35808a4aba7Sskrll EPE_WRITE(RXDQBLen, RX_QLEN * 2 * sizeof(uint32_t));
3594eeab775Sjoff
36008a4aba7Sskrll addr += (sc->RXStsQ - sc->RXDQ) * sizeof(uint32_t);
36108a4aba7Sskrll EPE_WRITE(RXStsQBAdd, (uint32_t)addr);
36208a4aba7Sskrll EPE_WRITE(RXStsQCurAdd, (uint32_t)addr);
36308a4aba7Sskrll EPE_WRITE(RXStsQBLen, RX_QLEN * 2 * sizeof(uint32_t));
3644eeab775Sjoff
3654eeab775Sjoff /* Populate the RXDQ with mbufs */
3664eeab775Sjoff for (i = 0; i < RX_QLEN; i++) {
3674eeab775Sjoff struct mbuf *m;
3684eeab775Sjoff
3697b055612Smsaitoh bus_dmamap_create(sc->sc_dmat, MCLBYTES, TX_QLEN/4, MCLBYTES,
3707b055612Smsaitoh 0, BUS_DMA_WAITOK, &sc->rxq[i].m_dmamap);
3714eeab775Sjoff MGETHDR(m, M_WAIT, MT_DATA);
3724eeab775Sjoff MCLGET(m, M_WAIT);
3734eeab775Sjoff sc->rxq[i].m = m;
3744eeab775Sjoff bus_dmamap_load(sc->sc_dmat, sc->rxq[i].m_dmamap,
3757b055612Smsaitoh m->m_ext.ext_buf, MCLBYTES, NULL, BUS_DMA_WAITOK);
3764eeab775Sjoff
3774eeab775Sjoff sc->RXDQ[i * 2] = sc->rxq[i].m_dmamap->dm_segs[0].ds_addr;
3784eeab775Sjoff sc->RXDQ[i * 2 + 1] = (i << 16) | MCLBYTES;
3794eeab775Sjoff bus_dmamap_sync(sc->sc_dmat, sc->rxq[i].m_dmamap, 0,
3804eeab775Sjoff MCLBYTES, BUS_DMASYNC_PREREAD);
3814eeab775Sjoff }
3824eeab775Sjoff
3834eeab775Sjoff for (i = 0; i < TX_QLEN; i++) {
3844eeab775Sjoff bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
3854eeab775Sjoff (BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW),
3864eeab775Sjoff &sc->txq[i].m_dmamap);
3874eeab775Sjoff sc->txq[i].m = NULL;
3884eeab775Sjoff sc->TXDQ[i * 2 + 1] = (i << 16);
3894eeab775Sjoff }
3904eeab775Sjoff
3914eeab775Sjoff /* Divide HCLK by 32 for MDC clock */
3920bc32000Smatt if (device_cfdata(sc->sc_dev)->cf_flags)
3930bc32000Smatt mdcdiv = device_cfdata(sc->sc_dev)->cf_flags;
3947959c31aShamajima EPE_WRITE(SelfCtl, (SelfCtl_MDCDIV(mdcdiv) | SelfCtl_PSPRS));
3954eeab775Sjoff
3965689358dSmsaitoh mii->mii_ifp = ifp;
3975689358dSmsaitoh mii->mii_readreg = epe_mii_readreg;
3985689358dSmsaitoh mii->mii_writereg = epe_mii_writereg;
3995689358dSmsaitoh mii->mii_statchg = epe_statchg;
4005689358dSmsaitoh sc->sc_ec.ec_mii = mii;
401912cc31fSthorpej ifmedia_init(&mii->mii_media, IFM_IMASK, ether_mediachange,
402b480b622Sdyoung ether_mediastatus);
4035689358dSmsaitoh mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
4044eeab775Sjoff MII_OFFSET_ANY, 0);
4055689358dSmsaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
4064eeab775Sjoff
4074eeab775Sjoff EPE_WRITE(BMCtl, BMCtl_RxEn | BMCtl_TxEn);
408944e317aSjoff EPE_WRITE(IntEn, IntEn_REOFIE);
4094eeab775Sjoff /* maximum valid max frame length */
4104eeab775Sjoff EPE_WRITE(MaxFrmLen, (0x7ff << 16) | MHLEN);
4114eeab775Sjoff /* wait for receiver ready */
4122300bb5cSjoerg while ((EPE_READ(BMSts) & BMSts_RxAct) == 0)
4132300bb5cSjoerg continue;
4144eeab775Sjoff /* enqueue the entries in RXStsQ and RXDQ */
415944e317aSjoff CTRLPAGE_DMASYNC(0, sc->ctrlpage_dmamap->dm_mapsize,
4164eeab775Sjoff BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
4174eeab775Sjoff EPE_WRITE(RXDEnq, RX_QLEN - 1);
4184eeab775Sjoff EPE_WRITE(RXStsEnq, RX_QLEN - 1);
4194eeab775Sjoff
4204eeab775Sjoff /*
4214eeab775Sjoff * We can support 802.1Q VLAN-sized frames.
4224eeab775Sjoff */
4234eeab775Sjoff sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
4244eeab775Sjoff
4250bc32000Smatt strcpy(ifp->if_xname, device_xname(sc->sc_dev));
426091e1526Smsaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
4274eeab775Sjoff ifp->if_ioctl = epe_ifioctl;
4284eeab775Sjoff ifp->if_start = epe_ifstart;
4294eeab775Sjoff ifp->if_watchdog = epe_ifwatchdog;
4304eeab775Sjoff ifp->if_init = epe_ifinit;
4314eeab775Sjoff ifp->if_stop = epe_ifstop;
4324eeab775Sjoff ifp->if_timer = 0;
4334eeab775Sjoff ifp->if_softc = sc;
4344eeab775Sjoff IFQ_SET_READY(&ifp->if_snd);
4354eeab775Sjoff if_attach(ifp);
43630b089e7Snonaka if_deferred_start_init(ifp, NULL);
4374eeab775Sjoff ether_ifattach(ifp, (sc)->sc_enaddr);
4384eeab775Sjoff }
4394eeab775Sjoff
4404eeab775Sjoff int
epe_mii_readreg(device_t self,int phy,int reg,uint16_t * val)441a5cdd4b4Smsaitoh epe_mii_readreg(device_t self, int phy, int reg, uint16_t *val)
4424eeab775Sjoff {
443a5cdd4b4Smsaitoh uint32_t d;
4444eeab775Sjoff
4454eeab775Sjoff d = EPE_READ(SelfCtl);
4464eeab775Sjoff EPE_WRITE(SelfCtl, d & ~SelfCtl_PSPRS); /* no preamble suppress */
4474eeab775Sjoff EPE_WRITE(MIICmd, (MIICmd_READ | (phy << 5) | reg));
4487b055612Smsaitoh while (EPE_READ(MIISts) & MIISts_BUSY)
4497b055612Smsaitoh ;
450a5cdd4b4Smsaitoh *val = EPE_READ(MIIData) & 0xffff;
4514eeab775Sjoff EPE_WRITE(SelfCtl, d); /* restore old value */
452a5cdd4b4Smsaitoh return 0;
4534eeab775Sjoff }
4544eeab775Sjoff
455a5cdd4b4Smsaitoh int
epe_mii_writereg(device_t self,int phy,int reg,uint16_t val)456a5cdd4b4Smsaitoh epe_mii_writereg(device_t self, int phy, int reg, uint16_t val)
4574eeab775Sjoff {
45808a4aba7Sskrll uint32_t d;
4594eeab775Sjoff
4604eeab775Sjoff d = EPE_READ(SelfCtl);
4614eeab775Sjoff EPE_WRITE(SelfCtl, d & ~SelfCtl_PSPRS); /* no preamble suppress */
4624eeab775Sjoff EPE_WRITE(MIIData, val);
4630f969113Shamajima EPE_WRITE(MIICmd, (MIICmd_WRITE | (phy << 5) | reg));
4647b055612Smsaitoh while (EPE_READ(MIISts) & MIISts_BUSY)
4657b055612Smsaitoh ;
4664eeab775Sjoff EPE_WRITE(SelfCtl, d); /* restore old value */
467a5cdd4b4Smsaitoh
468a5cdd4b4Smsaitoh return 0;
4694eeab775Sjoff }
4704eeab775Sjoff
4714eeab775Sjoff void
epe_statchg(struct ifnet * ifp)4720bc32000Smatt epe_statchg(struct ifnet *ifp)
4734eeab775Sjoff {
4740bc32000Smatt struct epe_softc *sc = ifp->if_softc;
47508a4aba7Sskrll uint32_t reg;
4764eeab775Sjoff
4774eeab775Sjoff /*
4784eeab775Sjoff * We must keep the MAC and the PHY in sync as
4794eeab775Sjoff * to the status of full-duplex!
4804eeab775Sjoff */
4814eeab775Sjoff reg = EPE_READ(TestCtl);
4824eeab775Sjoff if (sc->sc_mii.mii_media_active & IFM_FDX)
4834eeab775Sjoff reg |= TestCtl_MFDX;
4844eeab775Sjoff else
4854eeab775Sjoff reg &= ~TestCtl_MFDX;
4864eeab775Sjoff EPE_WRITE(TestCtl, reg);
4874eeab775Sjoff }
4884eeab775Sjoff
4894eeab775Sjoff void
epe_tick(void * arg)490454af1c0Sdsl epe_tick(void *arg)
4914eeab775Sjoff {
4924eeab775Sjoff struct epe_softc* sc = (struct epe_softc *)arg;
4934eeab775Sjoff struct ifnet * ifp = &sc->sc_ec.ec_if;
494944e317aSjoff int s;
49508a4aba7Sskrll uint32_t misses;
4964eeab775Sjoff
49745fddbdaSskrll if_statadd(ifp, if_collisions, EPE_READ(TXCollCnt));
4984eeab775Sjoff /* These misses are ok, they will happen if the RAM/CPU can't keep up */
4994eeab775Sjoff misses = EPE_READ(RXMissCnt);
5004eeab775Sjoff if (misses > 0)
5010bc32000Smatt printf("%s: %d rx misses\n", device_xname(sc->sc_dev), misses);
5024eeab775Sjoff
503944e317aSjoff s = splnet();
504944e317aSjoff if (epe_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) {
505944e317aSjoff epe_ifstart(ifp);
506944e317aSjoff }
507944e317aSjoff splx(s);
508944e317aSjoff
5094eeab775Sjoff mii_tick(&sc->sc_mii);
5104eeab775Sjoff callout_reset(&sc->epe_tick_ch, hz, epe_tick, sc);
5114eeab775Sjoff }
5124eeab775Sjoff
5134eeab775Sjoff
5144eeab775Sjoff static int
epe_ifioctl(struct ifnet * ifp,u_long cmd,void * data)515454af1c0Sdsl epe_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
5164eeab775Sjoff {
5174eeab775Sjoff int s, error;
5184eeab775Sjoff
5194eeab775Sjoff s = splnet();
5204eeab775Sjoff error = ether_ioctl(ifp, cmd, data);
5214eeab775Sjoff if (error == ENETRESET) {
5224eeab775Sjoff if (ifp->if_flags & IFF_RUNNING)
5234eeab775Sjoff epe_setaddr(ifp);
5244eeab775Sjoff error = 0;
5254eeab775Sjoff }
5264eeab775Sjoff splx(s);
5274eeab775Sjoff return error;
5284eeab775Sjoff }
5294eeab775Sjoff
5304eeab775Sjoff static void
epe_ifstart(struct ifnet * ifp)531454af1c0Sdsl epe_ifstart(struct ifnet *ifp)
5324eeab775Sjoff {
5334eeab775Sjoff struct epe_softc *sc = (struct epe_softc *)ifp->if_softc;
5344eeab775Sjoff struct mbuf *m;
5354eeab775Sjoff bus_dma_segment_t *segs;
536944e317aSjoff int s, bi, err, nsegs, ndq;
5374eeab775Sjoff
5384eeab775Sjoff s = splnet();
539944e317aSjoff start:
540944e317aSjoff ndq = 0;
5414eeab775Sjoff if (sc->TXDQ_avail == 0) {
542944e317aSjoff if (epe_gctx(sc) == 0) {
543944e317aSjoff /* Enable End-Of-TX-Chain interrupt */
544944e317aSjoff EPE_WRITE(IntEn, IntEn_REOFIE | IntEn_ECIE);
54540db1b6eSthorpej sc->tx_busy = true;
546944e317aSjoff ifp->if_timer = 10;
5474eeab775Sjoff splx(s);
5484eeab775Sjoff return;
5494eeab775Sjoff }
550944e317aSjoff }
551944e317aSjoff
5524eeab775Sjoff bi = sc->TXDQ_cur - sc->TXDQ;
5534eeab775Sjoff
5544eeab775Sjoff IFQ_POLL(&ifp->if_snd, m);
5554eeab775Sjoff if (m == NULL) {
5564eeab775Sjoff splx(s);
5574eeab775Sjoff return;
5584eeab775Sjoff }
559944e317aSjoff more:
5604eeab775Sjoff if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m,
5614eeab775Sjoff BUS_DMA_NOWAIT)) ||
5624eeab775Sjoff sc->txq[bi].m_dmamap->dm_segs[0].ds_addr & 0x3 ||
5634eeab775Sjoff sc->txq[bi].m_dmamap->dm_nsegs > (sc->TXDQ_avail - ndq)) {
5644eeab775Sjoff /* Copy entire mbuf chain to new and 32-bit aligned storage */
5654eeab775Sjoff struct mbuf *mn;
5664eeab775Sjoff
5674eeab775Sjoff if (err == 0)
5684eeab775Sjoff bus_dmamap_unload(sc->sc_dmat, sc->txq[bi].m_dmamap);
5694eeab775Sjoff
5704eeab775Sjoff MGETHDR(mn, M_DONTWAIT, MT_DATA);
5714eeab775Sjoff if (mn == NULL) goto stop;
5724eeab775Sjoff if (m->m_pkthdr.len > (MHLEN & (~0x3))) {
5734eeab775Sjoff MCLGET(mn, M_DONTWAIT);
5744eeab775Sjoff if ((mn->m_flags & M_EXT) == 0) {
5754eeab775Sjoff m_freem(mn);
5764eeab775Sjoff goto stop;
5774eeab775Sjoff }
5784eeab775Sjoff }
57908a4aba7Sskrll mn->m_data = (void *)(((uint32_t)mn->m_data + 0x3) & (~0x3));
58053524e44Schristos m_copydata(m, 0, m->m_pkthdr.len, mtod(mn, void *));
5814eeab775Sjoff mn->m_pkthdr.len = mn->m_len = m->m_pkthdr.len;
5824eeab775Sjoff IFQ_DEQUEUE(&ifp->if_snd, m);
5834eeab775Sjoff m_freem(m);
5844eeab775Sjoff m = mn;
5854eeab775Sjoff bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m,
5864eeab775Sjoff BUS_DMA_NOWAIT);
5874eeab775Sjoff } else {
5884eeab775Sjoff IFQ_DEQUEUE(&ifp->if_snd, m);
5894eeab775Sjoff }
5904eeab775Sjoff
5913cd62456Smsaitoh bpf_mtap(ifp, m, BPF_D_OUT);
5924eeab775Sjoff
5934eeab775Sjoff nsegs = sc->txq[bi].m_dmamap->dm_nsegs;
5944eeab775Sjoff segs = sc->txq[bi].m_dmamap->dm_segs;
5954eeab775Sjoff bus_dmamap_sync(sc->sc_dmat, sc->txq[bi].m_dmamap, 0,
5964eeab775Sjoff sc->txq[bi].m_dmamap->dm_mapsize,
5974eeab775Sjoff BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5984eeab775Sjoff
5994eeab775Sjoff /* XXX: This driver hasn't been tested w/nsegs > 1 */
6004eeab775Sjoff while (nsegs > 0) {
6014eeab775Sjoff nsegs--;
6024eeab775Sjoff sc->txq[bi].m = m;
6034eeab775Sjoff sc->TXDQ[bi * 2] = segs->ds_addr;
6044eeab775Sjoff if (nsegs == 0)
6054eeab775Sjoff sc->TXDQ[bi * 2 + 1] = segs->ds_len | (bi << 16) |
6064eeab775Sjoff (1 << 31);
6074eeab775Sjoff else
6084eeab775Sjoff sc->TXDQ[bi * 2 + 1] = segs->ds_len | (bi << 16);
6094eeab775Sjoff segs++;
6104eeab775Sjoff bi = (bi + 1) % TX_QLEN;
6114eeab775Sjoff ndq++;
6124eeab775Sjoff }
6134eeab775Sjoff
6144eeab775Sjoff
615944e317aSjoff /*
616944e317aSjoff * Enqueue another. Don't do more than half the available
617944e317aSjoff * descriptors before telling the MAC about them
618944e317aSjoff */
619944e317aSjoff if ((sc->TXDQ_avail - ndq) > 0 && ndq < TX_QLEN / 2) {
6204eeab775Sjoff IFQ_POLL(&ifp->if_snd, m);
6217b055612Smsaitoh if (m != NULL)
622944e317aSjoff goto more;
6234eeab775Sjoff }
6244eeab775Sjoff stop:
6254eeab775Sjoff if (ndq > 0) {
6264eeab775Sjoff sc->TXDQ_avail -= ndq;
6274eeab775Sjoff sc->TXDQ_cur = &sc->TXDQ[bi];
62808a4aba7Sskrll CTRLPAGE_DMASYNC(0, TX_QLEN * 2 * sizeof(uint32_t),
6294eeab775Sjoff BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
6304eeab775Sjoff EPE_WRITE(TXDEnq, ndq);
6314eeab775Sjoff }
6324eeab775Sjoff
633944e317aSjoff if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
634944e317aSjoff goto start;
635944e317aSjoff
636944e317aSjoff splx(s);
6374eeab775Sjoff return;
6384eeab775Sjoff }
6394eeab775Sjoff
6404eeab775Sjoff static void
epe_ifwatchdog(struct ifnet * ifp)641454af1c0Sdsl epe_ifwatchdog(struct ifnet *ifp)
6424eeab775Sjoff {
6434eeab775Sjoff struct epe_softc *sc = (struct epe_softc *)ifp->if_softc;
6444eeab775Sjoff
6454eeab775Sjoff if ((ifp->if_flags & IFF_RUNNING) == 0)
6464eeab775Sjoff return;
6474eeab775Sjoff printf("%s: device timeout, BMCtl = 0x%08x, BMSts = 0x%08x\n",
6480bc32000Smatt device_xname(sc->sc_dev), EPE_READ(BMCtl), EPE_READ(BMSts));
6494eeab775Sjoff }
6504eeab775Sjoff
6514eeab775Sjoff static int
epe_ifinit(struct ifnet * ifp)652454af1c0Sdsl epe_ifinit(struct ifnet *ifp)
6534eeab775Sjoff {
6544eeab775Sjoff struct epe_softc *sc = ifp->if_softc;
655b480b622Sdyoung int rc, s = splnet();
6564eeab775Sjoff
6574eeab775Sjoff callout_stop(&sc->epe_tick_ch);
6584eeab775Sjoff EPE_WRITE(RXCtl, RXCtl_IA0 | RXCtl_BA | RXCtl_RCRCA | RXCtl_SRxON);
6594eeab775Sjoff EPE_WRITE(TXCtl, TXCtl_STxON);
6604eeab775Sjoff EPE_WRITE(GIIntMsk, GIIntMsk_INT); /* start interrupting */
661b480b622Sdyoung
662b480b622Sdyoung if ((rc = mii_mediachg(&sc->sc_mii)) == ENXIO)
663b480b622Sdyoung rc = 0;
664b480b622Sdyoung else if (rc != 0)
665b480b622Sdyoung goto out;
666b480b622Sdyoung
6674eeab775Sjoff callout_reset(&sc->epe_tick_ch, hz, epe_tick, sc);
6684eeab775Sjoff ifp->if_flags |= IFF_RUNNING;
669b480b622Sdyoung out:
6704eeab775Sjoff splx(s);
6714eeab775Sjoff return 0;
6724eeab775Sjoff }
6734eeab775Sjoff
6744eeab775Sjoff static void
epe_ifstop(struct ifnet * ifp,int disable)675454af1c0Sdsl epe_ifstop(struct ifnet *ifp, int disable)
6764eeab775Sjoff {
6774eeab775Sjoff struct epe_softc *sc = ifp->if_softc;
6784eeab775Sjoff
6794eeab775Sjoff
6804eeab775Sjoff EPE_WRITE(RXCtl, 0);
6814eeab775Sjoff EPE_WRITE(TXCtl, 0);
6824eeab775Sjoff EPE_WRITE(GIIntMsk, 0);
6834eeab775Sjoff callout_stop(&sc->epe_tick_ch);
6844eeab775Sjoff
6854eeab775Sjoff /* Down the MII. */
6864eeab775Sjoff mii_down(&sc->sc_mii);
6874eeab775Sjoff
68840db1b6eSthorpej ifp->if_flags &= ~IFF_RUNNING;
6894eeab775Sjoff ifp->if_timer = 0;
6904eeab775Sjoff sc->sc_mii.mii_media_status &= ~IFM_ACTIVE;
6914eeab775Sjoff }
6924eeab775Sjoff
6934eeab775Sjoff static void
epe_setaddr(struct ifnet * ifp)694454af1c0Sdsl epe_setaddr(struct ifnet *ifp)
6954eeab775Sjoff {
6964eeab775Sjoff struct epe_softc *sc = ifp->if_softc;
6977b055612Smsaitoh struct ethercom *ec = &sc->sc_ec;
6984eeab775Sjoff struct ether_multi *enm;
6994eeab775Sjoff struct ether_multistep step;
70008a4aba7Sskrll uint8_t ias[2][ETHER_ADDR_LEN];
70108a4aba7Sskrll uint32_t h, nma = 0, hashes[2] = { 0, 0 };
70208a4aba7Sskrll uint32_t rxctl = EPE_READ(RXCtl);
7034eeab775Sjoff
7044eeab775Sjoff /* disable receiver temporarily */
7054eeab775Sjoff EPE_WRITE(RXCtl, rxctl & ~RXCtl_SRxON);
7064eeab775Sjoff
7074eeab775Sjoff rxctl &= ~(RXCtl_MA | RXCtl_PA | RXCtl_IA2 | RXCtl_IA3);
7084eeab775Sjoff
7097b055612Smsaitoh if (ifp->if_flags & IFF_PROMISC)
7104eeab775Sjoff rxctl |= RXCtl_PA;
7114eeab775Sjoff
7124eeab775Sjoff ifp->if_flags &= ~IFF_ALLMULTI;
7134eeab775Sjoff
71483759283Smsaitoh ETHER_LOCK(ec);
7157b055612Smsaitoh ETHER_FIRST_MULTI(step, ec, enm);
7164eeab775Sjoff while (enm != NULL) {
7174eeab775Sjoff if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
7184eeab775Sjoff /*
7194eeab775Sjoff * We must listen to a range of multicast addresses.
7204eeab775Sjoff * For now, just accept all multicasts, rather than
7214eeab775Sjoff * trying to set only those filter bits needed to match
7224eeab775Sjoff * the range. (At this time, the only use of address
7234eeab775Sjoff * ranges is for IP multicast routing, for which the
7244eeab775Sjoff * range is big enough to require all bits set.)
7254eeab775Sjoff */
7264eeab775Sjoff rxctl &= ~(RXCtl_IA2 | RXCtl_IA3);
7274eeab775Sjoff rxctl |= RXCtl_MA;
7284eeab775Sjoff hashes[0] = 0xffffffffUL;
7294eeab775Sjoff hashes[1] = 0xffffffffUL;
7304eeab775Sjoff ifp->if_flags |= IFF_ALLMULTI;
7314eeab775Sjoff break;
7324eeab775Sjoff }
7334eeab775Sjoff
7344eeab775Sjoff if (nma < 2) {
7354eeab775Sjoff /* We can program 2 perfect address filters for mcast */
7364eeab775Sjoff memcpy(ias[nma], enm->enm_addrlo, ETHER_ADDR_LEN);
7374eeab775Sjoff rxctl |= (1 << (nma + 2));
7384eeab775Sjoff } else {
7394eeab775Sjoff /*
7404eeab775Sjoff * XXX: Datasheet is not very clear here, I'm not sure
7414eeab775Sjoff * if I'm doing this right. --joff
7424eeab775Sjoff */
7434eeab775Sjoff h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
7444eeab775Sjoff
7454eeab775Sjoff /* Just want the 6 most-significant bits. */
7464eeab775Sjoff h = h >> 26;
7474eeab775Sjoff
7484eeab775Sjoff hashes[ h / 32 ] |= (1 << (h % 32));
7494eeab775Sjoff rxctl |= RXCtl_MA;
7504eeab775Sjoff }
7514eeab775Sjoff ETHER_NEXT_MULTI(step, enm);
7524eeab775Sjoff nma++;
7534eeab775Sjoff }
75483759283Smsaitoh ETHER_UNLOCK(ec);
7554eeab775Sjoff
7564eeab775Sjoff EPE_WRITE(AFP, 0);
7574eeab775Sjoff bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
7584eeab775Sjoff sc->sc_enaddr, ETHER_ADDR_LEN);
7594eeab775Sjoff if (rxctl & RXCtl_IA2) {
7604eeab775Sjoff EPE_WRITE(AFP, 2);
7614eeab775Sjoff bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
7624eeab775Sjoff ias[0], ETHER_ADDR_LEN);
7634eeab775Sjoff }
7644eeab775Sjoff if (rxctl & RXCtl_IA3) {
7654eeab775Sjoff EPE_WRITE(AFP, 3);
7664eeab775Sjoff bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
7674eeab775Sjoff ias[1], ETHER_ADDR_LEN);
7684eeab775Sjoff }
7694eeab775Sjoff if (hashes[0] != 0 && hashes[1] != 0) {
7704eeab775Sjoff EPE_WRITE(AFP, 7);
7714eeab775Sjoff EPE_WRITE(HashTbl, hashes[0]);
7724eeab775Sjoff EPE_WRITE(HashTbl + 4, hashes[1]);
7734eeab775Sjoff }
7744eeab775Sjoff EPE_WRITE(RXCtl, rxctl);
7754eeab775Sjoff }
776