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