static void
ed_rtl_get_media(struct ifnet *ifp, struct ifmediareq *imr)
{
	struct ed_softc *sc;

	sc = ifp->if_softc;
	imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media;


	if (IFM_SUBTYPE(imr->ifm_active) == IFM_AUTO) {
		ED_LOCK(sc);
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
		ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_3 |
			(ed_nic_inb(sc, ED_P0_CR) & (ED_CR_STA | ED_CR_STP)));
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);

		switch (ed_nic_inb(sc, ED_RTL80X9_CONFIG0)
				& (sc->chip_type == ED_CHIP_TYPE_RTL8029 ? ED_RTL80X9_CF0_BNC
				: (ED_RTL80X9_CF0_AUI | ED_RTL80X9_CF0_BNC))) {
		case ED_RTL80X9_CF0_BNC:
			imr->ifm_active |= IFM_10_2;
			break;
		case ED_RTL80X9_CF0_AUI:
			imr->ifm_active |= IFM_10_5;
			break;
		default:
			imr->ifm_active |= IFM_10_T;
			break;
		}
		ED_UNLOCK(sc);
	}
	imr->ifm_status = 0;
}
Exemple #2
0
/*
 * Detach the driver from the hardware and other systems in the kernel.
 */
int
ed_detach(device_t dev)
{
	struct ed_softc *sc = device_get_softc(dev);
	struct ifnet *ifp = sc->ifp;

	if (mtx_initialized(ED_MUTEX(sc)))
		ED_ASSERT_UNLOCKED(sc);
	if (ifp) {
		ED_LOCK(sc);
		if (bus_child_present(dev))
			ed_stop(sc);
		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
		ED_UNLOCK(sc);
		ether_ifdetach(ifp);
		callout_drain(&sc->tick_ch);
	}
	if (sc->irq_res != NULL && sc->irq_handle)
		bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
	ed_release_resources(dev);
	if (sc->miibus)
		device_delete_child(dev, sc->miibus);
	if (mtx_initialized(ED_MUTEX(sc)))
		ED_LOCK_DESTROY(sc);
	bus_generic_detach(dev);
	return (0);
}
Exemple #3
0
/*
 * Start output on interface.
 * We make two assumptions here:
 *  1) that the current priority is set to splimp _before_ this code
 *     is called *and* is returned to the appropriate priority after
 *     return
 *  2) that the IFF_DRV_OACTIVE flag is checked before this code is called
 *     (i.e. that the output part of the interface is idle)
 */
static void
ed_start(struct ifnet *ifp)
{
	struct ed_softc *sc = ifp->if_softc;

	ED_ASSERT_UNLOCKED(sc);
	ED_LOCK(sc);
	ed_start_locked(ifp);
	ED_UNLOCK(sc);
}
Exemple #4
0
/*
 * Initialize device.
 */
static void
ed_init(void *xsc)
{
	struct ed_softc *sc = xsc;

	ED_ASSERT_UNLOCKED(sc);
	ED_LOCK(sc);
	ed_init_locked(sc);
	ED_UNLOCK(sc);
}
Exemple #5
0
/*
 * Retreive packet from shared memory and send to the next level up via
 * ether_input().
 */
static void
ed_get_packet(struct ed_softc *sc, bus_size_t buf, u_short len)
{
	struct ifnet *ifp = sc->ifp;
	struct ether_header *eh;
	struct mbuf *m;

	/* Allocate a header mbuf */
	MGETHDR(m, M_NOWAIT, MT_DATA);
	if (m == NULL)
		return;
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = len;

	/*
	 * We always put the received packet in a single buffer -
	 * either with just an mbuf header or in a cluster attached
	 * to the header. The +2 is to compensate for the alignment
	 * fixup below.
	 */
	if ((len + 2) > MHLEN) {
		/* Attach an mbuf cluster */
		MCLGET(m, M_NOWAIT);

		/* Insist on getting a cluster */
		if ((m->m_flags & M_EXT) == 0) {
			m_freem(m);
			return;
		}
	}

	/*
	 * The +2 is to longword align the start of the real packet.
	 * This is important for NFS.
	 */
	m->m_data += 2;
	eh = mtod(m, struct ether_header *);

	/*
	 * Get packet, including link layer address, from interface.
	 */
	ed_ring_copy(sc, buf, (char *)eh, len);

	m->m_pkthdr.len = m->m_len = len;

	ED_UNLOCK(sc);
	(*ifp->if_input)(ifp, m);
	ED_LOCK(sc);
}
Exemple #6
0
static int
ed_ifmedia_upd(struct ifnet *ifp)
{
	struct ed_softc *sc;
	int error;

	sc = ifp->if_softc;
	ED_LOCK(sc);
	if (sc->miibus == NULL) {
		ED_UNLOCK(sc);
		return (ENXIO);
	}

	error = ed_pccard_kick_phy(sc);
	ED_UNLOCK(sc);
	return (error);
}
static int
ed_rtl_set_media(struct ifnet *ifp)
{
	struct ed_softc *sc;

	sc = ifp->if_softc;
	ED_LOCK(sc);
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_3
		| (ed_nic_inb(sc, ED_P0_CR) & (ED_CR_STA | ED_CR_STP)));
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);

	switch(IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) {
	case IFM_10_T:
		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_T
			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
				& ~ED_RTL80X9_CF2_MEDIA));
		break;
	case IFM_10_2:
		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_2
			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
				& ~ED_RTL80X9_CF2_MEDIA));
		break;
	case IFM_10_5:
		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_10_5
			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
				& ~ED_RTL80X9_CF2_MEDIA));
		break;
	case IFM_AUTO:
		ed_nic_outb(sc, ED_RTL80X9_CONFIG2, ED_RTL80X9_CF2_AUTO
			| (ed_nic_inb(sc, ED_RTL80X9_CONFIG2)
				& ~ED_RTL80X9_CF2_MEDIA));
		break;
	}
	ed_nic_outb(sc, ED_RTL80X9_CONFIG3,
		(sc->ifmedia.ifm_cur->ifm_media & IFM_FDX) ?
		(ed_nic_inb(sc, ED_RTL80X9_CONFIG3) | ED_RTL80X9_CF3_FUDUP) :
		(ed_nic_inb(sc, ED_RTL80X9_CONFIG3) & ~ED_RTL80X9_CF3_FUDUP));

	ED_UNLOCK(sc);
	return (0);
}
Exemple #8
0
static void
ed_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
	struct ed_softc *sc;
	struct mii_data *mii;

	sc = ifp->if_softc;
	ED_LOCK(sc);
	if (sc->miibus == NULL) {
		ED_UNLOCK(sc);
		return;
	}

	mii = device_get_softc(sc->miibus);
	mii_pollstat(mii);
	ifmr->ifm_active = mii->mii_media_active;
	ifmr->ifm_status = mii->mii_media_status;
	ED_UNLOCK(sc);
}
Exemple #9
0
/*
 * Ethernet interface interrupt processor
 */
void
edintr(void *arg)
{
	struct ed_softc *sc = (struct ed_softc*) arg;
	struct ifnet *ifp = sc->ifp;
	u_char  isr;
	int	count;

	ED_LOCK(sc);
	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
		ED_UNLOCK(sc);
		return;
	}
	/*
	 * Set NIC to page 0 registers
	 */
	ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA);

	/*
	 * loop until there are no more new interrupts.  When the card goes
	 * away, the hardware will read back 0xff.  Looking at the interrupts,
	 * it would appear that 0xff is impossible, or at least extremely
	 * unlikely.
	 */
	while ((isr = ed_nic_inb(sc, ED_P0_ISR)) != 0 && isr != 0xff) {

		/*
		 * reset all the bits that we are 'acknowledging' by writing a
		 * '1' to each bit position that was set (writing a '1'
		 * *clears* the bit)
		 */
		ed_nic_outb(sc, ED_P0_ISR, isr);

		/*
		 * The AX88190 and AX88190A has problems acking an interrupt
		 * and having them clear.  This interferes with top-level loop
		 * here.  Wait for all the bits to clear.
		 *
		 * We limit this to 5000 iterations.  At 1us per inb/outb,
		 * this translates to about 15ms, which should be plenty of
		 * time, and also gives protection in the card eject case.
		 */
		if (sc->chip_type == ED_CHIP_TYPE_AX88190) {
			count = 5000;		/* 15ms */
			while (count-- && (ed_nic_inb(sc, ED_P0_ISR) & isr)) {
				ed_nic_outb(sc, ED_P0_ISR,0);
				ed_nic_outb(sc, ED_P0_ISR,isr);
			}
			if (count == 0)
				break;
		}

		/*
		 * Handle transmitter interrupts. Handle these first because
		 * the receiver will reset the board under some conditions.
		 */
		if (isr & (ED_ISR_PTX | ED_ISR_TXE)) {
			u_char  collisions = ed_nic_inb(sc, ED_P0_NCR) & 0x0f;

			/*
			 * Check for transmit error. If a TX completed with an
			 * error, we end up throwing the packet away. Really
			 * the only error that is possible is excessive
			 * collisions, and in this case it is best to allow
			 * the automatic mechanisms of TCP to backoff the
			 * flow. Of course, with UDP we're screwed, but this
			 * is expected when a network is heavily loaded.
			 */
			(void) ed_nic_inb(sc, ED_P0_TSR);
			if (isr & ED_ISR_TXE) {
				u_char tsr;

				/*
				 * Excessive collisions (16)
				 */
				tsr = ed_nic_inb(sc, ED_P0_TSR);
				if ((tsr & ED_TSR_ABT)	
				    && (collisions == 0)) {

					/*
					 * When collisions total 16, the
					 * P0_NCR will indicate 0, and the
					 * TSR_ABT is set.
					 */
					collisions = 16;
					sc->mibdata.dot3StatsExcessiveCollisions++;
					sc->mibdata.dot3StatsCollFrequencies[15]++;
				}
				if (tsr & ED_TSR_OWC)
					sc->mibdata.dot3StatsLateCollisions++;
				if (tsr & ED_TSR_CDH)
					sc->mibdata.dot3StatsSQETestErrors++;
				if (tsr & ED_TSR_CRS)
					sc->mibdata.dot3StatsCarrierSenseErrors++;
				if (tsr & ED_TSR_FU)
					sc->mibdata.dot3StatsInternalMacTransmitErrors++;

				/*
				 * update output errors counter
				 */
				ifp->if_oerrors++;
			} else {

				/*
				 * Update total number of successfully
				 * transmitted packets.
				 */
				ifp->if_opackets++;
			}

			/*
			 * reset tx busy and output active flags
			 */
			sc->xmit_busy = 0;
			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;

			/*
			 * clear watchdog timer
			 */
			sc->tx_timer = 0;

			/*
			 * Add in total number of collisions on last
			 * transmission.
			 */
			ifp->if_collisions += collisions;
			switch(collisions) {
			case 0:
			case 16:
				break;
			case 1:
				sc->mibdata.dot3StatsSingleCollisionFrames++;
				sc->mibdata.dot3StatsCollFrequencies[0]++;
				break;
			default:
				sc->mibdata.dot3StatsMultipleCollisionFrames++;
				sc->mibdata.
					dot3StatsCollFrequencies[collisions-1]
						++;
				break;
			}

			/*
			 * Decrement buffer in-use count if not zero (can only
			 * be zero if a transmitter interrupt occured while
			 * not actually transmitting). If data is ready to
			 * transmit, start it transmitting, otherwise defer
			 * until after handling receiver
			 */
			if (sc->txb_inuse && --sc->txb_inuse)
				ed_xmit(sc);
		}

		/*
		 * Handle receiver interrupts
		 */
		if (isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) {

			/*
			 * Overwrite warning. In order to make sure that a
			 * lockup of the local DMA hasn't occurred, we reset
			 * and re-init the NIC. The NSC manual suggests only a
			 * partial reset/re-init is necessary - but some chips
			 * seem to want more. The DMA lockup has been seen
			 * only with early rev chips - Methinks this bug was
			 * fixed in later revs. -DG
			 */
			if (isr & ED_ISR_OVW) {
				ifp->if_ierrors++;
#ifdef DIAGNOSTIC
				log(LOG_WARNING,
				    "%s: warning - receiver ring buffer overrun\n",
				    ifp->if_xname);
#endif

				/*
				 * Stop/reset/re-init NIC
				 */
				ed_reset(ifp);
			} else {

				/*
				 * Receiver Error. One or more of: CRC error,
				 * frame alignment error FIFO overrun, or
				 * missed packet.
				 */
				if (isr & ED_ISR_RXE) {
					u_char rsr;
					rsr = ed_nic_inb(sc, ED_P0_RSR);
					if (rsr & ED_RSR_CRC)
						sc->mibdata.dot3StatsFCSErrors++;
					if (rsr & ED_RSR_FAE)
						sc->mibdata.dot3StatsAlignmentErrors++;
					if (rsr & ED_RSR_FO)
						sc->mibdata.dot3StatsInternalMacReceiveErrors++;
					ifp->if_ierrors++;
#ifdef ED_DEBUG
					if_printf(ifp, "receive error %x\n",
					       ed_nic_inb(sc, ED_P0_RSR));
#endif
				}

				/*
				 * Go get the packet(s) XXX - Doing this on an
				 * error is dubious because there shouldn't be
				 * any data to get (we've configured the
				 * interface to not accept packets with
				 * errors).
				 */

				/*
				 * Enable 16bit access to shared memory first
				 * on WD/SMC boards.
				 */
				ed_enable_16bit_access(sc);
				ed_rint(sc);
				ed_disable_16bit_access(sc);
			}
		}

		/*
		 * If it looks like the transmitter can take more data,
		 * attempt to start output on the interface. This is done
		 * after handling the receiver to give the receiver priority.
		 */
		if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
			ed_start_locked(ifp);

		/*
		 * return NIC CR to standard state: page 0, remote DMA
		 * complete, start (toggling the TXP bit off, even if was just
		 * set in the transmit routine, is *okay* - it is 'edge'
		 * triggered from low to high)
		 */
		ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA);

		/*
		 * If the Network Talley Counters overflow, read them to reset
		 * them. It appears that old 8390's won't clear the ISR flag
		 * otherwise - resulting in an infinite loop.
		 */
		if (isr & ED_ISR_CNT) {
			(void) ed_nic_inb(sc, ED_P0_CNTR0);
			(void) ed_nic_inb(sc, ED_P0_CNTR1);
			(void) ed_nic_inb(sc, ED_P0_CNTR2);
		}
	}
	ED_UNLOCK(sc);
}
Exemple #10
0
/*
 * Process an ioctl request.
 */
