📄 eepro100.c
字号:
long ioaddr = dev->base_addr; int phy_num = sp->phy[0] & 0x1f; /* We have MII and lost link beat. */ if ((sp->phy[0] & 0x8000) == 0) { int partner = mdio_read(ioaddr, phy_num, 5); if (partner != sp->partner) { int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0; if (speedo_debug > 2) { printk(KERN_DEBUG "%s: Link status change.\n", dev->name); printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", dev->name, sp->partner, partner, sp->advertising); } sp->partner = partner; if (flow_ctrl != sp->flow_ctrl) { sp->flow_ctrl = flow_ctrl; sp->rx_mode = -1; /* Trigger a reload. */ } /* Clear sticky bit. */ mdio_read(ioaddr, phy_num, 1); /* If link beat has returned... */ if (mdio_read(ioaddr, phy_num, 1) & 0x0004) dev->flags |= IFF_RUNNING; else dev->flags &= ~IFF_RUNNING; } } if (speedo_debug > 3) { 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. */ if (speedo_debug > 2) printk(KERN_DEBUG "%s: Sending a multicast list set command" " from a timer routine.\n", dev->name); 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);}static void speedo_show_state(struct net_device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv;#if 0 long ioaddr = dev->base_addr; int phy_num = sp->phy[0] & 0x1f;#endif int i; /* Print a few items for debugging. */ if (speedo_debug > 0) { int i; printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", dev->name, sp->cur_tx, sp->dirty_tx); for (i = 0; i < TX_RING_SIZE; i++) printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name, i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ', i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ', i, sp->tx_ring[i].status); } printk(KERN_DEBUG "%s: Printing Rx ring" " (next to receive into %u, dirty index %u).\n", dev->name, sp->cur_rx, sp->dirty_rx); for (i = 0; i < RX_RING_SIZE; i++) printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name, sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ', i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ', i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ', i, (sp->rx_ringp[i] != NULL) ? (unsigned)sp->rx_ringp[i]->status : 0);#if 0 for (i = 0; i < 16; i++) { /* FIXME: what does it mean? --SAW */ if (i == 6) i = 21; printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i)); }#endif}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidspeedo_init_rx_ring(struct net_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_le32desc(rxf); last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ sp->last_rxf = last_rxf;}static void speedo_purge_tx(struct net_device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry; while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { entry = sp->dirty_tx % TX_RING_SIZE; if (sp->tx_skbuff[entry]) { sp->stats.tx_errors++; dev_free_skb(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; } sp->dirty_tx++; } while (sp->mc_setup_head != NULL) { struct speedo_mc_block *t; if (speedo_debug > 1) printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); t = sp->mc_setup_head->next; kfree(sp->mc_setup_head); sp->mc_setup_head = t; } sp->mc_setup_tail = NULL; sp->tx_full = 0; netif_wake_queue(dev);}static void reset_mii(struct net_device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { int phy_addr = sp->phy[0] & 0x1f; int advertising = mdio_read(ioaddr, phy_addr, 4); int mii_bmcr = mdio_read(ioaddr, phy_addr, 0); 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]);#else mdio_read(ioaddr, phy_addr, 0); mdio_write(ioaddr, phy_addr, 0, mii_bmcr); mdio_write(ioaddr, phy_addr, 4, advertising);#endif }}static void speedo_tx_timeout(struct net_device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; int status = inw(ioaddr + SCBStatus); unsigned long flags; printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " " %4.4x at %d/%d command %8.8x.\n", dev->name, status, inw(ioaddr + SCBCmd), sp->dirty_tx, sp->cur_tx, sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); /* Trigger a stats dump to give time before the reset. */ speedo_get_stats(dev); speedo_show_state(dev);#if 0 if ((status & 0x00C0) != 0x0080 && (status & 0x003C) == 0x0010) { /* Only the command unit has stopped. */ 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(CUStart, ioaddr + SCBCmd); reset_mii(dev); } else {#else {#endif start_bh_atomic(); /* Ensure that timer routine doesn't run! */ del_timer(&sp->timer); end_bh_atomic(); /* Reset the Tx and Rx units. */ outl(PortReset, ioaddr + SCBPort); /* We may get spurious interrupts here. But I don't think that they may do much harm. 1999/12/09 SAW */ udelay(10); /* Disable interrupts. */ outw(SCBMaskAll, ioaddr + SCBCmd); synchronize_irq(); speedo_tx_buffer_gc(dev); /* Free as much as possible. It helps to recover from a hang because of out-of-memory. It also simplifies speedo_resume() in case TX ring is full or close-to-be full. */ speedo_purge_tx(dev); speedo_refill_rx_buffers(dev, 1); spin_lock_irqsave(&sp->lock, flags); speedo_resume(dev); sp->rx_mode = -1; dev->trans_start = jiffies; spin_unlock_irqrestore(&sp->lock, flags); set_rx_mode(dev); /* it takes the spinlock itself --SAW */ /* Reset MII transceiver. Do it before starting the timer to serialize mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */ reset_mii(dev); sp->timer.expires = RUN_AT(2*HZ); add_timer(&sp->timer); } return;}static intspeedo_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; int entry;#if ! defined(HAS_NETIF_QUEUE) if (test_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. */ unsigned long flags; /* Take a spinlock to make wait_for_cmd_done and sending the command atomic. --SAW */ spin_lock_irqsave(&sp->lock, flags); wait_for_cmd_done(ioaddr + SCBCmd); outw(SCBTriggerIntr, ioaddr + SCBCmd); spin_unlock_irqrestore(&sp->lock, flags); return 1; } speedo_tx_timeout(dev); return 1; }#endif { /* Prevent interrupts from changing the Tx ring from underneath us. */ unsigned long flags; spin_lock_irqsave(&sp->lock, flags); /* Check if there are enough space. */ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name); netif_stop_queue(dev); sp->tx_full = 1; spin_unlock_irqrestore(&sp->lock, flags); return 1; } /* Calculate the Tx descriptor entry. */ entry = sp->cur_tx++ % TX_RING_SIZE; sp->tx_skbuff[entry] = skb; sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex); if (!(entry & ((TX_RING_SIZE>>2)-1))) sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr); sp->tx_ring[entry].link = virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = virt_to_le32desc(&sp->tx_ring[entry].tx_buf_addr0); /* The data region is always in one buffer descriptor. */ sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32desc(skb->data); sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); /* Trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(sp->last_cmd); /* We want the time window between clearing suspend flag on the previous command and resuming CU to be as small as possible. Interrupts in between are very undesired. --SAW */ outb(CUResume, ioaddr + SCBCmd); sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; /* Leave room for set_rx_mode(). If there is no more space than reserved for multicast filter mark the ring as full. */ if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { netif_stop_queue(dev); sp->tx_full = 1; } spin_unlock_irqrestore(&sp->lock, flags); } dev->trans_start = jiffies; return 0;}static void speedo_tx_buffer_gc(struct net_device *dev){ unsigned int dirty_tx; struct speedo_private *sp = (struct speedo_private *)dev->priv; dirty_tx = sp->dirty_tx; while ((int)(sp->cur_tx - dirty_tx) > 0) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(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. */ if (status & TxUnderrun) if (sp->tx_threshold < 0x01e08000) { if (speedo_debug > 2) printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n", dev->name); sp->tx_threshold += 0x00040000; } /* 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; */ dev_free_skb(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; } dirty_tx++; } if (speedo_debug && (int)(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; } while (sp->mc_setup_head != NULL && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) { struct speedo_mc_block *t; if (speedo_debug > 1) printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); t = sp->mc_setup_head->next; kfree(sp->mc_setup_head); sp->mc_setup_head = t; } if (sp->mc_setup_head == NULL) sp->mc_setup_tail = NULL; sp->dirty_tx = dirty_tx;}/* 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 net_device *dev = (struct net_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;#ifndef final_version
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -