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