コード例 #1
0
/*
 * Reset interface.
 */
void
bereset(struct be_softc *sc)
{
	int s;

	s = splnet();
	bestop(sc);
	if ((sc->sc_arpcom.ac_if.if_flags & IFF_UP) != 0)
		beinit(sc);
	splx(s);
}
コード例 #2
0
ファイル: be.c プロジェクト: yazshel/netbsd-kernel
int
beioctl(struct ifnet *ifp, u_long cmd, void *data)
{
	struct be_softc *sc = ifp->if_softc;
	struct ifaddr *ifa = data;
	struct ifreq *ifr = data;
	int s, error = 0;

	s = splnet();

	switch (cmd) {
	case SIOCINITIFADDR:
		ifp->if_flags |= IFF_UP;
		beinit(ifp);
		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			arp_ifinit(ifp, ifa);
			break;
#endif /* INET */
		default:
			break;
		}
		break;

	case SIOCSIFFLAGS:
		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
			break;
		/* XXX re-use ether_ioctl() */
		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
		case IFF_RUNNING:
			/*
			 * If interface is marked down and it is running, then
			 * stop it.
			 */
			bestop(ifp, 0);
			ifp->if_flags &= ~IFF_RUNNING;
			break;
		case IFF_UP:
			/*
			 * If interface is marked up and it is stopped, then
			 * start it.
			 */
			beinit(ifp);
			break;
		default:
			/*
			 * Reset the interface to pick up changes in any other
			 * flags that affect hardware registers.
			 */
			bestop(ifp, 0);
			beinit(ifp);
			break;
		}
#ifdef BEDEBUG
		if (ifp->if_flags & IFF_DEBUG)
			sc->sc_debug = 1;
		else
			sc->sc_debug = 0;
#endif
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
		break;
	default:
		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
			/*
			 * Multicast list has changed; set the hardware filter
			 * accordingly.
			 */
			if (ifp->if_flags & IFF_RUNNING)
				error = beinit(ifp);
			else
				error = 0;
		}
		break;
	}
	splx(s);
	return error;
}
コード例 #3
0
ファイル: be.c プロジェクト: yazshel/netbsd-kernel
int
beinit(struct ifnet *ifp)
{
	struct be_softc *sc = ifp->if_softc;
	bus_space_tag_t t = sc->sc_bustag;
	bus_space_handle_t br = sc->sc_br;
	bus_space_handle_t cr = sc->sc_cr;
	struct qec_softc *qec = sc->sc_qec;
	uint32_t v;
	uint32_t qecaddr;
	uint8_t *ea;
	int rc, s;

	s = splnet();

	qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);

	bestop(ifp, 1);

	ea = sc->sc_enaddr;
	bus_space_write_4(t, br, BE_BRI_MACADDR0, (ea[0] << 8) | ea[1]);
	bus_space_write_4(t, br, BE_BRI_MACADDR1, (ea[2] << 8) | ea[3]);
	bus_space_write_4(t, br, BE_BRI_MACADDR2, (ea[4] << 8) | ea[5]);

	/* Clear hash table */
	bus_space_write_4(t, br, BE_BRI_HASHTAB0, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB1, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB2, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB3, 0);

	/* Re-initialize RX configuration */
	v = BE_BR_RXCFG_FIFO;
	bus_space_write_4(t, br, BE_BRI_RXCFG, v);

	be_mcreset(sc);

	bus_space_write_4(t, br, BE_BRI_RANDSEED, 0xbd);

	bus_space_write_4(t, br,
	    BE_BRI_XIFCFG, BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV);

	bus_space_write_4(t, br, BE_BRI_JSIZE, 4);

	/*
	 * Turn off counter expiration interrupts as well as
	 * 'gotframe' and 'sentframe'
	 */
	bus_space_write_4(t, br, BE_BRI_IMASK,
	    BE_BR_IMASK_GOTFRAME |
	    BE_BR_IMASK_RCNTEXP |
	    BE_BR_IMASK_ACNTEXP |
	    BE_BR_IMASK_CCNTEXP |
	    BE_BR_IMASK_LCNTEXP |
	    BE_BR_IMASK_CVCNTEXP |
	    BE_BR_IMASK_SENTFRAME |
	    BE_BR_IMASK_NCNTEXP |
	    BE_BR_IMASK_ECNTEXP |
	    BE_BR_IMASK_LCCNTEXP |
	    BE_BR_IMASK_FCNTEXP |
	    BE_BR_IMASK_DTIMEXP);

	/* Channel registers: */
	bus_space_write_4(t, cr, BE_CRI_RXDS, (uint32_t)sc->sc_rb.rb_rxddma);
	bus_space_write_4(t, cr, BE_CRI_TXDS, (uint32_t)sc->sc_rb.rb_txddma);

	qecaddr = sc->sc_channel * qec->sc_msize;
	bus_space_write_4(t, cr, BE_CRI_RXWBUF, qecaddr);
	bus_space_write_4(t, cr, BE_CRI_RXRBUF, qecaddr);
	bus_space_write_4(t, cr, BE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
	bus_space_write_4(t, cr, BE_CRI_TXRBUF, qecaddr + qec->sc_rsize);

	bus_space_write_4(t, cr, BE_CRI_RIMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_TIMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_QMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_BMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_CCNT, 0);

	/* Set max packet length */
	v = ETHER_MAX_LEN;
	if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU)
		v += ETHER_VLAN_ENCAP_LEN;
	bus_space_write_4(t, br, BE_BRI_RXMAX, v);
	bus_space_write_4(t, br, BE_BRI_TXMAX, v);

	/* Enable transmitter */
	bus_space_write_4(t, br,
	    BE_BRI_TXCFG, BE_BR_TXCFG_FIFO | BE_BR_TXCFG_ENABLE);

	/* Enable receiver */
	v = bus_space_read_4(t, br, BE_BRI_RXCFG);
	v |= BE_BR_RXCFG_FIFO | BE_BR_RXCFG_ENABLE;
	bus_space_write_4(t, br, BE_BRI_RXCFG, v);

	if ((rc = be_ifmedia_upd(ifp)) != 0)
		goto out;

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	callout_reset(&sc->sc_tick_ch, hz, be_tick, sc);

	return 0;
out:
	splx(s);
	return rc;
}
コード例 #4
0
int
beioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct be_softc *sc = ifp->if_softc;
	struct ifaddr *ifa = (struct ifaddr *)data;
	struct ifreq *ifr = (struct ifreq *)data;
	int s, error = 0;

	s = splnet();

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			beinit(sc);
			arp_ifinit(&sc->sc_arpcom, ifa);
			break;
#endif /* INET */
		default:
			beinit(sc);
			break;
		}
		break;

	case SIOCSIFFLAGS:
		if ((ifp->if_flags & IFF_UP) == 0 &&
		    (ifp->if_flags & IFF_RUNNING) != 0) {
			/*
			 * If interface is marked down and it is running, then
			 * stop it.
			 */
			bestop(sc);
			ifp->if_flags &= ~IFF_RUNNING;
		} else if ((ifp->if_flags & IFF_UP) != 0 &&
		    (ifp->if_flags & IFF_RUNNING) == 0) {
			/*
			 * If interface is marked up and it is stopped, then
			 * start it.
			 */
			beinit(sc);
		} else {
			/*
			 * Reset the interface to pick up changes in any other
			 * flags that affect hardware registers.
			 */
			bestop(sc);
			beinit(sc);
		}
#ifdef BEDEBUG
		if (ifp->if_flags & IFF_DEBUG)
			sc->sc_debug = 1;
		else
			sc->sc_debug = 0;
#endif
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			be_mcreset(sc);
		error = 0;
	}

	splx(s);
	return (error);
}
コード例 #5
0
void
beattach(struct device *parent, struct device *self, void *aux)
{
	struct sbus_attach_args *sa = aux;
	struct qec_softc *qec = (struct qec_softc *)parent;
	struct be_softc *sc = (struct be_softc *)self;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct mii_data *mii = &sc->sc_mii;
	struct mii_softc *child;
	int node = sa->sa_node;
	bus_dma_tag_t dmatag = sa->sa_dmatag;
	bus_dma_segment_t seg;
	bus_size_t size;
	int instance;
	int rseg, error;
	u_int32_t v;
	extern void myetheraddr(u_char *);

	/* Pass on the bus tags */
	sc->sc_bustag = sa->sa_bustag;
	sc->sc_dmatag = sa->sa_dmatag;

	if (sa->sa_nreg < 3) {
		printf("%s: only %d register sets\n",
		    self->dv_xname, sa->sa_nreg);
		return;
	}

	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
	    (bus_addr_t)sa->sa_reg[0].sbr_offset,
	    (bus_size_t)sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_cr) != 0) {
		printf("beattach: cannot map registers\n");
		return;
	}

	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
	    (bus_addr_t)sa->sa_reg[1].sbr_offset,
	    (bus_size_t)sa->sa_reg[1].sbr_size, 0, 0, &sc->sc_br) != 0) {
		printf("beattach: cannot map registers\n");
		return;
	}

	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[2].sbr_slot,
	    (bus_addr_t)sa->sa_reg[2].sbr_offset,
	    (bus_size_t)sa->sa_reg[2].sbr_size, 0, 0, &sc->sc_tr) != 0) {
		printf("beattach: cannot map registers\n");
		return;
	}

	sc->sc_qec = qec;
	sc->sc_qr = qec->sc_regs;

	sc->sc_rev = getpropint(node, "board-version", -1);
	printf(" rev %x", sc->sc_rev);

	bestop(sc);

	sc->sc_channel = getpropint(node, "channel#", -1);
	if (sc->sc_channel == -1)
		sc->sc_channel = 0;

	sc->sc_burst = getpropint(node, "burst-sizes", -1);
	if (sc->sc_burst == -1)
		sc->sc_burst = qec->sc_burst;

	/* Clamp at parent's burst sizes */
	sc->sc_burst &= qec->sc_burst;

	/* Establish interrupt handler */
	if (sa->sa_nintr == 0 || bus_intr_establish(sa->sa_bustag, sa->sa_pri,
	    IPL_NET, 0, beintr, sc, self->dv_xname) == NULL) {
		printf(": no interrupt established\n");
		return;
	}

	myetheraddr(sc->sc_arpcom.ac_enaddr);
	printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));

	/*
	 * Allocate descriptor ring and buffers.
	 */

	/* for now, allocate as many bufs as there are ring descriptors */
	sc->sc_rb.rb_ntbuf = QEC_XD_RING_MAXSIZE;
	sc->sc_rb.rb_nrbuf = QEC_XD_RING_MAXSIZE;

	size =	QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
		QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
		sc->sc_rb.rb_ntbuf * BE_PKT_BUF_SZ +
		sc->sc_rb.rb_nrbuf * BE_PKT_BUF_SZ;

	/* Get a DMA handle */
	if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
	    BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
		printf("%s: DMA map create error %d\n", self->dv_xname, error);
		return;
	}

	/* Allocate DMA buffer */
	if ((error = bus_dmamem_alloc(sa->sa_dmatag, size, 0, 0,
	    &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
		printf("%s: DMA buffer alloc error %d\n",
			self->dv_xname, error);
		return;
	}

	/* Map DMA memory in CPU addressable space */
	if ((error = bus_dmamem_map(sa->sa_dmatag, &seg, rseg, size,
	    &sc->sc_rb.rb_membase, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
		printf("%s: DMA buffer map error %d\n",
			self->dv_xname, error);
		bus_dmamem_free(sa->sa_dmatag, &seg, rseg);
		return;
	}

	/* Load the buffer */
	if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
	    sc->sc_rb.rb_membase, size, NULL, BUS_DMA_NOWAIT)) != 0) {
		printf("%s: DMA buffer map load error %d\n",
		    self->dv_xname, error);
		bus_dmamem_unmap(dmatag, sc->sc_rb.rb_membase, size);
		bus_dmamem_free(dmatag, &seg, rseg);
		return;
	}
	sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;

	/*
	 * Initialize our media structures and MII info.
	 */
	mii->mii_ifp = ifp;
	mii->mii_readreg = be_mii_readreg;
	mii->mii_writereg = be_mii_writereg;
	mii->mii_statchg = be_mii_statchg;

	ifmedia_init(&mii->mii_media, 0, be_ifmedia_upd, be_ifmedia_sts);

	timeout_set(&sc->sc_tick_ch, be_tick, sc);

	/*
	 * Initialize transceiver and determine which PHY connection to use.
	 */
	be_mii_sync(sc);
	v = bus_space_read_4(sc->sc_bustag, sc->sc_tr, BE_TRI_MGMTPAL);

	instance = 0;

	if ((v & MGMT_PAL_EXT_MDIO) != 0) {

		mii_attach(&sc->sc_dev, mii, 0xffffffff, BE_PHY_EXTERNAL,
		    MII_OFFSET_ANY, 0);

		child = LIST_FIRST(&mii->mii_phys);
		if (child == NULL) {
			/* No PHY attached */
			ifmedia_add(&sc->sc_media,
			    IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance),
			    0, NULL);
			ifmedia_set(&sc->sc_media,
			    IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance));
		} else {
			/*
			 * Note: we support just one PHY on the external
			 * MII connector.
			 */
#ifdef DIAGNOSTIC
			if (LIST_NEXT(child, mii_list) != NULL) {
				printf("%s: spurious MII device %s attached\n",
				    sc->sc_dev.dv_xname,
				    child->mii_dev.dv_xname);
			}
#endif
			if (child->mii_phy != BE_PHY_EXTERNAL ||
			    child->mii_inst > 0) {
				printf("%s: cannot accommodate MII device %s"
				    " at phy %d, instance %d\n",
				    sc->sc_dev.dv_xname,
				    child->mii_dev.dv_xname,
				    child->mii_phy, child->mii_inst);
			} else {
				sc->sc_phys[instance] = child->mii_phy;
			}

			/*
			 * XXX - we can really do the following ONLY if the
			 * phy indeed has the auto negotiation capability!!
			 */
			ifmedia_set(&sc->sc_media,
			    IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));

			/* Mark our current media setting */
			be_pal_gate(sc, BE_PHY_EXTERNAL);
			instance++;
		}

	}

	if ((v & MGMT_PAL_INT_MDIO) != 0) {
		/*
		 * The be internal phy looks vaguely like MII hardware,
		 * but not enough to be able to use the MII device
		 * layer. Hence, we have to take care of media selection
		 * ourselves.
		 */

		sc->sc_mii_inst = instance;
		sc->sc_phys[instance] = BE_PHY_INTERNAL;

		/* Use `ifm_data' to store BMCR bits */
		ifmedia_add(&sc->sc_media,
		    IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,instance), 0, NULL);
		ifmedia_add(&sc->sc_media,
		    IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,instance),
		    BMCR_S100, NULL);
		ifmedia_add(&sc->sc_media,
		    IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance), 0, NULL);

		printf("on-board transceiver at %s: 10baseT, 100baseTX, auto\n",
		    self->dv_xname);

		be_mii_reset(sc, BE_PHY_INTERNAL);
		/* Only set default medium here if there's no external PHY */
		if (instance == 0) {
			be_pal_gate(sc, BE_PHY_INTERNAL);
			ifmedia_set(&sc->sc_media,
			    IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
		} else
			be_mii_writereg((void *)sc,
			    BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
	}

	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
	ifp->if_softc = sc;
	ifp->if_start = bestart;
	ifp->if_ioctl = beioctl;
	ifp->if_watchdog = bewatchdog;
	ifp->if_flags =
	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
	IFQ_SET_READY(&ifp->if_snd);

	/* Attach the interface. */
	if_attach(ifp);
	ether_ifattach(ifp);
}
コード例 #6
0
void
beinit(struct be_softc *sc)
{
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	bus_space_tag_t t = sc->sc_bustag;
	bus_space_handle_t br = sc->sc_br;
	bus_space_handle_t cr = sc->sc_cr;
	struct qec_softc *qec = sc->sc_qec;
	u_int32_t v;
	u_int32_t qecaddr;
	u_int8_t *ea;
	int s;

	s = splnet();

	qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);

	bestop(sc);

	ea = sc->sc_arpcom.ac_enaddr;
	bus_space_write_4(t, br, BE_BRI_MACADDR0, (ea[0] << 8) | ea[1]);
	bus_space_write_4(t, br, BE_BRI_MACADDR1, (ea[2] << 8) | ea[3]);
	bus_space_write_4(t, br, BE_BRI_MACADDR2, (ea[4] << 8) | ea[5]);

	/* Clear hash table */
	bus_space_write_4(t, br, BE_BRI_HASHTAB0, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB1, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB2, 0);
	bus_space_write_4(t, br, BE_BRI_HASHTAB3, 0);

	/* Re-initialize RX configuration */
	v = BE_BR_RXCFG_FIFO;
	bus_space_write_4(t, br, BE_BRI_RXCFG, v);

	be_mcreset(sc);

	bus_space_write_4(t, br, BE_BRI_RANDSEED, 0xbd);

	bus_space_write_4(t, br, BE_BRI_XIFCFG,
			  BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV);

	bus_space_write_4(t, br, BE_BRI_JSIZE, 4);

	/*
	 * Turn off counter expiration interrupts as well as
	 * 'gotframe' and 'sentframe'
	 */
	bus_space_write_4(t, br, BE_BRI_IMASK,
			  BE_BR_IMASK_GOTFRAME	|
			  BE_BR_IMASK_RCNTEXP	|
			  BE_BR_IMASK_ACNTEXP	|
			  BE_BR_IMASK_CCNTEXP	|
			  BE_BR_IMASK_LCNTEXP	|
			  BE_BR_IMASK_CVCNTEXP	|
			  BE_BR_IMASK_SENTFRAME	|
			  BE_BR_IMASK_NCNTEXP	|
			  BE_BR_IMASK_ECNTEXP	|
			  BE_BR_IMASK_LCCNTEXP	|
			  BE_BR_IMASK_FCNTEXP	|
			  BE_BR_IMASK_DTIMEXP);

	/* Channel registers: */
	bus_space_write_4(t, cr, BE_CRI_RXDS, (u_int32_t)sc->sc_rb.rb_rxddma);
	bus_space_write_4(t, cr, BE_CRI_TXDS, (u_int32_t)sc->sc_rb.rb_txddma);

	qecaddr = sc->sc_channel * qec->sc_msize;
	bus_space_write_4(t, cr, BE_CRI_RXWBUF, qecaddr);
	bus_space_write_4(t, cr, BE_CRI_RXRBUF, qecaddr);
	bus_space_write_4(t, cr, BE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
	bus_space_write_4(t, cr, BE_CRI_TXRBUF, qecaddr + qec->sc_rsize);

	bus_space_write_4(t, cr, BE_CRI_RIMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_TIMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_QMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_BMASK, 0);
	bus_space_write_4(t, cr, BE_CRI_CCNT, 0);

	/* Enable transmitter */
	bus_space_write_4(t, br, BE_BRI_TXCFG,
			  BE_BR_TXCFG_FIFO | BE_BR_TXCFG_ENABLE);

	/* Enable receiver */
	v = bus_space_read_4(t, br, BE_BRI_RXCFG);
	v |= BE_BR_RXCFG_FIFO | BE_BR_RXCFG_ENABLE;
	bus_space_write_4(t, br, BE_BRI_RXCFG, v);

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	be_ifmedia_upd(ifp);
	timeout_add_sec(&sc->sc_tick_ch, 1);
	splx(s);
}