📄 3c515.c
字号:
EL3WINDOW(4); outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); for (i = 0; i < 10; i++) inb(ioaddr + i); inw(ioaddr + 10); inw(ioaddr + 12); /* New: On the Vortex we must also clear the BadSSD counter. */ EL3WINDOW(4); inb(ioaddr + 12); /* ..and on the Boomerang we enable the extra statistics bits. */ outw(0x0040, ioaddr + Wn4_NetDiag); /* Switch to register set 7 for normal use. */ EL3WINDOW(7); if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; if (corkscrew_debug > 2) printk("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; if (i < (RX_RING_SIZE - 1)) vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i + 1]); else vp->rx_ring[i].next = 0; vp->rx_ring[i].status = 0; /* Clear complete bit. */ vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000; skb = dev_alloc_skb(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = virt_to_bus(skb->tail); } vp->rx_ring[i - 1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ vp->cur_tx = vp->dirty_tx = 0; outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Tx ring. */ for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); } /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ netif_start_queue(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull | (vp->full_bus_master_tx ? DownComplete : TxAvailable) | (vp->full_bus_master_rx ? UpComplete : RxComplete) | (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, ioaddr + EL3_CMD); return 0;}static void corkscrew_timer(unsigned long data){#ifdef AUTOMEDIA struct net_device *dev = (struct net_device *) data; struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; unsigned long flags; int ok = 0; if (corkscrew_debug > 1) printk("%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); save_flags(flags); cli(); { int old_window = inw(ioaddr + EL3_CMD) >> 13; int media_status; EL3WINDOW(4); media_status = inw(ioaddr + Wn4_Media); switch (dev->if_port) { case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */ if (media_status & Media_LnkBeat) { ok = 1; if (corkscrew_debug > 1) printk("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else if (corkscrew_debug > 1) printk("%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); break; default: /* Other media types handled by Tx timeouts. */ if (corkscrew_debug > 1) printk("%s: Media %s is has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } if (!ok) { union wn3_config config; do { dev->if_port = media_tbl[dev->if_port].next; } while (!(vp->available_media & media_tbl[dev->if_port].mask)); if (dev->if_port == 8) { /* Go back to default. */ dev->if_port = vp->default_media; if (corkscrew_debug > 1) printk("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (corkscrew_debug > 1) printk("%s: Media selection failed, now trying %s port.\n", dev->name, media_tbl[dev->if_port].name); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); add_timer(&vp->timer); } outw((media_status & ~(Media_10TP | Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); EL3WINDOW(3); config.i = inl(ioaddr + Wn3_Config); config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); } EL3WINDOW(old_window); } restore_flags(flags); if (corkscrew_debug > 1) printk("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name);#endif /* AUTOMEDIA */ return;}static void corkscrew_timeout(struct net_device *dev){ int i; struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; printk(KERN_WARNING "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_WARNING "%s: Transmitter encountered 16 collisions -- network" " network cable problem?\n", dev->name);#ifndef final_version printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n", vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[0]); for (i = 0; i < TX_RING_SIZE; i++) { printk(" %d: %p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], vp->tx_ring[i].length, vp->tx_ring[i].status); }#endif /* Issue TX_RESET and TX_START commands. */ outw(TxReset, ioaddr + EL3_CMD); for (i = 20; i >= 0; i--) if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(TxEnable, ioaddr + EL3_CMD); dev->trans_start = jiffies; vp->stats.tx_errors++; vp->stats.tx_dropped++; netif_wake_queue(dev);}static int corkscrew_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; int ioaddr = dev->base_addr; /* Block a timer-based transmit from overlapping. */ netif_stop_queue(dev); if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */ /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry; unsigned long flags, i; if (vp->tx_full) /* No room to transmit with */ return 1; if (vp->cur_tx != 0) prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; else prev_entry = NULL; if (corkscrew_debug > 3) printk("%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); /* vp->tx_full = 1; */ vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; vp->tx_ring[entry].addr = virt_to_bus(skb->data); vp->tx_ring[entry].length = skb->len | 0x80000000; vp->tx_ring[entry].status = skb->len | 0x80000000; save_flags(flags); cli(); outw(DownStall, ioaddr + EL3_CMD); /* Wait for the stall to complete. */ for (i = 20; i >= 0; i--) if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) break; if (prev_entry) prev_entry->next = virt_to_bus(&vp->tx_ring[entry]); if (inl(ioaddr + DownListPtr) == 0) { outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); queued_packet++; } outw(DownUnstall, ioaddr + EL3_CMD); restore_flags(flags); vp->cur_tx++; if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) vp->tx_full = 1; else { /* Clear previous interrupt enable. */ if (prev_entry) prev_entry->status &= ~0x80000000; netif_wake_queue(dev); } dev->trans_start = jiffies; return 0; } /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO);#ifdef VORTEX_BUS_MASTER if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ outl((int) (skb->data), ioaddr + Wn7_MasterAddr); outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); /* queue will be woken at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { netif_wake_queue(dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD); }#else /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { netif_wake_queue(dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);#endif /* bus master */ dev->trans_start = jiffies; /* Clear the Tx status stack. */ { short tx_status; int i = 4; while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (corkscrew_debug > 2) printk("%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; if (tx_status & 0x30) { int j; outw(TxReset, ioaddr + EL3_CMD); for (j = 20; j >= 0; j--) if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; } outw(TxEnable, ioaddr + EL3_CMD); } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } vp->stats.tx_bytes += skb->len; return 0;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */static void corkscrew_interrupt(int irq, void *dev_id, struct pt_regs *regs){ /* Use the now-standard shared IRQ implementation. */ struct net_device *dev = dev_id; struct corkscrew_private *lp; int ioaddr, status; int latency; int i = max_interrupt_work; ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); lp = (struct corkscrew_private *) dev->priv; status = inw(ioaddr + EL3_STATUS); if (corkscrew_debug > 4) printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name, status, latency); if ((status & 0xE000) != 0xE000) { static int donedidthis = 0; /* Some interrupt controllers store a bogus interrupt from boot-time. Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ if (donedidthis++ > 100) { printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", dev->name, status, netif_running(dev)); free_irq(dev->irq, dev); } } do { if (corkscrew_debug > 5) printk("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) corkscrew_rx(dev); if (status & TxAvailable) { if (corkscrew_debug > 5) printk (" 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 & DownComplete) { unsigned int dirty_tx = lp->dirty_tx; while (lp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; if (inl(ioaddr + DownListPtr) == virt_to_bus(&lp->tx_ring[entry])) break; /* It still hasn't been processed. */ if (lp->tx_skbuff[entry]) { dev_kfree_skb_irq(lp-> tx_skbuff [entry]); lp->tx_skbuff[entry] = 0; } dirty_tx++; } lp->dirty_tx = dirty_tx; outw(AckIntr | DownComplete, ioaddr + EL3_CMD); if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -