📄 tulip_core.c
字号:
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tulip_start_rxtx(tp); outl(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), inl(ioaddr + CSR6)); } /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ tp->timer.expires = RUN_AT(next_tick); add_timer(&tp->timer);}#ifdef CONFIG_NET_HW_FLOWCONTROL/* Enable receiver */void tulip_xon(struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; clear_bit(tp->fc_bit, &netdev_fc_xoff); if (netif_running(dev)){ tulip_refill_rx(dev); outl(tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7); }}#endifstatic inttulip_open(struct net_device *dev){#ifdef CONFIG_NET_HW_FLOWCONTROL struct tulip_private *tp = (struct tulip_private *)dev->priv;#endif int retval; MOD_INC_USE_COUNT; if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) { MOD_DEC_USE_COUNT; return retval; } tulip_init_ring (dev); tulip_up (dev);#ifdef CONFIG_NET_HW_FLOWCONTROL tp->fc_bit = netdev_register_fc(dev, tulip_xon);#endif netif_start_queue (dev); return 0;}static void tulip_tx_timeout(struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; unsigned long flags; spin_lock_irqsave (&tp->lock, flags); if (tulip_media_cap[dev->if_port] & MediaIsMII) { /* Do nothing -- the media monitor should handle this. */ if (tulip_debug > 1) printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", dev->name); } else if (tp->chip_id == DC21040) { if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { dev->if_port = (dev->if_port == 2 ? 0 : 2); printk(KERN_INFO "%s: 21040 transmit timed out, switching to " "%s.\n", dev->name, medianame[dev->if_port]); tulip_select_media(dev, 0); } goto out; } else if (tp->chip_id == DC21041) { int csr12 = inl(ioaddr + CSR12); printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", dev->name, inl(ioaddr + CSR5), csr12, inl(ioaddr + CSR13), inl(ioaddr + CSR14)); tp->mediasense = 1; if ( ! tp->medialock) { if (dev->if_port == 1 || dev->if_port == 2) if (csr12 & 0x0004) { dev->if_port = 2 - dev->if_port; } else dev->if_port = 0; else if (dev->if_port != 0 || (csr12 & 0x0004) != 0) dev->if_port = 1; tulip_select_media(dev, 0); } } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 || tp->chip_id == DM910X) { printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); if ( ! tp->medialock && tp->mtable) { do --tp->cur_index; while (tp->cur_index >= 0 && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media] & MediaIsFD)); if (--tp->cur_index < 0) { /* We start again, but should instead look for default. */ tp->cur_index = tp->mtable->leafcount - 1; } tulip_select_media(dev, 0); printk(KERN_WARNING "%s: transmit timed out, switching to %s " "media.\n", dev->name, medianame[dev->if_port]); } } else if (tp->chip_id == PNIC2) { printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, " "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n", dev->name, (int)inl(ioaddr + CSR5), (int)inl(ioaddr + CSR6), (int)inl(ioaddr + CSR7), (int)inl(ioaddr + CSR12)); } else { printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " "%8.8x, resetting...\n", dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); dev->if_port = 0; }#if defined(way_too_many_messages) if (tulip_debug > 3) { int i; for (i = 0; i < RX_RING_SIZE; i++) { u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); int j; printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " "%2.2x %2.2x %2.2x.\n", i, (unsigned int)tp->rx_ring[i].status, (unsigned int)tp->rx_ring[i].length, (unsigned int)tp->rx_ring[i].buffer1, (unsigned int)tp->rx_ring[i].buffer2, buf[0], buf[1], buf[2]); for (j = 0; buf[j] != 0xee && j < 1600; j++) if (j < 100) printk(" %2.2x", buf[j]); printk(" j=%d.\n", j); } printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); printk("\n"); }#endif /* Stop and restart the chip's Tx processes . */#ifdef CONFIG_NET_HW_FLOWCONTROL if (tp->fc_bit && test_bit(tp->fc_bit,&netdev_fc_xoff)) printk("BUG tx_timeout restarting rx when fc on\n");#endif tulip_restart_rxtx(tp); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); tp->stats.tx_errors++;out: spin_unlock_irqrestore (&tp->lock, flags); dev->trans_start = jiffies; netif_wake_queue (dev);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void tulip_init_ring(struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; tp->susp_rx = 0; tp->ttimer = 0; tp->nir = 0; for (i = 0; i < RX_RING_SIZE; i++) { tp->rx_ring[i].status = 0x00000000; tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); tp->rx_ring[i].buffer2 = cpu_to_le32(tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * (i + 1)); tp->rx_buffers[i].skb = NULL; tp->rx_buffers[i].mapping = 0; } /* Mark the last entry as wrapping the ring. */ tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); tp->rx_ring[i-1].buffer2 = cpu_to_le32(tp->rx_ring_dma); for (i = 0; i < RX_RING_SIZE; i++) { dma_addr_t mapping; /* Note the receive buffer must be longword aligned. dev_alloc_skb() provides 16 byte alignment. But do *not* use skb_reserve() to align the IP header! */ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); tp->rx_buffers[i].skb = skb; if (skb == NULL) break; mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[i].mapping = mapping; skb->dev = dev; /* Mark as being used by this device. */ tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ tp->rx_ring[i].buffer1 = cpu_to_le32(mapping); } tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { tp->tx_buffers[i].skb = NULL; tp->tx_buffers[i].mapping = 0; tp->tx_ring[i].status = 0x00000000; tp->tx_ring[i].buffer2 = cpu_to_le32(tp->tx_ring_dma + sizeof(struct tulip_tx_desc) * (i + 1)); } tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma);}static inttulip_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry; u32 flag; dma_addr_t mapping; unsigned long eflags; spin_lock_irqsave(&tp->lock, eflags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; tp->tx_buffers[entry].skb = skb; mapping = pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].mapping = mapping; tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping); if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ flag = 0x60000000; /* No interrupt */ } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { flag = 0xe0000000; /* Tx-done intr. */ } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { flag = 0x60000000; /* No Tx-done intr. */ } else { /* Leave room for set_rx_mode() to fill entries. */ flag = 0xe0000000; /* Tx-done intr. */ netif_stop_queue(dev); } if (entry == TX_RING_SIZE-1) flag = 0xe0000000 | DESC_RING_WRAP; tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); /* if we were using Transmit Automatic Polling, we would need a * wmb() here. */ tp->tx_ring[entry].status = cpu_to_le32(DescOwned); wmb(); tp->cur_tx++; /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); spin_unlock_irqrestore(&tp->lock, eflags); dev->trans_start = jiffies; return 0;}static void tulip_clean_tx_ring(struct tulip_private *tp){ unsigned int dirty_tx; for (dirty_tx = tp->dirty_tx ; tp->cur_tx - dirty_tx > 0; dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status); if (status < 0) { tp->stats.tx_errors++; /* It wasn't Txed */ tp->tx_ring[entry].status = 0; } /* Check for Tx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping) pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); continue; } pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, tp->tx_buffers[entry].skb->len, PCI_DMA_TODEVICE); /* Free the original skb. */ dev_kfree_skb_irq(tp->tx_buffers[entry].skb); tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; }}static void tulip_down (struct net_device *dev){ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *) dev->priv; unsigned long flags; del_timer_sync (&tp->timer); spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ outl (0x00000000, ioaddr + CSR7); /* Stop the Tx and Rx processes. */ tulip_stop_rxtx(tp); /* prepare receive buffers */ tulip_refill_rx(dev); /* release any unconsumed transmit buffers */ tulip_clean_tx_ring(tp); /* 21040 -- Leave the card in 10baseT state. */ if (tp->chip_id == DC21040) outl (0x00000004, ioaddr + CSR13); if (inl (ioaddr + CSR6) != 0xffffffff) tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; spin_unlock_irqrestore (&tp->lock, flags); init_timer(&tp->timer); tp->timer.data = (unsigned long)dev; tp->timer.function = tulip_tbl[tp->chip_id].media_timer; dev->if_port = tp->saved_if_port; /* Leave the driver in snooze, not sleep, mode. */ tulip_set_power_state (tp, 0, 1);}static int tulip_close (struct net_device *dev){ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *) dev->priv; int i; netif_stop_queue (dev);#ifdef CONFIG_NET_HW_FLOWCONTROL if (tp->fc_bit) { int bit = tp->fc_bit; tp->fc_bit = 0; netdev_unregister_fc(bit); }#endif tulip_down (dev); if (tulip_debug > 1) printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl (ioaddr + CSR5)); free_irq (dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = tp->rx_buffers[i].skb; dma_addr_t mapping = tp->rx_buffers[i].mapping; tp->rx_buffers[i].skb = NULL; tp->rx_buffers[i].mapping = 0; tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ tp->rx_ring[i].length = 0; tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ if (skb) { pci_unmap_single(tp->pdev, mapping, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); dev_kfree_skb (skb); } } for (i = 0; i < TX_RING_SIZE; i++) { struct sk_buff *skb = tp->tx_buffers[i].skb; if (skb != NULL) { pci_unmap_single(tp->pdev, tp->tx_buffers[i].mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb (skb); } tp->tx_buffers[i].skb = NULL; tp->tx_buffers[i].mapping = 0; } MOD_DEC_USE_COUNT; return 0;}static struct net_device_stats *tulip_get_stats(struct net_device *dev){ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; if (netif_running(dev)) { unsigned long flags; spin_lock_irqsave (&tp->lock, flags); tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; spin_unlock_irqrestore(&tp->lock, flags); } return &tp->stats;}static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ struct tulip_private *np = dev->priv; u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strcpy(info.driver, DRV_NAME); strcpy(info.version, DRV_VERSION); strcpy(info.bus_info, np->pdev->slot_name); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } } return -EOPNOTSUPP;}/* Provide ioctl() calls to examine the MII xcvr state. */static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){ struct tulip_private *tp = dev->priv; long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; const unsigned int phy_idx = 0; int phy = tp->phys[phy_idx] & 0x1f; unsigned int regnum = data->reg_num; switch (cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ if (tp->mii_cnt) data->phy_id = phy; else if (tp->flags & HAS_NWAY) data->phy_id = 32; else if (tp->chip_id == COMET) data->phy_id = 1; else return -ENODEV; case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -