📄 eepro100.c
字号:
dev->if_port = sp->default_port; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; /* Start the chip's Tx process and unmask interrupts. */ /* Todo: verify that we must wait for previous command completion. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer); outw(CU_START, ioaddr + SCBCmd); /* Setup the chip and configure the multicast list. */ sp->mc_setup_frm = NULL; sp->mc_setup_frm_len = 0; sp->mc_setup_busy = 0; sp->rx_mode = -1; /* Invalid -> always reset the mode. */ set_rx_mode(dev); if (speedo_debug > 2) { printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", dev->name, inw(ioaddr + SCBStatus)); } wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_DUMPSTATS, ioaddr + SCBCmd); /* * Request the IRQ last, after we have set up all data structures. * It would be bad to get an interrupt before we're ready. */ if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, "Intel EtherExpress Pro 10/100 Ethernet", dev)) { return -EAGAIN; } /* No need to wait for the command unit to accept here. */ if ((sp->phy[0] & 0x8000) == 0) mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); MOD_INC_USE_COUNT; /* Set the timer. The timer serves a dual purpose: 1) to monitor the media interface (e.g. link beat) and perhaps switch to an alternate media type 2) to monitor Rx activity, and restart the Rx process if the receiver hangs. */ init_timer(&sp->timer); sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ sp->timer.data = (unsigned long)dev; sp->timer.function = &speedo_timer; /* timer handler */ add_timer(&sp->timer); return 0;}/* Media monitoring and control. */static void speedo_timer(unsigned long data){ struct device *dev = (struct device *)data; struct speedo_private *sp = (struct speedo_private *)dev->priv; if (speedo_debug > 3) { long ioaddr = dev->base_addr; printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); } if (sp->rx_mode < 0 || (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { /* We haven't received a packet in a Long Time. We might have been bitten by the receiver hang bug. This can be cleared by sending a set multicast list command. */ set_rx_mode(dev); } /* We must continue to monitor the media. */ sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ add_timer(&sp->timer);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidspeedo_init_rx_ring(struct device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; struct RxFD *rxf, *last_rxf = NULL; int i; sp->cur_rx = 0; for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); sp->rx_skbuff[i] = skb; if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ skb->dev = dev; /* Mark as being used by this device. */ rxf = (struct RxFD *)skb->tail; sp->rx_ringp[i] = rxf; skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) last_rxf->link = virt_to_bus(rxf); last_rxf = rxf; rxf->status = 0x00000001; /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557, we use it as a consistency check. */#ifdef final_version rxf->rx_buf_addr = 0xffffffff;#else rxf->rx_buf_addr = virt_to_bus(skb->tail);#endif rxf->count = 0; rxf->size = PKT_BUF_SZ; } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = 0xC0000002; /* '2' is flag value only. */ sp->last_rxf = last_rxf;}static void speedo_tx_timeout(struct device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " " %4.4x at %d/%d command %8.8x.\n", dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd), sp->dirty_tx, sp->cur_tx, sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) { printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", dev->name); outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), ioaddr + SCBPointer); outw(CU_START, ioaddr + SCBCmd); } else { outw(DRVR_INT, ioaddr + SCBCmd); }#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { int phy_addr = sp->phy[0] & 0x1f; mdio_write(ioaddr, phy_addr, 0, 0x0400); mdio_write(ioaddr, phy_addr, 1, 0x0000); mdio_write(ioaddr, phy_addr, 4, 0x0000); mdio_write(ioaddr, phy_addr, 0, 0x8000);#ifdef honor_default_port mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);#endif }#endif sp->stats.tx_errors++; dev->trans_start = jiffies; return;}static intspeedo_start_xmit(struct sk_buff *skb, struct device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; int entry; /* 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) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < TX_TIMEOUT - 2) return 1; if (tickssofar < TX_TIMEOUT) { /* Reap sent packets from the full Tx queue. */ outw(DRVR_INT, ioaddr + SCBCmd); return 1; } speedo_tx_timeout(dev); return 1; } /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ { /* Prevent interrupts from changing the Tx ring from underneath us. */ unsigned long flags; spin_lock_irqsave(&sp->lock, flags); /* Calculate the Tx descriptor entry. */ entry = sp->cur_tx++ % TX_RING_SIZE; sp->tx_skbuff[entry] = skb; /* Todo: be a little more clever about setting the interrupt bit. */ sp->tx_ring[entry].status = (CmdSuspend | CmdTx | CmdTxFlex) << 16; sp->tx_ring[entry].link = virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0); /* The data region is always in one buffer descriptor, Tx FIFO threshold of 256. */ sp->tx_ring[entry].count = 0x01208000; sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data); sp->tx_ring[entry].tx_buf_size0 = skb->len; /* Todo: perhaps leave the interrupt bit set if the Tx queue is more than half full. Argument against: we should be receiving packets and scavenging the queue. Argument for: if so, it shouldn't matter. */ sp->last_cmd->command &= ~(CmdSuspend | CmdIntr); sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; /* Trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_RESUME, ioaddr + SCBCmd); spin_unlock_irqrestore(&sp->lock, flags); } /* Leave room for set_rx_mode() to fill two entries. */ if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3) sp->tx_full = 1; else clear_bit(0, (void*)&dev->tbusy); dev->trans_start = jiffies; return 0;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct device *dev = (struct device *)dev_instance; struct speedo_private *sp; long ioaddr, boguscnt = max_interrupt_work; unsigned short status;#ifndef final_version if (dev == NULL) { printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq); return; }#endif ioaddr = dev->base_addr; sp = (struct speedo_private *)dev->priv; spin_lock(&sp->lock);#ifndef final_version dev->interrupt = 1;#endif do { status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ outw(status & 0xfc00, ioaddr + SCBStatus); if (speedo_debug > 4) printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", dev->name, status); if ((status & 0xfc00) == 0) break; if (status & 0x4000) /* Packet received. */ speedo_rx(dev); if (status & 0x1000) { if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */ outw(RX_RESUMENR, ioaddr + SCBCmd); else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */ /* No idea of what went wrong. Restart the receiver. */ outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), ioaddr + SCBPointer); outw(RX_START, ioaddr + SCBCmd); } sp->stats.rx_errors++; } /* User interrupt, Command/Tx unit interrupt or CU not active. */ if (status & 0xA400) { unsigned int dirty_tx = sp->dirty_tx; while (sp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; int status = sp->tx_ring[entry].status; if (speedo_debug > 5) printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", entry, status); if ((status & StatusComplete) == 0) break; /* It still hasn't been processed. */ /* Free the original skb. */ if (sp->tx_skbuff[entry]) { sp->stats.tx_packets++; /* Count only user packets. */ sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; /* Count transmitted bytes */ dev_free_skb(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; } else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16) sp->mc_setup_busy = 0; dirty_tx++; }#ifndef final_version if (sp->cur_tx - dirty_tx > TX_RING_SIZE) { printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," " full=%d.\n", dirty_tx, sp->cur_tx, sp->tx_full); dirty_tx += TX_RING_SIZE; }#endif if (sp->tx_full && dev->tbusy && dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); } sp->dirty_tx = dirty_tx; } if (--boguscnt < 0) { printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", dev->name, status); /* Clear all interrupt sources. */ outl(0xfc00, ioaddr + SCBStatus); break; } } while (1); if (speedo_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); dev->interrupt = 0; spin_unlock(&sp->lock); return;}static intspeedo_rx(struct device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry = sp->cur_rx % RX_RING_SIZE; int status; int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ while (sp->rx_ringp[entry] != NULL && (status = sp->rx_ringp[entry]->status) & RxComplete) { if (--rx_work_limit < 0) break; if (speedo_debug > 4) printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, sp->rx_ringp[entry]->count & 0x3fff); if ((status & (RxErrTooBig|RxOK)) != RxOK) { if (status & RxErrTooBig) printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " "status %8.8x!\n", dev->name, status); else if ( ! (status & 0x2000)) { /* There was a fatal error. This *should* be impossible. */ sp->stats.rx_errors++; printk(KERN_ERR "%s: Anomalous event in speedo_rx(), " "status %8.8x.\n", dev->name, status); } } else { int pkt_len = sp->rx_ringp[entry]->count & 0x3fff; struct sk_buff *skb; /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */#if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len, 0); skb_put(skb, pkt_len);#else memcpy(skb_put(skb, pkt_len), bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);#endif } else { void *temp; /* Pass up the already-filled skbuff. */ skb = sp->rx_skbuff[entry]; if (skb == NULL) { printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", dev->name); break; } sp->rx_skbuff[entry] = NULL; temp = skb_put(skb, pkt_len); if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) printk(KERN_ERR "%s: Rx consistency error -- the skbuff " "addresses do not match in speedo_rx: %p vs. %p " "/ %p.\n", dev->name, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), skb->head, temp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -