📄 sunlance.c
字号:
creg &= ~DMA_EN_ENETAUI; udelay(20); dregs->cond_reg = creg; udelay(200); } ll->rap = LE_CSR0; ll->rdp = LE_C0_INIT; /* Wait for the lance to complete initialization */ for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++) barrier(); if ((i == 100) || (ll->rdp & LE_C0_ERR)) { printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); if (lp->ledma) printk ("dcsr=%8.8x\n", (unsigned int) lp->ledma->regs->cond_reg); return -1; } /* Clear IDON by writing a "1", enable interrupts and start lance */ ll->rdp = LE_C0_IDON; ll->rdp = LE_C0_INEA | LE_C0_STRT; if (lp->ledma) lp->ledma->regs->cond_reg |= DMA_INT_ENAB; return 0;}static int lance_rx (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; int len; struct sk_buff *skb;#ifdef TEST_HITS printk ("["); for (i = 0; i < RX_RING_SIZE; i++) { if (i == lp->rx_new) printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X"); else printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1"); } printk ("]");#endif for (rd = &ib->brx_ring [lp->rx_new]; !((bits = rd->rmd1_bits) & LE_R1_OWN); rd = &ib->brx_ring [lp->rx_new]) { /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { lp->stats.rx_over_errors++; lp->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; if (bits & LE_R1_EOP) lp->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb (len+2); if (skb == 0) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; return 0; } lp->stats.rx_bytes += len; skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put (skb, len); /* make room */ eth_copy_and_sum(skb, (unsigned char *)&(ib->rx_buf [lp->rx_new][0]), len, 0); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); lp->stats.rx_packets++; } /* Return the packet to the pool */ rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; } return 0;}static int lance_tx (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; volatile struct lance_tx_desc *td; int i, j; int status; j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { td = &ib->btx_ring [i]; /* If we hit a packet not owned by us, stop */ if (td->tmd1_bits & LE_T1_OWN) break; if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; lp->stats.tx_errors++; if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; if (status & LE_T3_CLOS) { lp->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk("%s: Carrier Lost, trying %s\n", dev->name, lp->tpe?"TPE":"AUI"); /* Stop the lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; lance_init_ring (dev); load_csrs (lp); init_restart_lance (lp); return 0; } } /* Buffer errors and underflows turn off the * transmitter, restart the adapter. */ if (status & (LE_T3_BUF|LE_T3_UFL)) { lp->stats.tx_fifo_errors++; printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); /* Stop the lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; lance_init_ring (dev); load_csrs (lp); init_restart_lance (lp); return 0; } } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) { /* * So we don't count the packet more than once. */ td->tmd1_bits &= ~(LE_T1_POK); /* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE) lp->stats.collisions++; /* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE) lp->stats.collisions += 2; lp->stats.tx_packets++; } j = (j + 1) & TX_RING_MOD_MASK; } lp->tx_old = j; return 0;}static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs){ struct device *dev = (struct device *)dev_id; struct lance_private *lp = (struct lance_private *)dev->priv; volatile struct lance_regs *ll = lp->ll; int csr0; if (dev->interrupt) printk ("%s: again", dev->name); dev->interrupt = 1; ll->rap = LE_CSR0; csr0 = ll->rdp; /* Acknowledge all the interrupt sources ASAP */ ll->rdp = csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT); if ((csr0 & LE_C0_ERR)) { /* Clear the error condition */ ll->rdp = LE_C0_BABL | LE_C0_ERR | LE_C0_MISS | LE_C0_CERR | LE_C0_MERR; } if (csr0 & LE_C0_RINT) lance_rx (dev); if (csr0 & LE_C0_TINT) lance_tx (dev); if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { dev->tbusy = 0; mark_bh (NET_BH); } if (csr0 & LE_C0_BABL) lp->stats.tx_errors++; if (csr0 & LE_C0_MISS) lp->stats.rx_errors++; if (csr0 & LE_C0_MERR) { struct sparc_dma_registers *dregs = lp->ledma->regs; unsigned long tst = (unsigned long)dregs->st_addr; printk ("%s: Memory error, status %04x, addr %06lx\n", dev->name, csr0, tst & 0xffffff); ll->rdp = LE_C0_STOP; if (lp->ledma) lp->ledma->regs->cond_reg |= DMA_FIFO_INV; lance_init_ring (dev); load_csrs (lp); init_restart_lance (lp); dev->tbusy = 0; } ll->rdp = LE_C0_INEA; dev->interrupt = 0;}struct device *last_dev = 0;static int lance_open (struct device *dev){ struct lance_private *lp = (struct lance_private *)dev->priv; volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int status = 0; last_dev = dev; if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) { printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq)); return -EAGAIN; } /* Stop the Lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; /* On the 4m, setup the ledma to provide the upper bits for buffers */ if (lp->ledma) lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000; /* Set mode and clear multicast filter only at device open, so that lance_init_ring() called at any error will not forget multicast filters. BTW it is common bug in all lance drivers! --ANK */ ib->mode = 0; ib->filter [0] = 0; ib->filter [1] = 0; lance_init_ring (dev); load_csrs (lp); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; status = init_restart_lance (lp);#if 0 /* To emulate SunOS, we add a route to the local network */ rt_add (RTF_UP, dev->pa_addr & ip_get_mask (dev->pa_addr), ip_get_mask (dev->pa_addr), 0, dev, dev->mtu, 0, 0);#endif if (!status && lp->auto_select) { /* * Build a fake network packet and send it to ourselfs. */ volatile struct lance_init_block *ib = lp->init_block; volatile unsigned long flush; unsigned char packet[ETH_ZLEN]; struct ethhdr *eth = (struct ethhdr *)packet; int i, entry; memset(packet, 0, ETH_ZLEN); for (i = 0; i < 6; i++) { eth->h_dest[i] = dev->dev_addr[i]; eth->h_source[i] = dev->dev_addr[i]; } entry = lp->tx_new & TX_RING_MOD_MASK; ib->btx_ring[entry].length = (-ETH_ZLEN) | 0xf000; ib->btx_ring[entry].misc = 0; memcpy((char *)&ib->tx_buf[entry][0], packet, ETH_ZLEN); ib->btx_ring[entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK; ll->rdp = LE_C0_INEA | LE_C0_TDMD; flush = ll->rdp; } if (!status) MOD_INC_USE_COUNT; return status;}static int lance_close (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_regs *ll = lp->ll; dev->start = 0; dev->tbusy = 1; del_timer(&lp->multicast_timer); /* Stop the card */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; free_irq (dev->irq, (void *) dev); MOD_DEC_USE_COUNT; return 0;}static inline int lance_reset (struct device *dev){ struct lance_private *lp = (struct lance_private *)dev->priv; volatile struct lance_regs *ll = lp->ll; int status; /* Stop the lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; /* On the 4m, reset the dma too */ if (lp->ledma) { printk ("resetting ledma\n"); lp->ledma->regs->cond_reg |= DMA_RST_ENET; udelay (200); lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000; } lance_init_ring (dev); load_csrs (lp); dev->trans_start = jiffies; dev->interrupt = 0; dev->start = 1; dev->tbusy = 0; status = init_restart_lance (lp);#ifdef DEBUG_DRIVER printk ("Lance restart=%d\n", status);#endif return status;}static int lance_start_xmit (struct sk_buff *skb, struct device *dev){ struct lance_private *lp = (struct lance_private *)dev->priv; volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; volatile unsigned long flush; unsigned long flags; int entry, skblen, len; if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 100) return 1; printk ("%s: transmit timed out, status %04x, reset\n", dev->name, ll->rdp); lp->stats.tx_errors++; lance_reset (dev); return 1; } skblen = skb->len; save_and_cli(flags); if (!TX_BUFFS_AVAIL) { restore_flags(flags); return 1; } len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; lp->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; ib->btx_ring [entry].length = (-len) | 0xf000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -