xref: /netbsd-src/sys/arch/playstation2/dev/if_smap.c (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
1 /*	$NetBSD: if_smap.c,v 1.32 2020/01/29 05:32:04 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_smap.c,v 1.32 2020/01/29 05:32:04 thorpej Exp $");
34 
35 #include "debug_playstation2.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/syslog.h>
41 #include <sys/mbuf.h>
42 #include <sys/ioctl.h>
43 #include <sys/rndsource.h>
44 #include <sys/socket.h>
45 
46 #include <playstation2/ee/eevar.h>
47 
48 #include <net/if.h>
49 #include <net/if_dl.h>
50 #include <net/if_types.h>
51 #include <net/if_ether.h>
52 #include <net/if_media.h>
53 #include <net/bpf.h>
54 
55 #include <dev/mii/miivar.h>
56 
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/if_inarp.h>
62 
63 #include <playstation2/dev/spdvar.h>
64 #include <playstation2/dev/spdreg.h>
65 #include <playstation2/dev/emac3var.h>
66 #include <playstation2/dev/if_smapreg.h>
67 
68 #ifdef SMAP_DEBUG
69 #include <playstation2/ee/gsvar.h>
70 int	smap_debug = 0;
71 #define	DPRINTF(fmt, args...)						\
72 	if (smap_debug)							\
73 		printf("%s: " fmt, __func__ , ##args)
74 #define	DPRINTFN(n, arg)						\
75 	if (smap_debug > (n))						\
76 		printf("%s: " fmt, __func__ , ##args)
77 #define STATIC
78 struct smap_softc *__sc;
79 void __smap_status(int);
80 void __smap_lock_check(const char *, int);
81 #define FUNC_ENTER()	__smap_lock_check(__func__, 1)
82 #define FUNC_EXIT()	__smap_lock_check(__func__, 0)
83 #else
84 #define	DPRINTF(arg...)		((void)0)
85 #define DPRINTFN(n, arg...)	((void)0)
86 #define STATIC			static
87 #define FUNC_ENTER()		((void)0)
88 #define FUNC_EXIT()		((void)0)
89 #endif
90 
91 struct smap_softc {
92 	struct emac3_softc emac3;
93 	struct ethercom ethercom;
94 
95 	u_int32_t *tx_buf;
96 	u_int32_t *rx_buf;
97 	struct smap_desc *tx_desc;
98 	struct smap_desc *rx_desc;
99 
100 #define	SMAP_FIFO_ALIGN		4
101 	int tx_buf_freesize;	/* buffer usage */
102 	int tx_desc_cnt;	/* descriptor usage */
103 	u_int16_t tx_fifo_ptr;
104 	int tx_done_index, tx_start_index;
105 	int rx_done_index;
106 
107 	krndsource_t rnd_source;
108 };
109 
110 #define DEVNAME		(sc->emac3.dev.dv_xname)
111 #define ROUND4(x)	(((x) + 3) & ~3)
112 #define ROUND16(x)	(((x) + 15) & ~15)
113 
114 STATIC int smap_match(struct device *, struct cfdata *, void *);
115 STATIC void smap_attach(struct device *, struct device *, void *);
116 
117 CFATTACH_DECL_NEW(smap, sizeof (struct smap_softc),
118     smap_match, smap_attach, NULL, NULL);
119 
120 STATIC int smap_intr(void *);
121 STATIC void smap_rxeof(void *);
122 STATIC void smap_txeof(void *);
123 STATIC void smap_start(struct ifnet *);
124 STATIC void smap_watchdog(struct ifnet *);
125 STATIC int smap_ioctl(struct ifnet *, u_long, void *);
126 STATIC int smap_init(struct ifnet *);
127 STATIC void smap_stop(struct ifnet *, int);
128 
129 STATIC int smap_get_eaddr(struct smap_softc *, u_int8_t *);
130 STATIC int smap_fifo_init(struct smap_softc *);
131 STATIC int smap_fifo_reset(bus_addr_t);
132 STATIC void smap_desc_init(struct smap_softc *);
133 
134 int
135 smap_match(struct device *parent, struct cfdata *cf, void *aux)
136 {
137 	struct spd_attach_args *spa = aux;
138 
139 	if (spa->spa_slot != SPD_NIC)
140 		return (0);
141 
142 	return (1);
143 }
144 
145 void
146 smap_attach(struct device *parent, struct device *self, void *aux)
147 {
148 	struct spd_attach_args *spa = aux;
149 	struct smap_softc *sc = (void *)self;
150 	struct emac3_softc *emac3 = &sc->emac3;
151 	struct ifnet *ifp = &sc->ethercom.ec_if;
152 	struct mii_data *mii = &emac3->mii;
153 	void *txbuf, *rxbuf;
154 	u_int16_t r;
155 
156 #ifdef SMAP_DEBUG
157 	__sc = sc;
158 #endif
159 
160 	printf(": %s\n", spa->spa_product_name);
161 
162 	/* SPD EEPROM */
163 	if (smap_get_eaddr(sc, emac3->eaddr) != 0)
164 		return;
165 
166 	printf("%s: Ethernet address %s\n", DEVNAME,
167 	    ether_sprintf(emac3->eaddr));
168 
169 	/* disable interrupts */
170 	r = _reg_read_2(SPD_INTR_ENABLE_REG16);
171 	r &= ~(SPD_INTR_RXEND | SPD_INTR_TXEND | SPD_INTR_RXDNV |
172 	    SPD_INTR_EMAC3);
173 	_reg_write_2(SPD_INTR_ENABLE_REG16, r);
174 	emac3_intr_disable();
175 
176 	/* clear pending interrupts */
177 	_reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND |
178 	    SPD_INTR_RXDNV);
179 	emac3_intr_clear();
180 
181 	/* buffer descriptor mode */
182 	_reg_write_1(SMAP_DESC_MODE_REG8, 0);
183 
184 	if (smap_fifo_init(sc) != 0)
185 		return;
186 
187 	if (emac3_init(&sc->emac3) != 0)
188 		return;
189 	emac3_intr_disable();
190 	emac3_disable();
191 
192 	smap_desc_init(sc);
193 
194 	/* allocate temporary buffer */
195 	txbuf = malloc(ETHER_MAX_LEN - ETHER_CRC_LEN + SMAP_FIFO_ALIGN + 16,
196 	    M_DEVBUF, M_WAITOK);
197 	rxbuf = malloc(ETHER_MAX_LEN + SMAP_FIFO_ALIGN + 16,
198 	    M_DEVBUF, M_WAITOK);
199 	sc->tx_buf = (u_int32_t *)ROUND16((vaddr_t)txbuf);
200 	sc->rx_buf = (u_int32_t *)ROUND16((vaddr_t)rxbuf);
201 
202 	/*
203 	 * setup MI layer
204 	 */
205 	strcpy(ifp->if_xname, DEVNAME);
206 	ifp->if_softc	= sc;
207 	ifp->if_start	= smap_start;
208 	ifp->if_ioctl	= smap_ioctl;
209 	ifp->if_init	= smap_init;
210 	ifp->if_stop	= smap_stop;
211 	ifp->if_watchdog= smap_watchdog;
212 	ifp->if_flags	= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
213 	IFQ_SET_READY(&ifp->if_snd);
214 
215 	/* ifmedia setup. */
216 	mii->mii_ifp		= ifp;
217 	mii->mii_readreg	= emac3_phy_readreg;
218 	mii->mii_writereg	= emac3_phy_writereg;
219 	mii->mii_statchg	= emac3_phy_statchg;
220 	sc->ethercom.ec_mii = mii;
221 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
222 	mii_attach(&emac3->dev, mii, 0xffffffff, MII_PHY_ANY,
223 	    MII_OFFSET_ANY, 0);
224 
225 	/* Choose a default media. */
226 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
227 		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
228 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
229 	} else {
230 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
231 	}
232 
233 	if_attach(ifp);
234 	if_deferred_start_init(ifp, NULL);
235 	ether_ifattach(ifp, emac3->eaddr);
236 
237 	spd_intr_establish(SPD_NIC, smap_intr, sc);
238 
239 	rnd_attach_source(&sc->rnd_source, DEVNAME,
240 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
241 }
242 
243 int
244 smap_ioctl(struct ifnet *ifp, u_long command, void *data)
245 {
246 	struct smap_softc *sc = ifp->if_softc;
247 	int error, s;
248 
249 	s = splnet();
250 
251 	error = ether_ioctl(ifp, command, data);
252 
253 	if (error == ENETRESET) {
254 		if (ifp->if_flags & IFF_RUNNING)
255 			emac3_setmulti(&sc->emac3, &sc->ethercom);
256 		error = 0;
257 	}
258 
259 	splx(s);
260 
261 	return (error);
262 }
263 
264 int
265 smap_intr(void *arg)
266 {
267 	struct smap_softc *sc = arg;
268 	struct ifnet *ifp;
269 	u_int16_t cause, disable, r;
270 
271 	cause = _reg_read_2(SPD_INTR_STATUS_REG16) &
272 	    _reg_read_2(SPD_INTR_ENABLE_REG16);
273 
274 	disable = cause & (SPD_INTR_RXDNV | SPD_INTR_TXDNV);
275 	if (disable) {
276 		r = _reg_read_2(SPD_INTR_ENABLE_REG16);
277 		r &= ~disable;
278 		_reg_write_2(SPD_INTR_ENABLE_REG16, r);
279 
280 		printf("%s: invalid descriptor. (%c%c)\n", DEVNAME,
281 		    disable & SPD_INTR_RXDNV ? 'R' : '_',
282 		    disable & SPD_INTR_TXDNV ? 'T' : '_');
283 
284 		if (disable & SPD_INTR_RXDNV)
285 			smap_rxeof(arg);
286 
287 		_reg_write_2(SPD_INTR_CLEAR_REG16, disable);
288 	}
289 
290 	if (cause & SPD_INTR_TXEND) {
291 		_reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_TXEND);
292 		if (_reg_read_1(SMAP_RXFIFO_FRAME_REG8) > 0)
293 			cause |= SPD_INTR_RXEND;
294 		smap_txeof(arg);
295 	}
296 
297 	if (cause & SPD_INTR_RXEND) {
298 		_reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND);
299 		smap_rxeof(arg);
300 		if (sc->tx_desc_cnt > 0 &&
301 		    sc->tx_desc_cnt > _reg_read_1(SMAP_TXFIFO_FRAME_REG8))
302 			smap_txeof(arg);
303 	}
304 
305 	if (cause & SPD_INTR_EMAC3)
306 		emac3_intr(arg);
307 
308 	/* if transmission is pending, start here */
309 	ifp = &sc->ethercom.ec_if;
310 	if_schedule_deferred_start(ifp);
311 	rnd_add_uint32(&sc->rnd_source, cause | sc->tx_fifo_ptr << 16);
312 
313 	return (1);
314 }
315 
316 void
317 smap_rxeof(void *arg)
318 {
319 	struct smap_softc *sc = arg;
320 	struct smap_desc *d;
321 	struct ifnet *ifp = &sc->ethercom.ec_if;
322 	struct mbuf *m;
323 	u_int16_t r16, stat;
324 	u_int32_t *p;
325 	int i, j, sz, rxsz, cnt;
326 
327 	FUNC_ENTER();
328 
329 	i = sc->rx_done_index;
330 
331 	for (cnt = 0;; cnt++, i = (i + 1) & 0x3f) {
332 		m = NULL;
333 		d = &sc->rx_desc[i];
334 		stat = d->stat;
335 
336 		if ((stat & SMAP_RXDESC_EMPTY) != 0) {
337 			break;
338 		} else if (stat & 0x7fff) {
339 			if_statinc(ifp, if_ierrors);
340 			goto next_packet;
341 		}
342 
343 		sz = d->sz;
344 		rxsz = ROUND4(sz);
345 
346 		KDASSERT(sz >= ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN);
347 		KDASSERT(sz <= ETHER_MAX_LEN);
348 
349 		/* load data from FIFO */
350 		_reg_write_2(SMAP_RXFIFO_PTR_REG16, d->ptr & 0x3ffc);
351 		p = sc->rx_buf;
352 		for (j = 0; j < rxsz; j += sizeof(u_int32_t)) {
353 			*p++ = _reg_read_4(SMAP_RXFIFO_DATA_REG);
354 		}
355 
356 		/* put to mbuf */
357 		MGETHDR(m, M_DONTWAIT, MT_DATA);
358 		if (m == NULL) {
359 			printf("%s: unable to allocate Rx mbuf\n", DEVNAME);
360 			if_statinc(ifp, if_ierrors);
361 			goto next_packet;
362 		}
363 
364 		if (sz > (MHLEN - 2)) {
365 			MCLGET(m, M_DONTWAIT);
366 			if ((m->m_flags & M_EXT) == 0) {
367 				printf("%s: unable to allocate Rx cluster\n",
368 				    DEVNAME);
369 				m_freem(m);
370 				m = NULL;
371 				if_statinc(ifp, if_ierrors);
372 				goto next_packet;
373 			}
374 		}
375 
376 		m->m_data += 2; /* for alignment */
377 		m_set_rcvif(m, ifp);
378 		m->m_pkthdr.len = m->m_len = sz;
379 		memcpy(mtod(m, void *), (void *)sc->rx_buf, sz);
380 
381 	next_packet:
382 		_reg_write_1(SMAP_RXFIFO_FRAME_DEC_REG8, 1);
383 
384 		/* free descriptor */
385 		d->sz	= 0;
386 		d->ptr	= 0;
387 		d->stat	= SMAP_RXDESC_EMPTY;
388 		_wbflush();
389 
390 		if (m != NULL)
391 			if_percpuq_enqueue(ifp->if_percpuq, m);
392 	}
393 	sc->rx_done_index = i;
394 
395 	r16 = _reg_read_2(SPD_INTR_ENABLE_REG16);
396 	if (((r16 & SPD_INTR_RXDNV) == 0) && cnt > 0) {
397 		r16  |= SPD_INTR_RXDNV;
398 		_reg_write_2(SPD_INTR_ENABLE_REG16, r16);
399 	}
400 
401 	FUNC_EXIT();
402 }
403 
404 void
405 smap_txeof(void *arg)
406 {
407 	struct smap_softc *sc = arg;
408 	struct ifnet *ifp = &sc->ethercom.ec_if;
409 	struct smap_desc *d;
410 	int i;
411 
412 	FUNC_ENTER();
413 
414 	/* clear the timeout timer. */
415 	ifp->if_timer = 0;
416 
417 	/* garbage collect */
418 	for (i = sc->tx_done_index;; i = (i + 1) & 0x3f) {
419 		u_int16_t stat;
420 
421 		d = &sc->tx_desc[i];
422 		stat = d->stat;
423 		if (stat & SMAP_TXDESC_READY) {
424 			/* all descriptor processed. */
425 			break;
426 		} else if (stat & 0x7fff) {
427 			if (stat & (SMAP_TXDESC_ECOLL | SMAP_TXDESC_LCOLL |
428 			    SMAP_TXDESC_MCOLL | SMAP_TXDESC_SCOLL))
429 				if_statinc(ifp, if_collisions);
430 			else
431 				if_statinc(ifp, if_oerrors);
432 		} else {
433 			if_statinc(ifp, if_opackets);
434 		}
435 
436 		if (sc->tx_desc_cnt == 0)
437 			break;
438 
439 		sc->tx_buf_freesize += ROUND4(d->sz);
440 		sc->tx_desc_cnt--;
441 
442 		d->sz = 0;
443 		d->ptr = 0;
444 		d->stat = 0;
445 		_wbflush();
446 	}
447 	sc->tx_done_index = i;
448 
449 	/* OK to start transmit */
450 	ifp->if_flags &= ~IFF_OACTIVE;
451 
452 	FUNC_EXIT();
453 }
454 
455 void
456 smap_start(struct ifnet *ifp)
457 {
458 	struct smap_softc *sc = ifp->if_softc;
459 	struct smap_desc *d;
460 	struct mbuf *m0, *m;
461 	u_int8_t *p, *q;
462 	u_int32_t *r;
463 	int i, sz, pktsz;
464 	u_int16_t fifop;
465 	u_int16_t r16;
466 
467 	KDASSERT(ifp->if_flags & IFF_RUNNING);
468 	FUNC_ENTER();
469 
470 	while (1) {
471 		IFQ_POLL(&ifp->if_snd, m0);
472 		if (m0 == NULL)
473 			goto end;
474 
475 		pktsz = m0->m_pkthdr.len;
476 		KDASSERT(pktsz <= ETHER_MAX_LEN - ETHER_CRC_LEN);
477 		sz = ROUND4(pktsz);
478 
479 		if (sz > sc->tx_buf_freesize ||
480 		    sc->tx_desc_cnt >= SMAP_DESC_MAX ||
481 		    emac3_tx_done() != 0) {
482 			ifp->if_flags |= IFF_OACTIVE;
483 			goto end;
484 		}
485 
486 		IFQ_DEQUEUE(&ifp->if_snd, m0);
487 		KDASSERT(m0 != NULL);
488 		bpf_mtap(ifp, m0, BPF_D_OUT);
489 
490 		p = (u_int8_t *)sc->tx_buf;
491 		q = p + sz;
492 		/* copy to temporary buffer area */
493 		for (m = m0; m != 0; m = m->m_next) {
494 			memcpy(p, mtod(m, void *), m->m_len);
495 			p += m->m_len;
496 		}
497 		m_freem(m0);
498 
499 		/* zero padding area */
500 		for (; p < q; p++)
501 			*p = 0;
502 
503 		/* put to FIFO */
504 		fifop = sc->tx_fifo_ptr;
505 		KDASSERT((fifop & 3) == 0);
506 		_reg_write_2(SMAP_TXFIFO_PTR_REG16, fifop);
507 		sc->tx_fifo_ptr = (fifop + sz) & 0xfff;
508 
509 		r = sc->tx_buf;
510 		for (i = 0; i < sz; i += sizeof(u_int32_t))
511 			*(volatile u_int32_t *)SMAP_TXFIFO_DATA_REG = *r++;
512 		_wbflush();
513 
514 		/* put FIFO to EMAC3 */
515 		d = &sc->tx_desc[sc->tx_start_index];
516 		KDASSERT((d->stat & SMAP_TXDESC_READY) == 0);
517 
518 		d->sz = pktsz;
519 		d->ptr = fifop + SMAP_TXBUF_BASE;
520 		d->stat = SMAP_TXDESC_READY | SMAP_TXDESC_GENFCS |
521 		    SMAP_TXDESC_GENPAD;
522 		_wbflush();
523 
524 		sc->tx_buf_freesize -= sz;
525 		sc->tx_desc_cnt++;
526 		sc->tx_start_index = (sc->tx_start_index + 1) & 0x3f;
527 		_reg_write_1(SMAP_TXFIFO_FRAME_INC_REG8, 1);
528 
529 		emac3_tx_kick();
530 		r16 = _reg_read_2(SPD_INTR_ENABLE_REG16);
531 		if ((r16 & SPD_INTR_TXDNV) == 0) {
532 			r16 |= SPD_INTR_TXDNV;
533 			_reg_write_2(SPD_INTR_ENABLE_REG16, r16);
534 		}
535 	}
536  end:
537 	/* set watchdog timer */
538 	ifp->if_timer = 5;
539 
540 	FUNC_EXIT();
541 }
542 
543 void
544 smap_watchdog(struct ifnet *ifp)
545 {
546 	struct smap_softc *sc = ifp->if_softc;
547 
548 	printf("%s: watchdog timeout\n", DEVNAME);
549 	if_statinc(ifp, if_oerrors);
550 
551 	smap_fifo_init(sc);
552 	smap_desc_init(sc);
553 	emac3_reset(&sc->emac3);
554 }
555 
556 int
557 smap_init(struct ifnet *ifp)
558 {
559 	struct smap_softc *sc = ifp->if_softc;
560 	u_int16_t r16;
561 	int rc;
562 
563 	smap_fifo_init(sc);
564 	emac3_reset(&sc->emac3);
565 	smap_desc_init(sc);
566 
567 	_reg_write_2(SPD_INTR_CLEAR_REG16, SPD_INTR_RXEND | SPD_INTR_TXEND |
568 	    SPD_INTR_RXDNV);
569 	emac3_intr_clear();
570 
571 	r16 = _reg_read_2(SPD_INTR_ENABLE_REG16);
572 	r16 |=  SPD_INTR_EMAC3 | SPD_INTR_RXEND | SPD_INTR_TXEND |
573 	    SPD_INTR_RXDNV;
574 	_reg_write_2(SPD_INTR_ENABLE_REG16, r16);
575 	emac3_intr_enable();
576 
577 	emac3_enable();
578 
579 	/* Program the multicast filter, if necessary. */
580 	emac3_setmulti(&sc->emac3, &sc->ethercom);
581 
582 	/* Set current media. */
583 	if ((rc = mii_mediachg(&sc->emac3.mii)) == ENXIO)
584 		rc = 0;
585 	else if (rc != 0)
586 		return rc;
587 
588 	ifp->if_flags |= IFF_RUNNING;
589 
590 	return (0);
591 }
592 
593 void
594 smap_stop(struct ifnet *ifp, int disable)
595 {
596 	struct smap_softc *sc = ifp->if_softc;
597 
598 	mii_down(&sc->emac3.mii);
599 
600 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
601 
602 	if (disable)
603 		emac3_disable();
604 }
605 
606 /*
607  * FIFO
608  */
609 int
610 smap_fifo_init(struct smap_softc *sc)
611 {
612 
613 	if (smap_fifo_reset(SMAP_TXFIFO_CTRL_REG8) != 0)
614 		goto error;
615 
616 	if (smap_fifo_reset(SMAP_RXFIFO_CTRL_REG8) != 0)
617 		goto error;
618 
619 	return (0);
620 error:
621 	printf("%s: FIFO reset not complete.\n", DEVNAME);
622 
623 	return (1);
624 }
625 
626 int
627 smap_fifo_reset(bus_addr_t a)
628 {
629 	int retry = 10000;
630 
631 	_reg_write_1(a, SMAP_FIFO_RESET);
632 
633 	while ((_reg_read_1(a) & SMAP_FIFO_RESET) && --retry > 0)
634 		;
635 
636 	return (retry == 0);
637 }
638 
639 /*
640  * Buffer descriptor
641  */
642 void
643 smap_desc_init(struct smap_softc *sc)
644 {
645 	struct smap_desc *d;
646 	int i;
647 
648 	sc->tx_desc = (void *)SMAP_TXDESC_BASE;
649 	sc->rx_desc = (void *)SMAP_RXDESC_BASE;
650 
651 	sc->tx_buf_freesize = SMAP_TXBUF_SIZE;
652 	sc->tx_fifo_ptr = 0;
653 	sc->tx_start_index = 0;
654 	sc->tx_done_index = 0;
655 	sc->rx_done_index = 0;
656 
657 	/* initialize entry */
658 	d = sc->tx_desc;
659 	for (i = 0; i < SMAP_DESC_MAX; i++, d++) {
660 		d->stat = 0;
661 		d->__reserved = 0;
662 		d->sz = 0;
663 		d->ptr = 0;
664 	}
665 
666 	d = sc->rx_desc;
667 	for (i = 0; i < SMAP_DESC_MAX; i++, d++) {
668 		d->stat = SMAP_RXDESC_EMPTY;
669 		d->__reserved = 0;
670 		d->sz = 0;
671 		d->ptr = 0;
672 	}
673 	_wbflush();
674 }
675 
676 
677 /*
678  * EEPROM
679  */
680 int
681 smap_get_eaddr(struct smap_softc *sc, u_int8_t *eaddr)
682 {
683 	u_int16_t checksum, *p = (u_int16_t *)eaddr;
684 
685 	spd_eeprom_read(0, p, 3);
686 	spd_eeprom_read(3, &checksum, 1);
687 
688 	if (checksum != (u_int16_t)(p[0] + p[1] + p[2])) {
689 		printf("%s: Ethernet address checksum error.(%s)\n",
690 		    DEVNAME, ether_sprintf(eaddr));
691 		return (1);
692 	}
693 
694 	return (0);
695 }
696 
697 #ifdef SMAP_DEBUG
698 #include <mips/locore.h>
699 void
700 __smap_lock_check(const char *func, int enter)
701 {
702 	static int cnt;
703 	static const char *last;
704 
705 	cnt += enter ? 1 : -1;
706 
707 	if (cnt < 0 || cnt > 1)
708 		panic("%s cnt=%d last=%s", func, cnt, last);
709 
710 	last = func;
711 }
712 
713 void
714 __smap_status(int msg)
715 {
716 	static int cnt;
717 	__gsfb_print(1, "%d: tx=%d rx=%d txcnt=%d free=%d cnt=%d\n", msg,
718 	    _reg_read_1(SMAP_TXFIFO_FRAME_REG8),
719 	    _reg_read_1(SMAP_RXFIFO_FRAME_REG8), __sc->tx_desc_cnt,
720 	    __sc->tx_buf_freesize, cnt++);
721 }
722 #endif /* SMAP_DEBUG */
723