static void restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; fcc_t __iomem *fccp = fep->fcc.fccp; fcc_c_t __iomem *fcccp = fep->fcc.fcccp; fcc_enet_t __iomem *ep = fep->fcc.ep; dma_addr_t rx_bd_base_phys, tx_bd_base_phys; u16 paddrh, paddrm, paddrl; const unsigned char *mac; int i; C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) out_8((u8 __iomem *)ep + i, 0); /* get physical address */ rx_bd_base_phys = fep->ring_mem_addr; tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; /* point to bds */ W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); /* Set maximum bytes per receive buffer. * It must be a multiple of 32. */ W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); /* Allocate space in the reserved FCC area of DPRAM for the * internal buffers. No one uses this space (yet), so we * can do this. Later, we will add resource management for * this area. */ W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset); W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32); W16(ep, fen_padptr, fpi->dpram_offset + 64); /* fill with special symbol... */ memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); W32(ep, fen_genfcc.fcc_rbptr, 0); W32(ep, fen_genfcc.fcc_tbptr, 0); W32(ep, fen_genfcc.fcc_rcrc, 0); W32(ep, fen_genfcc.fcc_tcrc, 0); W16(ep, fen_genfcc.fcc_res1, 0); W32(ep, fen_genfcc.fcc_res2, 0); /* no CAM */ W32(ep, fen_camptr, 0); /* Set CRC preset and mask */ W32(ep, fen_cmask, 0xdebb20e3); W32(ep, fen_cpres, 0xffffffff); W32(ep, fen_crcec, 0); /* CRC Error counter */ W32(ep, fen_alec, 0); /* alignment error counter */ W32(ep, fen_disfc, 0); /* discard frame counter */ W16(ep, fen_retlim, 15); /* Retry limit threshold */ W16(ep, fen_pper, 0); /* Normal persistence */ /* set group address */ W32(ep, fen_gaddrh, fep->fcc.gaddrh); W32(ep, fen_gaddrl, fep->fcc.gaddrh); /* Clear hash filter tables */ W32(ep, fen_iaddrh, 0); W32(ep, fen_iaddrl, 0); /* Clear the Out-of-sequence TxBD */ W16(ep, fen_tfcstat, 0); W16(ep, fen_tfclen, 0); W32(ep, fen_tfcptr, 0); W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ /* set address */ mac = dev->dev_addr; paddrh = ((u16)mac[5] << 8) | mac[4]; paddrm = ((u16)mac[3] << 8) | mac[2]; paddrl = ((u16)mac[1] << 8) | mac[0]; W16(ep, fen_paddrh, paddrh); W16(ep, fen_paddrm, paddrm); W16(ep, fen_paddrl, paddrl); W16(ep, fen_taddrh, 0); W16(ep, fen_taddrm, 0); W16(ep, fen_taddrl, 0); W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ /* Clear stat counters, in case we ever enable RMON */ W32(ep, fen_octc, 0); W32(ep, fen_colc, 0); W32(ep, fen_broc, 0); W32(ep, fen_mulc, 0); W32(ep, fen_uspc, 0); W32(ep, fen_frgc, 0); W32(ep, fen_ospc, 0); W32(ep, fen_jbrc, 0); W32(ep, fen_p64c, 0); W32(ep, fen_p65c, 0); W32(ep, fen_p128c, 0); W32(ep, fen_p256c, 0); W32(ep, fen_p512c, 0); W32(ep, fen_p1024c, 0); W16(ep, fen_rfthr, 0); /* Suggested by manual */ W16(ep, fen_rfcnt, 0); W16(ep, fen_cftype, 0); fs_init_bds(dev); /* adjust to speed (for RMII mode) */ if (fpi->use_rmii) { if (fep->phydev->speed == 100) C8(fcccp, fcc_gfemr, 0x20); else S8(fcccp, fcc_gfemr, 0x20); } fcc_cr_cmd(fep, CPM_CR_INIT_TRX); /* clear events */ W16(fccp, fcc_fcce, 0xffff); /* Enable interrupts we wish to service */ W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); /* Set GFMR to enable Ethernet operating mode */ W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); /* set sync/delimiters */ W16(fccp, fcc_fdsr, 0xd555); W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); if (fpi->use_rmii) S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); /* adjust to duplex mode */ if (fep->phydev->duplex) S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); else C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); /* Restore multicast and promiscuous settings */ set_multicast_list(dev); S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); }
/* The EL3 interrupt handler. */ static irqreturn_t el3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr; __u16 status; int i = 0, handled = 1; if (!netif_device_present(dev)) return IRQ_NONE; ioaddr = dev->base_addr; DEBUG(3, "%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); spin_lock(&lp->lock); while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { if ((status & 0xe000) != 0x2000) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); handled = 0; break; } if (status & RxComplete) el3_rx(dev); if (status & TxAvailable) { DEBUG(3, " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); } if (status & TxComplete) pop_tx_status(dev); if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); if (status & RxEarly) { /* Rx early is unused. */ el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & AdapterFailure) { u16 fifo_diag; EL3WINDOW(4); fifo_diag = inw(ioaddr + 4); EL3WINDOW(1); printk(KERN_WARNING "%s: adapter failure, FIFO diagnostic" " register %04x.\n", dev->name, fifo_diag); if (fifo_diag & 0x0400) { /* Tx overrun */ tc589_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } if (fifo_diag & 0x2000) { /* Rx underrun */ tc589_wait_for_completion(dev, RxReset); set_multicast_list(dev); outw(RxEnable, ioaddr + EL3_CMD); } outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); } } if (++i > 10) { printk(KERN_ERR "%s: infinite loop in interrupt, " "status %4.4x.\n", dev->name, status); /* Clear all interrupts */ outw(AckIntr | 0xFF, ioaddr + EL3_CMD); break; } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } lp->last_irq = jiffies; spin_unlock(&lp->lock); DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); return IRQ_RETVAL(handled); }