static void txp_intr(void *vsc) { struct txp_softc *sc = vsc; struct txp_hostvar *hv = sc->sc_hostvar; u_int32_t isr; /* mask all interrupts */ WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF | TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 | TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | TXP_INT_LATCH); isr = READ_REG(sc, TXP_ISR); while (isr) { WRITE_REG(sc, TXP_ISR, isr); if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff)) txp_rx_reclaim(sc, &sc->sc_rxhir); if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff)) txp_rx_reclaim(sc, &sc->sc_rxlor); if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx) txp_rxbuf_reclaim(sc); if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons != TXP_OFFSET2IDX(*(sc->sc_txhir.r_off)))) txp_tx_reclaim(sc, &sc->sc_txhir); if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons != TXP_OFFSET2IDX(*(sc->sc_txlor.r_off)))) txp_tx_reclaim(sc, &sc->sc_txlor); isr = READ_REG(sc, TXP_ISR); } /* unmask all interrupts */ WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3); if_devstart(&sc->sc_arpcom.ac_if); }
static void ep_if_watchdog(struct ifnet *ifp) { struct ep_softc *sc = ifp->if_softc; /* if_printf(ifp, "watchdog\n"); log(LOG_ERR, "%s: watchdog\n", ifp->if_xname); ifp->if_oerrors++; */ if (sc->gone) { return; } ifq_clr_oactive(&ifp->if_snd); if_devstart(ifp); ep_intr(ifp->if_softc); }
static int wi_pci_resume(device_t dev) { struct wi_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; wlan_serialize_enter(); if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { wlan_serialize_exit(); return (0); } if (ifp->if_flags & IFF_UP) { ifp->if_init(ifp->if_softc); if (ifp->if_flags & IFF_RUNNING) if_devstart(ifp); } wlan_serialize_exit(); return (0); }
void sn_intr(void *arg) { int status, interrupts; struct sn_softc *sc = (struct sn_softc *) arg; struct ifnet *ifp = &sc->arpcom.ac_if; /* * Chip state registers */ u_char mask; u_char packet_no; u_short tx_status; u_short card_stats; /* * Clear the watchdog. */ ifp->if_timer = 0; SMC_SELECT_BANK(2); /* * Obtain the current interrupt mask and clear the hardware mask * while servicing interrupts. */ mask = inb(BASE + INTR_MASK_REG_B); outb(BASE + INTR_MASK_REG_B, 0x00); /* * Get the set of interrupts which occurred and eliminate any which * are masked. */ interrupts = inb(BASE + INTR_STAT_REG_B); status = interrupts & mask; /* * Now, process each of the interrupt types. */ /* * Receive Overrun. */ if (status & IM_RX_OVRN_INT) { /* * Acknowlege Interrupt */ SMC_SELECT_BANK(2); outb(BASE + INTR_ACK_REG_B, IM_RX_OVRN_INT); IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1); } /* * Got a packet. */ if (status & IM_RCV_INT) { #if 1 int packet_number; SMC_SELECT_BANK(2); packet_number = inw(BASE + FIFO_PORTS_REG_W); if (packet_number & FIFO_REMPTY) { /* * we got called , but nothing was on the FIFO */ kprintf("sn: Receive interrupt with nothing on FIFO\n"); goto out; } #endif snread(ifp); } /* * An on-card memory allocation came through. */ if (status & IM_ALLOC_INT) { /* * Disable this interrupt. */ mask &= ~IM_ALLOC_INT; ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); snresume(&sc->arpcom.ac_if); } /* * TX Completion. Handle a transmit error message. This will only be * called when there is an error, because of the AUTO_RELEASE mode. */ if (status & IM_TX_INT) { /* * Acknowlege Interrupt */ SMC_SELECT_BANK(2); outb(BASE + INTR_ACK_REG_B, IM_TX_INT); packet_no = inw(BASE + FIFO_PORTS_REG_W); packet_no &= FIFO_TX_MASK; /* * select this as the packet to read from */ outb(BASE + PACKET_NUM_REG_B, packet_no); /* * Position the pointer to the first word from this packet */ outw(BASE + POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000); /* * Fetch the TX status word. The value found here will be a * copy of the EPH_STATUS_REG_W at the time the transmit * failed. */ tx_status = inw(BASE + DATA_REG_W); if (tx_status & EPHSR_TX_SUC) { device_printf(sc->dev, "Successful packet caused interrupt\n"); } else { IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1); } if (tx_status & EPHSR_LATCOL) IFNET_STAT_INC(&sc->arpcom.ac_if, collisions, 1); /* * Some of these errors will have disabled transmit. * Re-enable transmit now. */ SMC_SELECT_BANK(0); #ifdef SW_PAD outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE); #else outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE | TCR_PAD_ENABLE); #endif /* SW_PAD */ /* * kill the failed packet. Wait for the MMU to be un-busy. */ SMC_SELECT_BANK(2); while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ ; outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT); /* * Attempt to queue more transmits. */ ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); if_devstart(&sc->arpcom.ac_if); } /* * Transmit underrun. We use this opportunity to update transmit * statistics from the card. */ if (status & IM_TX_EMPTY_INT) { /* * Acknowlege Interrupt */ SMC_SELECT_BANK(2); outb(BASE + INTR_ACK_REG_B, IM_TX_EMPTY_INT); /* * Disable this interrupt. */ mask &= ~IM_TX_EMPTY_INT; SMC_SELECT_BANK(0); card_stats = inw(BASE + COUNTER_REG_W); /* * Single collisions */ IFNET_STAT_INC(&sc->arpcom.ac_if, collisions, card_stats & ECR_COLN_MASK); /* * Multiple collisions */ IFNET_STAT_INC(&sc->arpcom.ac_if, collisions, (card_stats & ECR_MCOLN_MASK) >> 4); SMC_SELECT_BANK(2); /* * Attempt to enqueue some more stuff. */ ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); if_devstart(&sc->arpcom.ac_if); }
/* Resume a packet transmit operation after a memory allocation * has completed. * * This is basically a hacked up copy of snstart() which handles * a completed memory allocation the same way snstart() does. * It then passes control to snstart to handle any other queued * packets. */ static void snresume(struct ifnet *ifp) { struct sn_softc *sc = ifp->if_softc; u_int len; struct mbuf *m; struct mbuf *top; int pad; int mask; u_short length; u_short numPages; u_short pages_wanted; u_char packet_no; if (sc->pages_wanted < 0) return; pages_wanted = sc->pages_wanted; sc->pages_wanted = -1; /* * Sneak a peek at the next packet */ m = ifq_dequeue(&ifp->if_snd); if (m == NULL) { kprintf("%s: snresume() with nothing to send\n", ifp->if_xname); return; } /* * Compute the frame length and set pad to give an overall even * number of bytes. Below we assume that the packet length is even. */ for (len = 0, top = m; m; m = m->m_next) len += m->m_len; pad = (len & 1); /* * We drop packets that are too large. Perhaps we should truncate * them instead? */ if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { kprintf("%s: large packet discarded (B)\n", ifp->if_xname); IFNET_STAT_INC(ifp, oerrors, 1); m_freem(top); return; } #ifdef SW_PAD /* * If HW padding is not turned on, then pad to ETHER_MIN_LEN. */ if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; #endif /* SW_PAD */ length = pad + len; /* * The MMU wants the number of pages to be the number of 256 byte * 'pages', minus 1 (A packet can't ever have 0 pages. We also * include space for the status word, byte count and control bytes in * the allocation request. */ numPages = (length + 6) >> 8; SMC_SELECT_BANK(2); /* * The memory allocation completed. Check the results. If it failed, * we simply set a watchdog timer and hope for the best. */ packet_no = inb(BASE + ALLOC_RESULT_REG_B); if (packet_no & ARR_FAILED) { kprintf("%s: Memory allocation failed. Weird.\n", ifp->if_xname); ifp->if_timer = 1; ifq_prepend(&ifp->if_snd, top); goto try_start; } /* * We have a packet number, so tell the card to use it. */ outb(BASE + PACKET_NUM_REG_B, packet_no); /* * Now, numPages should match the pages_wanted recorded when the * memory allocation was initiated. */ if (pages_wanted != numPages) { kprintf("%s: memory allocation wrong size. Weird.\n", ifp->if_xname); /* * If the allocation was the wrong size we simply release the * memory once it is granted. Wait for the MMU to be un-busy. */ while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ ; outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT); ifq_prepend(&ifp->if_snd, top); return; } /* * Point to the beginning of the packet */ outw(BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000); /* * Send the packet length (+6 for status, length and control byte) * and the status word (set to zeros) */ outw(BASE + DATA_REG_W, 0); outb(BASE + DATA_REG_B, (length + 6) & 0xFF); outb(BASE + DATA_REG_B, (length + 6) >> 8); /* * Push out the data to the card. */ for (m = top; m != NULL; m = m->m_next) { /* * Push out words. */ outsw(BASE + DATA_REG_W, mtod(m, caddr_t), m->m_len / 2); /* * Push out remaining byte. */ if (m->m_len & 1) outb(BASE + DATA_REG_B, *(mtod(m, caddr_t) + m->m_len - 1)); } /* * Push out padding. */ while (pad > 1) { outw(BASE + DATA_REG_W, 0); pad -= 2; } if (pad) outb(BASE + DATA_REG_B, 0); /* * Push out control byte and unused packet byte The control byte is 0 * meaning the packet is even lengthed and no special CRC handling is * desired. */ outw(BASE + DATA_REG_W, 0); /* * Enable the interrupts and let the chipset deal with it Also set a * watchdog in case we miss the interrupt. */ mask = inb(BASE + INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); outb(BASE + INTR_MASK_REG_B, mask); sc->intr_mask = mask; outw(BASE + MMU_CMD_REG_W, MMUCR_ENQUEUE); BPF_MTAP(ifp, top); IFNET_STAT_INC(ifp, opackets, 1); m_freem(top); try_start: /* * Now pass control to snstart() to queue any additional packets */ ifq_clr_oactive(&ifp->if_snd); if_devstart(ifp); /* * We've sent something, so we're active. Set a watchdog in case the * TX_EMPTY interrupt is lost. */ ifq_set_oactive(&ifp->if_snd); ifp->if_timer = 1; }
/* * Reset and initialize the chip */ void sninit(void *xsc) { struct sn_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int flags; int mask; /* * This resets the registers mostly to defaults, but doesn't affect * EEPROM. After the reset cycle, we pause briefly for the chip to * be happy. */ SMC_SELECT_BANK(0); outw(BASE + RECV_CONTROL_REG_W, RCR_SOFTRESET); SMC_DELAY(); outw(BASE + RECV_CONTROL_REG_W, 0x0000); SMC_DELAY(); SMC_DELAY(); outw(BASE + TXMIT_CONTROL_REG_W, 0x0000); /* * Set the control register to automatically release succesfully * transmitted packets (making the best use out of our limited * memory) and to enable the EPH interrupt on certain TX errors. */ SMC_SELECT_BANK(1); outw(BASE + CONTROL_REG_W, (CTR_AUTO_RELEASE | CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE)); /* Set squelch level to 240mV (default 480mV) */ flags = inw(BASE + CONFIG_REG_W); flags |= CR_SET_SQLCH; outw(BASE + CONFIG_REG_W, flags); /* * Reset the MMU and wait for it to be un-busy. */ SMC_SELECT_BANK(2); outw(BASE + MMU_CMD_REG_W, MMUCR_RESET); while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ ; /* * Disable all interrupts */ outb(BASE + INTR_MASK_REG_B, 0x00); sn_setmcast(sc); /* * Set the transmitter control. We want it enabled. */ flags = TCR_ENABLE; #ifndef SW_PAD /* * I (GB) have been unlucky getting this to work. */ flags |= TCR_PAD_ENABLE; #endif /* SW_PAD */ outw(BASE + TXMIT_CONTROL_REG_W, flags); /* * Now, enable interrupts */ SMC_SELECT_BANK(2); mask = IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT; outb(BASE + INTR_MASK_REG_B, mask); sc->intr_mask = mask; sc->pages_wanted = -1; /* * Mark the interface running but not active. */ ifp->if_flags |= IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); /* * Attempt to push out any waiting packets. */ if_devstart(ifp); }
void ep_intr(void *arg) { struct ep_softc *sc = arg; struct ifnet *ifp = &sc->arpcom.ac_if; int status; /* * quick fix: Try to detect an interrupt when the card goes away. */ if (sc->gone || inw(BASE + EP_STATUS) == 0xffff) { return; } outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ rescan: while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) { /* first acknowledge all interrupt sources */ outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK)); if (status & (S_RX_COMPLETE | S_RX_EARLY)) epread(sc); if (status & S_TX_AVAIL) { /* we need ACK */ ifp->if_timer = 0; ifq_clr_oactive(&ifp->if_snd); GO_WINDOW(1); inw(BASE + EP_W1_FREE_TX); if_devstart(ifp); } if (status & S_CARD_FAILURE) { ifp->if_timer = 0; #ifdef EP_LOCAL_STATS kprintf("\n"); if_printf(ifp, "\n\tStatus: %x\n", status); GO_WINDOW(4); kprintf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG)); kprintf("\tStat: %x\n", sc->stat); kprintf("\tIpackets=%d, Opackets=%d\n", ifp->if_ipackets, ifp->if_opackets); kprintf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n", sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf, sc->rx_overrunl, sc->tx_underrun); #else #ifdef DIAGNOSTIC if_printf(ifp, "Status: %x (input buffer overflow)\n", status); #else IFNET_STAT_INC(ifp, ierrors, 1); #endif #endif ep_if_init(sc); return; } if (status & S_TX_COMPLETE) { ifp->if_timer = 0; /* we need ACK. we do it at the end */ /* * We need to read TX_STATUS until we get a 0 status in order to * turn off the interrupt flag. */ while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { if (status & TXS_SUCCES_INTR_REQ); else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) { outw(BASE + EP_COMMAND, TX_RESET); if (status & TXS_UNDERRUN) { #ifdef EP_LOCAL_STATS sc->tx_underrun++; #endif } else { if (status & TXS_JABBER); else /* TXS_MAX_COLLISION - we shouldn't get here */ IFNET_STAT_INC(ifp, collisions, 1); } IFNET_STAT_INC(ifp, oerrors, 1); outw(BASE + EP_COMMAND, TX_ENABLE); /* * To have a tx_avail_int but giving the chance to the * Reception */ if (!ifq_is_empty(&ifp->if_snd)) outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); } outb(BASE + EP_W1_TX_STATUS, 0x0); /* pops up the next * status */ } /* while */ ifq_clr_oactive(&ifp->if_snd); GO_WINDOW(1); inw(BASE + EP_W1_FREE_TX); if_devstart(ifp); } /* end TX_COMPLETE */ } outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ if ((status = inw(BASE + EP_STATUS)) & S_5_INTS) goto rescan; /* re-enable Ints */ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); }
/* * The order in here seems important. Otherwise we may not receive * interrupts. ?! */ static void ep_if_init(void *xsc) { struct ep_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; int i; if (sc->gone) return; crit_enter(); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); GO_WINDOW(0); outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); GO_WINDOW(4); outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP); GO_WINDOW(0); /* Disable the card */ outw(BASE + EP_W0_CONFIG_CTRL, 0); /* Enable the card */ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); GO_WINDOW(2); /* Reload the ether_addr. */ for (i = 0; i < 6; i++) outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); outw(BASE + EP_COMMAND, RX_RESET); outw(BASE + EP_COMMAND, TX_RESET); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); /* Window 1 is operating window */ GO_WINDOW(1); for (i = 0; i < 31; i++) inb(BASE + EP_W1_TX_STATUS); /* get rid of stray intr's */ outw(BASE + EP_COMMAND, ACK_INTR | 0xff); outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); if (ifp->if_flags & IFF_PROMISC) outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST | FIL_ALL); else outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST); if (!sc->epb.mii_trans) { ep_ifmedia_upd(ifp); } outw(BASE + EP_COMMAND, RX_ENABLE); outw(BASE + EP_COMMAND, TX_ENABLE); ifp->if_flags |= IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); /* just in case */ #ifdef EP_LOCAL_STATS sc->rx_no_first = sc->rx_no_mbuf = sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; #endif EP_FSET(sc, F_RX_FIRST); if (sc->top) { m_freem(sc->top); sc->top = sc->mcur = 0; } outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); /* * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up * any that we had in case we're being called from intr or somewhere * else. */ GO_WINDOW(1); if_devstart(ifp); crit_exit(); }