static int
ed_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
	struct ed_softc *sc = ifp->if_softc;
	struct ifreq *ifr = (struct ifreq *)data;
	int     error = 0;

	switch (command) {
	case SIOCSIFFLAGS:
		/*
		 * If the interface is marked up and stopped, then start it.
		 * If we're up and already running, then it may be a mediachg.
		 * If it is marked down and running, then stop it.
		 */
		ED_LOCK(sc);
		if (ifp->if_flags & IFF_UP) {
			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
				ed_init_locked(sc);
			else if (sc->sc_mediachg)
				sc->sc_mediachg(sc);
		} else {
			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
				ed_stop(sc);
				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
			}
		}

		/*
		 * Promiscuous flag may have changed, so reprogram the RCR.
		 */
		ed_setrcr(sc);

		ED_UNLOCK(sc);
		break;

	case SIOCADDMULTI:
	case SIOCDELMULTI:
		/*
		 * Multicast list has changed; set the hardware filter
		 * accordingly.
		 */
		ED_LOCK(sc);
		ed_setrcr(sc);
		ED_UNLOCK(sc);
		error = 0;
		break;

	case SIOCGIFMEDIA:
	case SIOCSIFMEDIA:
		if (sc->sc_media_ioctl == NULL) {
			error = EINVAL;
			break;
		}
		sc->sc_media_ioctl(sc, ifr, command);
		break;

	default:
		error = ether_ioctl(ifp, command, data);
		break;
	}
	return (error);
}