Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
int
ed_probe_generic8390(struct ed_softc *sc)
{
	if ((ed_nic_inb(sc, ED_P0_CR) &
	     (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
	    (ED_CR_RD2 | ED_CR_STP))
		return (0);
	if ((ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
		return (0);

	return (1);
}
Ejemplo n.º 3
0
static void
ed_stop_hw(struct ed_softc *sc)
{
	int     n = 5000;

	/*
	 * Stop everything on the interface, and select page 0 registers.
	 */
	ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STP);

	/*
	 * Wait for interface to enter stopped state, but limit # of checks to
	 * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
	 * just in case it's an old one.
	 *
	 * The AX88x90 chips don't seem to implement this behavor.  The
	 * datasheets say it is only turned on when the chip enters a RESET
	 * state and is silent about behavior for the stopped state we just
	 * entered.
	 */
	if (sc->chip_type == ED_CHIP_TYPE_AX88190 ||
	    sc->chip_type == ED_CHIP_TYPE_AX88790)
		return;
	while (((ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) == 0) && --n)
		continue;
	if (n <= 0)
		device_printf(sc->dev, "ed_stop_hw RST never set\n");
}
Ejemplo n.º 4
0
/*
 * MII bus support routines.
 */
static int
ed_miibus_readreg(device_t dev, int phy, int reg)
{
	struct ed_softc *sc;
	int val;
	uint8_t cr = 0;

	sc = device_get_softc(dev);
	/*
	 * The AX88790 has an interesting quirk.  It has an internal phy that
	 * needs a special bit set to access, but can also have additional
	 * external PHYs set for things like HomeNET media.  When accessing
	 * the internal PHY, a bit has to be set, when accessing the external
	 * PHYs, it must be clear.  See Errata 1, page 51, in the AX88790
	 * datasheet for more details.
	 *
	 * Also, PHYs above 16 appear to be phantoms on some cards, but not
	 * others.  Registers read for this are often the same as prior values
	 * read.  Filter all register requests to 17-31.
	 */
	if (sc->chip_type == ED_CHIP_TYPE_AX88790) {
		if (phy > 0x10)
			return (0);
		if (phy == 0x10)
			ed_asic_outb(sc, ED_AX88X90_GPIO,
			    ED_AX88X90_GPIO_INT_PHY);
		else
			ed_asic_outb(sc, ED_AX88X90_GPIO, 0);
		ed_asic_barrier(sc, ED_AX88X90_GPIO, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	} else if (sc->chip_type == ED_CHIP_TYPE_TC5299J) {
		/* Select page 3. */
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
		cr = ed_nic_inb(sc, ED_P0_CR);
		ed_nic_outb(sc, ED_P0_CR, cr | ED_CR_PAGE_3);
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	}
	val = mii_bitbang_readreg(dev, sc->mii_bitbang_ops, phy, reg);
	if (sc->chip_type == ED_CHIP_TYPE_TC5299J) {
		/* Restore prior page. */
		ed_nic_outb(sc, ED_P0_CR, cr);
		ed_nic_barrier(sc, ED_P0_CR, 1,
	    	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	}
	return (val);
}
Ejemplo n.º 5
0
/*
 * Stripped down routine for writing a linear buffer to NIC memory.
 *	Only used in the probe routine to test the memory. 'len' must
 *	be even.
 */
void
ed_pio_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len)
{
	int     maxwait = 200;	/* about 240us */

	/* select page 0 registers */
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STA);
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);

	/* reset remote DMA complete flag */
	ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC);

	/* set up DMA byte count */
	ed_nic_outb(sc, ED_P0_RBCR0, len);
	ed_nic_outb(sc, ED_P0_RBCR1, len >> 8);

	/* set up destination address in NIC mem */
	ed_nic_outb(sc, ED_P0_RSAR0, dst);
	ed_nic_outb(sc, ED_P0_RSAR1, dst >> 8);

	/* set remote DMA write */
	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD1 | ED_CR_STA);

	if (sc->isa16bit)
		ed_asic_outsw(sc, ED_NOVELL_DATA, src, len / 2);
	else
		ed_asic_outsb(sc, ED_NOVELL_DATA, src, len);

	/*
	 * Wait for remote DMA complete. This is necessary because on the
	 * transmit side, data is handled internally by the NIC in bursts and
	 * we can't start another remote DMA until this one completes. Not
	 * waiting causes really bad things to happen - like the NIC
	 * irrecoverably jamming the ISA bus.
	 */
	while (((ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) &&
	    --maxwait)
		continue;
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
static void
ed_pccard_ax88x90_reset(struct ed_softc *sc)
{
	int i;

	/* Reset Card */
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0);
	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	ed_asic_outb(sc, ED_NOVELL_RESET, ed_asic_inb(sc, ED_NOVELL_RESET));

	/* Wait for the RST bit to assert, but cap it at 10ms */
	for (i = 10000; !(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) && i > 0;
	     i--)
		continue;
	ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RST);	/* ACK INTR */
	if (i == 0)
		device_printf(sc->dev, "Reset didn't finish\n");
}
Ejemplo n.º 8
0
static int
ed_miibus_writereg(device_t dev, int phy, int reg, int data)
{
	struct ed_softc *sc;
	uint8_t cr = 0;

	sc = device_get_softc(dev);
	/* See ed_miibus_readreg for details */
	if (sc->chip_type == ED_CHIP_TYPE_AX88790) {
		if (phy > 0x10)
			return (0);
		if (phy == 0x10)
			ed_asic_outb(sc, ED_AX88X90_GPIO,
			    ED_AX88X90_GPIO_INT_PHY);
		else
			ed_asic_outb(sc, ED_AX88X90_GPIO, 0);
		ed_asic_barrier(sc, ED_AX88X90_GPIO, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	} else if (sc->chip_type == ED_CHIP_TYPE_TC5299J) {
		/* Select page 3. */
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
		cr = ed_nic_inb(sc, ED_P0_CR);
		ed_nic_outb(sc, ED_P0_CR, cr | ED_CR_PAGE_3);
		ed_nic_barrier(sc, ED_P0_CR, 1,
		    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	}
	mii_bitbang_writereg(dev, sc->mii_bitbang_ops, phy, reg, data);
	if (sc->chip_type == ED_CHIP_TYPE_TC5299J) {
		/* Restore prior page. */
		ed_nic_outb(sc, ED_P0_CR, cr);
		ed_nic_barrier(sc, ED_P0_CR, 1,
	    	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	}
	return (0);
}
Ejemplo n.º 9
0
int
ed_probe_RTL80x9(device_t dev, int port_rid, int flags)
{
	struct ed_softc *sc = device_get_softc(dev);
	char *ts;
	int error;

	if ((error = ed_alloc_port(dev, port_rid, ED_NOVELL_IO_PORTS)))
		return (error);
	
	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;

	if (ed_nic_inb(sc, ED_P0_CR) & (ED_CR_PS0 | ED_CR_PS1))
		ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);

	if (ed_nic_inb(sc, ED_RTL80X9_80X9ID0) != ED_RTL80X9_ID0)
		return (ENXIO);

	switch (ed_nic_inb(sc, ED_RTL80X9_80X9ID1)) {
	case ED_RTL8019_ID1:
		sc->chip_type = ED_CHIP_TYPE_RTL8019;
		ts = "RTL8019";
		break;
	case ED_RTL8029_ID1:
		sc->chip_type = ED_CHIP_TYPE_RTL8029;
		ts = "RTL8029";
		break;
	default:
		return (ENXIO);
	}

	if ((error = ed_probe_Novell_generic(dev, flags)))
		return (error);

	sc->type_str = ts;
	sc->sc_media_ioctl = &ed_rtl80x9_media_ioctl;
	ifmedia_init(&sc->ifmedia, 0, ed_rtl_set_media, ed_rtl_get_media);

	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, 0);
	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_2, 0, 0);
	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
	ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);

	ed_nic_barrier(sc, ED_P0_CR, 1,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_3 | 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_CONFIG2) & ED_RTL80X9_CF2_MEDIA) {
	case ED_RTL80X9_CF2_AUTO:
		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
		break;
	case ED_RTL80X9_CF2_10_5:
		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_5);
		break;
	case ED_RTL80X9_CF2_10_2:
		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_2);
		break;
	case ED_RTL80X9_CF2_10_T:
		ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T |
		    ((ed_nic_inb(sc, ED_RTL80X9_CONFIG3)
		    & ED_RTL80X9_CF3_FUDUP) ? IFM_FDX : 0));
		break;
	}
	return (0);
}
Ejemplo n.º 10
0
/*
 * Probe and vendor specific initialization for the HP PC Lan+ Cards.
 * (HP Part nos: 27247B and 27252A).
 *
 * The card has an asic wrapper around a DS8390 core.  The asic handles 
 * host accesses and offers both standard register IO and memory mapped 
 * IO.  Memory mapped I/O allows better performance at the expense of greater
 * chance of an incompatibility with existing ISA cards.
 *
 * The card has a few caveats: it isn't tolerant of byte wide accesses, only
 * short (16 bit) or word (32 bit) accesses are allowed.  Some card revisions
 * don't allow 32 bit accesses; these are indicated by a bit in the software
 * ID register (see if_edreg.h).
 * 
 * Other caveats are: we should read the MAC address only when the card
 * is inactive.
 *
 * For more information; please consult the CRYNWR packet driver.
 *
 * The AUI port is turned on using the "link2" option on the ifconfig 
 * command line.
 */
int
ed_probe_HP_pclanp(device_t dev, int port_rid, int flags)
{
	struct ed_softc *sc = device_get_softc(dev);
	int error;
	int n;				/* temp var */
	int memsize;			/* mem on board */
	u_char checksum;		/* checksum of board address */
	u_char irq;			/* board configured IRQ */
	uint8_t test_pattern[ED_HPP_TEST_SIZE];	/* read/write areas for */
	uint8_t test_buffer[ED_HPP_TEST_SIZE];	/* probing card */
	rman_res_t conf_maddr, conf_msize, conf_irq, junk;

	error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS);
	if (error)
		return (error);

	/* Fill in basic information */
	sc->asic_offset = ED_HPP_ASIC_OFFSET;
	sc->nic_offset  = ED_HPP_NIC_OFFSET;

	sc->chip_type = ED_CHIP_TYPE_DP8390;
	sc->isa16bit = 0;	/* the 8390 core needs to be in byte mode */

	/* 
	 * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" 
	 */
	
	if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || 
	    (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) ||
	    ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) ||
	    (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53))
		return (ENXIO);

	/* 
	 * Read the MAC address and verify checksum on the address.
	 */

	ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC);
	for (n  = 0, checksum = 0; n < ETHER_ADDR_LEN; n++)
		checksum += (sc->enaddr[n] = 
		    ed_asic_inb(sc, ED_HPP_MAC_ADDR + n));
	
	checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN);

	if (checksum != 0xFF)
		return (ENXIO);

	/*
	 * Verify that the software model number is 0.
	 */
	
	ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID);
	if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & 
		ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000)
		return (ENXIO);

	/*
	 * Read in and save the current options configured on card.
	 */

	sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION);

	sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | 
	    ED_HPP_OPTION_CHIP_RESET | ED_HPP_OPTION_ENABLE_IRQ);

	/* 
	 * Reset the chip.  This requires writing to the option register
	 * so take care to preserve the other bits.
	 */

	ed_asic_outw(sc, ED_HPP_OPTION, 
	    (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | 
	    ED_HPP_OPTION_CHIP_RESET)));

	DELAY(5000);	/* wait for chip reset to complete */

	ed_asic_outw(sc, ED_HPP_OPTION,
	    (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET |
	    ED_HPP_OPTION_CHIP_RESET |
	    ED_HPP_OPTION_ENABLE_IRQ)));

	DELAY(5000);

	if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST))
		return (ENXIO);	/* reset did not complete */

	/*
	 * Read out configuration information.
	 */

	ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);

	irq = ed_asic_inb(sc, ED_HPP_HW_IRQ);

	/*
 	 * Check for impossible IRQ.
	 */

	if (irq >= (sizeof(ed_hpp_intr_val) / sizeof(ed_hpp_intr_val[0])))
		return (ENXIO);

	/* 
	 * If the kernel IRQ was specified with a '?' use the cards idea
	 * of the IRQ.  If the kernel IRQ was explicitly specified, it
 	 * should match that of the hardware.
	 */
	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
	if (error)
		bus_set_resource(dev, SYS_RES_IRQ, 0, ed_hpp_intr_val[irq], 1);
	else {
		if (conf_irq != ed_hpp_intr_val[irq])
			return (ENXIO);
	}

	/*
	 * Fill in softconfig info.
	 */

	sc->vendor = ED_VENDOR_HP;
	sc->type = ED_TYPE_HP_PCLANPLUS;
	sc->type_str = "HP-PCLAN+";

	sc->mem_shared = 0;	/* we DON'T have dual ported RAM */
	sc->mem_start = 0;	/* we use offsets inside the card RAM */

	sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */

	/*
	 * The board has 32KB of memory.  Is there a way to determine
	 * this programmatically?
	 */
	
	memsize = 32768;

	/*
	 * Check if memory mapping of the I/O registers possible.
	 */
	if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) {
		u_long mem_addr;

		/*
		 * determine the memory address from the board.
		 */
		
		ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);
		mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8);

		/*
		 * Check that the kernel specified start of memory and
		 * hardware's idea of it match.
		 */
		error = bus_get_resource(dev, SYS_RES_MEMORY, 0,
					 &conf_maddr, &conf_msize);
		if (error)
			return (error);
		
		if (mem_addr != conf_maddr)
			return (ENXIO);

		error = ed_alloc_memory(dev, 0, memsize);
		if (error)
			return (error);

		sc->hpp_mem_start = rman_get_virtual(sc->mem_res);
	}

	/*
	 * Fill in the rest of the soft config structure.
	 */

	/*
	 * The transmit page index.
	 */

	sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET;

	if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING)
		sc->txb_cnt = 1;
	else
		sc->txb_cnt = 2;

	/*
	 * Memory description
	 */

	sc->mem_size = memsize;
	sc->mem_ring = sc->mem_start + 
		(sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE);
	sc->mem_end = sc->mem_start + sc->mem_size;

	/*
	 * Receive area starts after the transmit area and 
	 * continues till the end of memory.
	 */

	sc->rec_page_start = sc->tx_page_start + 
				(sc->txb_cnt * ED_TXBUF_SIZE);
	sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE);


	sc->cr_proto = 0;	/* value works */

	/*
	 * Set the wrap registers for string I/O reads.
	 */

	ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);
	ed_asic_outw(sc, ED_HPP_HW_WRAP,
	    ((sc->rec_page_start / ED_PAGE_SIZE) |
	    (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8)));

	/*
	 * Reset the register page to normal operation.
	 */

	ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF);

	/*
	 * Verify that we can read/write from adapter memory.
	 * Create test pattern.
	 */

	for (n = 0; n < ED_HPP_TEST_SIZE; n++)
		test_pattern[n] = (n*n) ^ ~n;

