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