/* * 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); }
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; }
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); }
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); }