#undef	ED_HPP_TEST_SIZE

	/*
	 * Check that the memory is accessible thru the I/O ports.
	 * Write out the contents of "test_pattern", read back
	 * into "test_buffer" and compare the two for any
	 * mismatch.
	 */

	for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) {
		ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), 
				sizeof(test_pattern));
		ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), 
			test_buffer, sizeof(test_pattern));

		if (bcmp(test_pattern, test_buffer, 
			sizeof(test_pattern)))
			return (ENXIO);
	}

	sc->sc_mediachg = ed_hpp_set_physical_link;
	sc->sc_write_mbufs = ed_hpp_write_mbufs;
	sc->readmem = ed_hpp_readmem;
	return (0);
}
Ejemplo n.º 11
0
/*
 * Probe and vendor-specific initialization routine for 3Com 3c503 boards
 */
int
ed_probe_3Com(device_t dev, int port_rid, int flags)
{
	struct ed_softc *sc = device_get_softc(dev);
	int	error;
	int     i;
	u_int   memsize;
	u_char  isa16bit;
	u_long	conf_maddr, conf_msize, irq, junk, pmem;

	error = ed_alloc_port(dev, 0, ED_3COM_IO_PORTS);
	if (error)
		return (error);

	sc->asic_offset = ED_3COM_ASIC_OFFSET;
	sc->nic_offset  = ED_3COM_NIC_OFFSET;

	/*
	 * Verify that the kernel configured I/O address matches the board
	 * configured address
	 */
	switch (ed_asic_inb(sc, ED_3COM_BCFR)) {
	case ED_3COM_BCFR_300:
		if (rman_get_start(sc->port_res) != 0x300)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_310:
		if (rman_get_start(sc->port_res) != 0x310)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_330:
		if (rman_get_start(sc->port_res) != 0x330)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_350:
		if (rman_get_start(sc->port_res) != 0x350)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_250:
		if (rman_get_start(sc->port_res) != 0x250)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_280:
		if (rman_get_start(sc->port_res) != 0x280)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_2A0:
		if (rman_get_start(sc->port_res) != 0x2a0)
			return (ENXIO);
		break;
	case ED_3COM_BCFR_2E0:
		if (rman_get_start(sc->port_res) != 0x2e0)
			return (ENXIO);
		break;
	default:
		return (ENXIO);
	}

	error = bus_get_resource(dev, SYS_RES_MEMORY, 0,
				 &conf_maddr, &conf_msize);
	if (error)
		return (error);

	/*
	 * Verify that the kernel shared memory address matches the board
	 * configured address.
	 */
	switch (ed_asic_inb(sc, ED_3COM_PCFR)) {
	case ED_3COM_PCFR_DC000:
		if (conf_maddr != 0xdc000)
			return (ENXIO);
		break;
	case ED_3COM_PCFR_D8000:
		if (conf_maddr != 0xd8000)
			return (ENXIO);
		break;
	case ED_3COM_PCFR_CC000:
		if (conf_maddr != 0xcc000)
			return (ENXIO);
		break;
	case ED_3COM_PCFR_C8000:
		if (conf_maddr != 0xc8000)
			return (ENXIO);
		break;
	default:
		return (ENXIO);
	}


	/*
	 * Reset NIC and ASIC. Enable on-board transceiver throughout reset
	 * sequence because it'll lock up if the cable isn't connected if we
	 * don't.
	 */
	ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);

	/*
	 * Wait for a while, then un-reset it
	 */
	DELAY(50);

	/*
	 * The 3Com ASIC defaults to rather strange settings for the CR after
	 * a reset - it's important to set it again after the following outb
	 * (this is done when we map the PROM below).
	 */
	ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL);

	/*
	 * Wait a bit for the NIC to recover from the reset
	 */
	DELAY(5000);

	sc->vendor = ED_VENDOR_3COM;
	sc->type_str = "3c503";
	sc->mem_shared = 1;
	sc->cr_proto = ED_CR_RD2;

	/*
	 * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window
	 * to it.
	 */
	memsize = 8192;

	/*
	 * Get station address from on-board ROM
	 */

	/*
	 * First, map ethernet address PROM over the top of where the NIC
	 * registers normally appear.
	 */
	ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);

	for (i = 0; i < ETHER_ADDR_LEN; ++i)
		sc->enaddr[i] = ed_nic_inb(sc, i);

	/*
	 * Unmap PROM - select NIC registers. The proper setting of the
	 * tranceiver is set in ed_init so that the attach code is given a
	 * chance to set the default based on a compile-time config option
	 */
	ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL);

	/*
	 * Determine if this is an 8bit or 16bit board
	 */

	/*
	 * select page 0 registers
	 */
	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);

	/*
	 * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit
	 * board.
	 */
	ed_nic_outb(sc, ED_P0_DCR, 0);

	/*
	 * select page 2 registers
	 */
	ed_nic_outb(sc, ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP);

	/*
	 * The 3c503 forces the WTS bit to a one if this is a 16bit board
	 */
	if (ed_nic_inb(sc, ED_P2_DCR) & ED_DCR_WTS)
		isa16bit = 1;
	else
		isa16bit = 0;

	/*
	 * select page 0 registers
	 */
	ed_nic_outb(sc, ED_P2_CR, ED_CR_RD2 | ED_CR_STP);

	error = ed_alloc_memory(dev, 0, memsize);
	if (error)
		return (error);

	pmem = rman_get_start(sc->mem_res);
	error = ed_isa_mem_ok(dev, pmem, memsize);
	if (error)
		return (error);

	sc->mem_start = 0;
	sc->mem_size = memsize;
	sc->mem_end = sc->mem_start + memsize;

	/*
	 * We have an entire 8k window to put the transmit buffers on the
	 * 16bit boards. But since the 16bit 3c503's shared memory is only
	 * fast enough to overlap the loading of one full-size packet, trying
	 * to load more than 2 buffers can actually leave the transmitter idle
	 * during the load. So 2 seems the best value. (Although a mix of
	 * variable-sized packets might change this assumption. Nonetheless,
	 * we optimize for linear transfers of same-size packets.)
	 */
	if (isa16bit) {
		if (flags & ED_FLAGS_NO_MULTI_BUFFERING)
			sc->txb_cnt = 1;
		else
			sc->txb_cnt = 2;

		sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
		sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
		sc->rec_page_stop = memsize / ED_PAGE_SIZE +
		    ED_3COM_RX_PAGE_OFFSET_16BIT;
		sc->mem_ring = sc->mem_start;
	} else {
		sc->txb_cnt = 1;
		sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
		sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
		sc->rec_page_stop = memsize / ED_PAGE_SIZE +
		    ED_3COM_TX_PAGE_OFFSET_8BIT;
		sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
	}

	sc->isa16bit = isa16bit;

	/*
	 * Initialize GA page start/stop registers. Probably only needed if
	 * doing DMA, but what the hell.
	 */
	ed_asic_outb(sc, ED_3COM_PSTR, sc->rec_page_start);
	ed_asic_outb(sc, ED_3COM_PSPR, sc->rec_page_stop);

	/*
	 * Set IRQ. 3c503 only allows a choice of irq 2-5.
	 */
	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk);
	if (error)
		return (error);

	switch (irq) {
	case 2:
	case 9:
		ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
		break;
	case 3:
		ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
		break;
	case 4:
		ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
		break;
	case 5:
		ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
		break;
	default:
		device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n",
			      irq);
		return (ENXIO);
	}

	/*
	 * Initialize GA configuration register. Set bank and enable shared
	 * mem.
	 */
	ed_asic_outb(sc, ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
	    ED_3COM_GACFR_MBS0);

	/*
	 * Initialize "Vector Pointer" registers. These gawd-awful things are
	 * compared to 20 bits of the address on ISA, and if they match, the
	 * shared memory is disabled. We set them to 0xffff0...allegedly the
	 * reset vector.
	 */
	ed_asic_outb(sc, ED_3COM_VPTR2, 0xff);
	ed_asic_outb(sc, ED_3COM_VPTR1, 0xff);
	ed_asic_outb(sc, ED_3COM_VPTR0, 0x00);

	error = ed_clear_memory(dev);
	if (error == 0) {
		sc->sc_mediachg = ed_3c503_mediachg;
		sc->sc_write_mbufs = ed_shmem_write_mbufs;
	}
	return (error);
}
Ejemplo n.º 12
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);
}
Ejemplo n.º 13
0
/*
 * Ethernet interface receiver interrupt.
 */
