Esempio n. 1
0
/*
 * Drains any FIFOs in the card, then pauses it
 */
static void
pcn_suspend(pcn_t *pcnp)
{
	uint32_t val;
	int i;

	PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND);
	for (i = 0; i < 5000; i++) {
		if ((val = pcn_csr_read(pcnp, PCN_CSR_EXTCTL1)) &
		    PCN_EXTCTL1_SPND)
			return;
		drv_usecwait(1000);
	}

	pcn_error(pcnp->pcn_dip, "Unable to suspend, EXTCTL1 was 0x%b", val,
	    PCN_EXTCTL1_STR);
}
Esempio n. 2
0
static int
pcn_irq_check_dis(device_t d)
{
struct pcn_softc *sc = device_get_softc(d);
/* This can be called from IRQ context -- since all register accesses
 * involve RAP we must take care to preserve it across this routine!
 */
u_int32_t rap = CSR_READ_4(sc, PCN_IO32_RAP);
u_int32_t csr;
int      rval;

	csr  = pcn_csr_read(sc, PCN_CSR_CSR);

	if ( PCN_CSR_INTR & csr ) {
		/* must not write 1 to any bit as this might clear things */
		pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_INTEN & ~(PCN_CSR_INTEN));
		rval = FILTER_HANDLED;
	} else {
		rval = FILTER_STRAY;
	}
	/* restore RAP */
	CSR_WRITE_4(sc, PCN_IO32_RAP, rap);
	return rval;
}
Esempio n. 3
0
static unsigned
pcn_intr(caddr_t arg1)
{
	pcn_t		*pcnp = (void *)arg1;
	mblk_t		*mp = NULL;
	uint32_t	status, status2;
	boolean_t	do_reset = B_FALSE;

	mutex_enter(&pcnp->pcn_intrlock);

	if (IS_SUSPENDED(pcnp)) {
		mutex_exit(&pcnp->pcn_intrlock);
		return (DDI_INTR_UNCLAIMED);
	}

	while ((status = pcn_csr_read(pcnp, PCN_CSR_CSR)) & PCN_CSR_INTR) {
		pcn_csr_write(pcnp, PCN_CSR_CSR, status);

		status2 = pcn_csr_read(pcnp, PCN_CSR_EXTCTL2);

		if (status & PCN_CSR_TINT) {
			mutex_enter(&pcnp->pcn_xmtlock);
			pcn_reclaim(pcnp);
			mutex_exit(&pcnp->pcn_xmtlock);
		}

		if (status & PCN_CSR_RINT)
			mp = pcn_receive(pcnp);

		if (status & PCN_CSR_ERR) {
			do_reset = B_TRUE;
			break;
		}

		/* timer interrupt */
		if (status2 & PCN_EXTCTL2_STINT) {
			/* ack it */
			PCN_CSR_SETBIT(pcnp, PCN_CSR_EXTCTL2,
			    PCN_EXTCTL2_STINT);

			if (pcn_watchdog(pcnp) != DDI_SUCCESS) {
				do_reset = B_TRUE;
				break;
			}
		}
	}

	if (do_reset) {
		mutex_enter(&pcnp->pcn_xmtlock);
		pcn_resetall(pcnp);
		mutex_exit(&pcnp->pcn_xmtlock);
		mutex_exit(&pcnp->pcn_intrlock);

		mii_reset(pcnp->pcn_mii);
	} else {
		mutex_exit(&pcnp->pcn_intrlock);
	}

	if (mp)
		mac_rx(pcnp->pcn_mh, NULL, mp);

	return (DDI_INTR_CLAIMED);
}
Esempio n. 4
0
static int
pcn_set_chipid(pcn_t *pcnp, uint32_t conf_id)
{
	char *name = NULL;
	uint32_t chipid;

	/*
	 * Note: we can *NOT* put the chip into 32-bit mode yet. If a
	 * lance ethernet device is present and pcn tries to attach, it can
	 * hang the device (requiring a hardware reset), since they only work
	 * in 16-bit mode.
	 *
	 * The solution is check using 16-bit operations first, and determine
	 * if 32-bit mode operations are supported.
	 *
	 * The safest way to do this is to read the PCI subsystem ID from
	 * BCR23/24 and compare that with the value read from PCI config
	 * space.
	 */
	chipid = pcn_bcr_read16(pcnp, PCN_BCR_PCISUBSYSID);
	chipid <<= 16;
	chipid |= pcn_bcr_read16(pcnp, PCN_BCR_PCISUBVENID);

	/*
	 * The test for 0x10001000 is a hack to pacify VMware, who's
	 * pseudo-PCnet interface is broken. Reading the subsystem register
	 * from PCI config space yields 0x00000000 while reading the same value
	 * from I/O space yields 0x10001000. It's not supposed to be that way.
	 */
	if (chipid == conf_id || chipid == 0x10001000) {
		/* We're in 16-bit mode. */
		chipid = pcn_csr_read16(pcnp, PCN_CSR_CHIPID1);
		chipid <<= 16;
		chipid |= pcn_csr_read16(pcnp, PCN_CSR_CHIPID0);
	} else {
		chipid = pcn_csr_read(pcnp, PCN_CSR_CHIPID1);
		chipid <<= 16;
		chipid |= pcn_csr_read(pcnp, PCN_CSR_CHIPID0);
	}

	chipid = CHIPID_PARTID(chipid);

	/* Set default value and override as needed */
	switch (chipid) {
	case Am79C970:
		name = "Am79C970 PCnet-PCI";
		pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
		return (DDI_FAILURE);
	case Am79C970A:
		name = "Am79C970A PCnet-PCI II";
		pcn_error(pcnp->pcn_dip, "Unsupported chip: %s", name);
		return (DDI_FAILURE);
	case Am79C971:
		name = "Am79C971 PCnet-FAST";
		break;
	case Am79C972:
		name = "Am79C972 PCnet-FAST+";
		break;
	case Am79C973:
		name = "Am79C973 PCnet-FAST III";
		break;
	case Am79C975:
		name = "Am79C975 PCnet-FAST III";
		break;
	case Am79C976:
		name = "Am79C976";
		break;
	case Am79C978:
		name = "Am79C978";
		break;
	default:
		name = "Unknown";
		pcn_error(pcnp->pcn_dip, "Unknown chip id 0x%x", chipid);
	}

	if (ddi_prop_update_string(DDI_DEV_T_NONE, pcnp->pcn_dip, "chipid",
	    name) != DDI_SUCCESS) {
		pcn_error(pcnp->pcn_dip, "Unable to set chipid property");
		return (DDI_FAILURE);
	}

	return (DDI_SUCCESS);
}