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