static __inline void
ed_rint(struct ed_softc *sc)
{
	struct ifnet *ifp = sc->ifp;
	u_char  boundry;
	u_short len;
	struct ed_ring packet_hdr;
	bus_size_t packet_ptr;

	ED_ASSERT_LOCKED(sc);

	/*
	 * Set NIC to page 1 registers to get 'current' pointer
	 */
	ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA);

	/*
	 * 'sc->next_packet' is the logical beginning of the ring-buffer -
	 * i.e. it points to where new data has been buffered. The 'CURR'
	 * (current) register points to the logical end of the ring-buffer -
	 * i.e. it points to where additional new data will be added. We loop
	 * here until the logical beginning equals the logical end (or in
	 * other words, until the ring-buffer is empty).
	 */
	while (sc->next_packet != ed_nic_inb(sc, ED_P1_CURR)) {

		/* get pointer to this buffer's header structure */
		packet_ptr = sc->mem_ring +
		    (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE;
	
		/*
		 * The byte count includes a 4 byte header that was added by
		 * the NIC.
		 */
		sc->readmem(sc, packet_ptr, (char *) &packet_hdr,
		    sizeof(packet_hdr));
		len = packet_hdr.count;
		if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN + sizeof(struct ed_ring)) ||
		    len < (ETHER_MIN_LEN - ETHER_CRC_LEN + sizeof(struct ed_ring))) {
			/*
			 * Length is a wild value. There's a good chance that
			 * this was caused by the NIC being old and buggy.
			 * The bug is that the length low byte is duplicated
			 * in the high byte. Try to recalculate the length
			 * based on the pointer to the next packet.  Also,
			 * need ot preserve offset into page.
			 *
			 * NOTE: sc->next_packet is pointing at the current
			 * packet.
			 */
			len &= ED_PAGE_SIZE - 1;
			if (packet_hdr.next_packet >= sc->next_packet)
				len += (packet_hdr.next_packet -
				    sc->next_packet) * ED_PAGE_SIZE;
			else
				len += 
				    ((packet_hdr.next_packet - sc->rec_page_start) +
				    (sc->rec_page_stop - sc->next_packet)) * ED_PAGE_SIZE;
			/*
			 * because buffers are aligned on 256-byte boundary,
			 * the length computed above is off by 256 in almost
			 * all cases. Fix it...
			 */
			if (len & 0xff)
				len -= 256;
			if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN 
			    + sizeof(struct ed_ring)))
				sc->mibdata.dot3StatsFrameTooLongs++;
		}

		/*
		 * Be fairly liberal about what we allow as a "reasonable"
		 * length so that a [crufty] packet will make it to BPF (and
		 * can thus be analyzed). Note that all that is really
		 * important is that we have a length that will fit into one
		 * mbuf cluster or less; the upper layer protocols can then
		 * figure out the length from their own length field(s).  But
		 * make sure that we have at least a full ethernet header or
		 * we would be unable to call ether_input() later.
		 */
		if ((len >= sizeof(struct ed_ring) + ETHER_HDR_LEN) &&
		    (len <= MCLBYTES) &&
		    (packet_hdr.next_packet >= sc->rec_page_start) &&
		    (packet_hdr.next_packet < sc->rec_page_stop)) {
			/*
			 * Go get packet.
			 */
			ed_get_packet(sc, packet_ptr + sizeof(struct ed_ring),
				      len - sizeof(struct ed_ring));
			ifp->if_ipackets++;
		} else {
			/*
			 * Really BAD. The ring pointers are corrupted.
			 */
			log(LOG_ERR,
			    "%s: NIC memory corrupt - invalid packet length %d\n",
			    ifp->if_xname, len);
			ifp->if_ierrors++;
			ed_reset(ifp);
			return;
		}

		/*
		 * Update next packet pointer
		 */
		sc->next_packet = packet_hdr.next_packet;

		/*
		 * Update NIC boundry pointer - being careful to keep it one
		 * buffer behind. (as recommended by NS databook)
		 */
		boundry = sc->next_packet - 1;
		if (boundry < sc->rec_page_start)
			boundry = sc->rec_page_stop - 1;

		/*
		 * Set NIC to page 0 registers to update boundry register
		 */
		ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA);
		ed_nic_outb(sc, ED_P0_BNRY, boundry);

		/*
		 * Set NIC to page 1 registers before looping to top (prepare
		 * to get 'CURR' current pointer)
		 */
		ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA);
	}
}