📄 3c515.c
字号:
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. */ dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; 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); MOD_INC_USE_COUNT; return 0;}static void vortex_timer(unsigned long data){#ifdef AUTOMEDIA struct device *dev = (struct device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; int ok = 0; if (vortex_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 (vortex_debug > 1) printk("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else if (vortex_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 (vortex_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 (vortex_debug > 1) printk("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (vortex_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 (vortex_debug > 1) printk("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name);#endif /* AUTOMEDIA*/ return;}static intvortex_start_xmit(struct sk_buff *skb, struct device *dev){ struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; int i; /* Min. wait before assuming a Tx failed == 400ms. */ if (tickssofar < 400*HZ/1000) /* We probably aren't empty. */ return 1; printk("%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("%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; /* dev->tbusy = 0;*/ vp->stats.tx_errors++; vp->stats.tx_dropped++; return 0; /* Yes, silently *drop* the packet! */ } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } 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 (vortex_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; dev->tbusy = 0; } 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); /* dev->tbusy will be cleared 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) { dev->tbusy = 0; } 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) { dev->tbusy = 0; } 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 (vortex_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. */ } } return 0;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs){ /* Use the now-standard shared IRQ implementation. */ struct device *dev = dev_id; struct vortex_private *lp; int ioaddr, status; int latency; int i = max_interrupt_work; if (test_and_set_bit(0, (void*)&dev->interrupt)) { printk("%s: Re-entering the interrupt handler.\n", dev->name); return; } ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); lp = (struct vortex_private *)dev->priv; status = inw(ioaddr + EL3_STATUS); if (vortex_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("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", dev->name, status, dev->start); FREE_IRQ(dev->irq, dev); } } do { if (vortex_debug > 5) printk("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) vortex_rx(dev); if (status & TxAvailable) { if (vortex_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); dev->tbusy = 0; mark_bh(NET_BH); } 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(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)) { lp->tx_full= 0; dev->tbusy = 0; mark_bh(NET_BH); } }#ifdef VORTEX_BUS_MASTER if (status & DMADone) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ dev->tbusy = 0; dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */ mark_bh(NET_BH); }#endif if (status & UpComplete) { boomerang_rx(dev); outw(AckIntr | UpComplete, ioaddr + EL3_CMD); } if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts at once. */ if (status & RxEarly) { /* Rx early is unused. */ vortex_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat = 0; if (vortex_debug > 4) printk("%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* DEBUG HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) { int win, reg; printk("%s: Updating stats failed, disabling stats as an" " interrupt source.\n", dev->name); for (win = 0; win < 8; win++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -