r6040.c
来自「Linux Home Server 是专门为家庭和SOHO/SMB 设计的高性价」· C语言 代码 · 共 1,405 行 · 第 1/3 页
C
1,405 行
if (lp->rx_ring) { for(i=0, ptr=lp->rx_ring; i < RX_DCNT; i++, ptr++) { printk(KERN_INFO "%s: %d. descr: status x%x len x%x " "ndesc %08x vbufp %p vndescp %p skb_ptr %p\n", DRV_NAME, i, ptr->status, ptr->len, ptr->ndesc, ptr->vbufp, ptr->vndescp, ptr->skb_ptr); } }}#endif /* #if (DEBUG & DBG_TX_RING_DUMP) */int r6040_alloc_rxbufs(struct net_device *dev){ struct r6040_private *lp = netdev_priv(dev); struct r6040_descriptor *desc; struct sk_buff *skb; int rc; lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); /* alloc skbs for the rx descriptors */ desc = lp->rx_ring; do { if (!(skb=netdev_alloc_skb(dev, MAX_BUF_SIZE))) { err("failed to alloc skb for rx\n"); rc = -ENOMEM; goto err_exit; } desc->skb_ptr = skb; desc->buf = cpu_to_le32(pci_map_single(lp->pdev, desc->skb_ptr->data, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); desc->status = DESC_STATUS_OWNER_MAC; desc = desc->vndescp; } while (desc != lp->rx_ring);#if (DEBUG & DBG_RX_RING_DUMP) if (debug & DBG_RX_RING_DUMP) { dump_rx_ring(lp); }#endif return 0;err_exit: /* dealloc all previously allocated skb */ r6040_free_rxbufs(dev); return rc;}/*! reset MAC and set all registers */void r6040_init_mac_regs(struct r6040_private *lp){ void __iomem *ioaddr = lp->base; int limit; char obuf[3*ETH_ALEN] __attribute__ ((unused)); /* Mask Off Interrupt */ iowrite16(MSK_INT, ioaddr + MIER); /* reset MAC */ iowrite16(MAC_RST, ioaddr + MCR1); udelay(100); limit=2048; while ((ioread16(ioaddr + MCR1) & MAC_RST) && limit-- > 0); /* Reset internal state machine */ iowrite16(2, ioaddr + MAC_SM); iowrite16(0, ioaddr + MAC_SM); udelay(5000); /* Restore MAC Addresses */ r6040_multicast_list(lp->dev); /* TODO: restore multcast and hash table */ /* MAC Bus Control Register */ iowrite16(MBCR_DEFAULT, ioaddr + MBCR); /* Buffer Size Register */ iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); /* write tx ring start address */ iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); /* write rx ring start address */ iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); /* set interrupt waiting time and packet numbers */ iowrite16(0, ioaddr + MT_ICR); iowrite16(0, ioaddr + MR_ICR); /* enable interrupts */ iowrite16(INT_MASK, ioaddr + MIER); /* enable tx and rx */ iowrite16(lp->mcr0 | 0x0002, ioaddr); /* let TX poll the descriptors - we may got called by r6040_tx_timeout which has left some unsent tx buffers */ iowrite16(0x01, ioaddr + MTPR);}void r6040_tx_timeout(struct net_device *dev){ struct r6040_private *priv = netdev_priv(dev); void __iomem *ioaddr = priv->base; /* we read MISR, which clears on read (i.e. we may loose an RX interupt, but this is an error anyhow ... */ printk(KERN_WARNING "%s: transmit timed out, int enable %4.4x " "status %4.4x, PHY status %4.4x\n", dev->name, ioread16(ioaddr + MIER), ioread16(ioaddr + MISR), mdio_read(dev, priv->mii_if.phy_id, MII_BMSR)); dev->stats.tx_errors++; /* Reset MAC and re-init all registers */ r6040_init_mac_regs(priv);}struct net_device_stats *r6040_get_stats(struct net_device *dev){ struct r6040_private *priv = netdev_priv(dev); void __iomem *ioaddr = priv->base; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); dev->stats.multicast += ioread8(ioaddr + ME_CNT0); spin_unlock_irqrestore(&priv->lock, flags); return &dev->stats;}/* Stop RDC MAC and Free the allocated resource */void r6040_down(struct net_device *dev){ struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; struct pci_dev *pdev = lp->pdev; int limit = 2048; dbg(DBG_EXIT, "ENTER\n"); /* Stop MAC */ iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ iowrite16(MAC_RST, ioaddr + MCR1); /* Reset RDC MAC */ udelay(100); while ((ioread16(ioaddr+MCR1) & 1) && limit-- > 0); if (limit <= 0) err("timeout while waiting for reset done.\n"); free_irq(dev->irq, dev); /* Free RX buffer */ r6040_free_rxbufs(dev); /* Free TX buffer */ r6040_free_txbufs(dev); /* Free Descriptor memory */ pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma); dbg(DBG_EXIT, "EXIT\n");}int r6040_close(struct net_device *dev){ struct r6040_private *lp = netdev_priv(dev); dbg(DBG_EXIT, "ENTER\n"); /* deleted timer */ del_timer_sync(&lp->timer); spin_lock_irq(&lp->lock); napi_disable(&lp->napi); netif_stop_queue(dev); r6040_down(dev); spin_unlock_irq(&lp->lock); dbg(DBG_EXIT, "EXIT\n"); return 0;}/* Status of PHY CHIP. Returns 0x8000 for full duplex, 0 for half duplex */STATIC int phy_mode_chk(struct net_device *dev){ struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int phy_dat; /* PHY Link Status Check */ phy_dat = phy_read(ioaddr, lp->phy_addr, 1); if (!(phy_dat & 0x4)) phy_dat = 0x8000; /* Link Failed, full duplex */ /* PHY Chip Auto-Negotiation Status */ phy_dat = phy_read(ioaddr, lp->phy_addr, 1); if (phy_dat & 0x0020) { /* Auto Negotiation Mode */ phy_dat = phy_read(ioaddr, lp->phy_addr, 5); phy_dat &= phy_read(ioaddr, lp->phy_addr, 4); if (phy_dat & 0x140) /* Force full duplex */ phy_dat = 0x8000; else phy_dat = 0; } else { /* Force Mode */ phy_dat = phy_read(ioaddr, lp->phy_addr, 0); if (phy_dat & 0x100) phy_dat = 0x8000; else phy_dat = 0x0000; } dbg(DBG_PHY, "RETURN x%x\n", phy_dat); return phy_dat;};void r6040_set_carrier(struct mii_if_info *mii){ if (phy_mode_chk(mii->dev)) { /* autoneg is off: Link is always assumed to be up */ if (!netif_carrier_ok(mii->dev)) netif_carrier_on(mii->dev); } else phy_mode_chk(mii->dev);}int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct r6040_private *lp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(rq); int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irq(&lp->lock); rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); spin_unlock_irq(&lp->lock); r6040_set_carrier(&lp->mii_if); return rc;}int r6040_rx(struct net_device *dev, int limit){ struct r6040_private *priv = netdev_priv(dev); int count=0; struct r6040_descriptor *descptr = priv->rx_remove_ptr; struct sk_buff *skb_ptr, *new_skb; char obuf[2*32+1] __attribute__ ((unused)); /* for debugging */ while (count < limit && !(descptr->status & DESC_STATUS_OWNER_MAC)) { /* limit not reached and the descriptor belongs to the CPU */ dbg(DBG_RX_DESCR, "descptr %p status x%x data len x%x\n", descptr, descptr->status, descptr->len); /* Check for errors */ if (descptr->status & DESC_STATUS_RX_ERR) { dev->stats.rx_errors++; if (descptr->status & (DESC_STATUS_RX_ERR_DRIBBLE| DESC_STATUS_RX_ERR_BUFLEN| DESC_STATUS_RX_ERR_LONG| DESC_STATUS_RX_ERR_RUNT)) { /* packet too long or too short*/ dev->stats.rx_length_errors++; } if (descptr->status & DESC_STATUS_RX_ERR_CRC) { dev->stats.rx_crc_errors++; } goto next_descr; } /* successful received packet */ /* first try to allocate new skb. If this fails we drop the packet and leave the old skb there.*/ new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); if (!new_skb) { dev->stats.rx_dropped++; goto next_descr; } skb_ptr = descptr->skb_ptr; skb_ptr->dev = priv->dev; /* Do not count the CRC */ skb_put(skb_ptr, descptr->len - 4); pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf), MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); dbg(DBG_RX_DATA, "rx len x%x: %s...\n", descptr->len, hex2str(skb_ptr->data, obuf, sizeof(obuf)/2, '\0')); /* Send to upper layer */ netif_receive_skb(skb_ptr); dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += (descptr->len-4); /* put new skb into descriptor */ descptr->skb_ptr = new_skb; descptr->buf = cpu_to_le32(pci_map_single(priv->pdev, descptr->skb_ptr->data, MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));next_descr: /* put the descriptor back to the MAC */ descptr->status = DESC_STATUS_OWNER_MAC; descptr = descptr->vndescp; count++; /* shall we count errors and dropped packets as well? */ } /* while (limit && !(descptr->status & DESC_STATUS_OWNER_MAC)) */ /* remember next descriptor to check for rx */ priv->rx_remove_ptr = descptr; return count;}void r6040_tx(struct net_device *dev){ struct r6040_private *priv = netdev_priv(dev); struct r6040_descriptor *descptr; void __iomem *ioaddr = priv->base; struct sk_buff *skb_ptr; u16 err; spin_lock(&priv->lock); descptr = priv->tx_remove_ptr; while (priv->tx_free_desc < TX_DCNT) { /* Check for errors */ err = ioread16(ioaddr + MLSR); if (err & 0x0200) dev->stats.rx_fifo_errors++; if (err & (0x2000 | 0x4000)) dev->stats.tx_carrier_errors++; dbg(DBG_TX_DONE, "descptr %p status x%x err x%x jiffies %lu\n", descptr, descptr->status, err, jiffies); if (descptr->status & 0x8000) break; /* Not complete */ skb_ptr = descptr->skb_ptr; pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf), skb_ptr->len, PCI_DMA_TODEVICE); /* Free buffer */ dev_kfree_skb_irq(skb_ptr); descptr->skb_ptr = NULL; /* To next descriptor */ descptr = descptr->vndescp; priv->tx_free_desc++; } priv->tx_remove_ptr = descptr; if (priv->tx_free_desc) netif_wake_queue(dev); spin_unlock(&priv->lock);}int r6040_poll(struct napi_struct *napi, int budget){ struct r6040_private *priv = container_of(napi, struct r6040_private, napi); struct net_device *dev = priv->dev; void __iomem *ioaddr = priv->base; int work_done; work_done = r6040_rx(dev, budget); dbg(DBG_POLL, "budget x%x done x%x\n", budget, work_done); if (work_done < budget) { netif_rx_complete(dev, napi); /* Enable RX interrupt */ iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER); } return work_done;}/* The RDC interrupt handler. */irqreturn_t r6040_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; u16 status; /* Read MISR status and clear */ status = ioread16(ioaddr + MISR); dbg(DBG_IRQ, "status x%x jiffies %lu\n", status, jiffies); if (status == 0x0000 || status == 0xffff) return IRQ_NONE; /* rx early / rx finish interrupt or rx descriptor unavail. */ if (status & RX_INTS) { if (status & RX_NO_DESC) { /* rx descriptor unavail. */ dev->stats.rx_dropped++; dev->stats.rx_missed_errors++; } /* Mask off RX interrupts */ iowrite16(ioread16(ioaddr + MIER) & ~RX_INTS, ioaddr + MIER); netif_rx_schedule(dev, &lp->napi); } /* rx FIFO full */ if (status & RX_FIFO_FULL) { dev->stats.rx_fifo_errors++; } /* TX interrupt request */ if (status & 0x10) r6040_tx(dev); return IRQ_HANDLED;}#ifdef CONFIG_NET_POLL_CONTROLLERvoid r6040_poll_controller(struct net_device *dev){ disable_irq(dev->irq); r6040_interrupt(dev->irq, dev); enable_irq(dev->irq);}#endif/* Init RDC MAC */int r6040_up(struct net_device *dev){ struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int rc; dbg(DBG_INIT, "ENTER\n"); /* Initialise and alloc RX/TX buffers */ r6040_init_txbufs(dev); if ((rc=r6040_alloc_rxbufs(dev))) return rc; /* Read the PHY ID */ lp->switch_sig = phy_read(ioaddr, 0, 2); if (lp->switch_sig == ICPLUS_PHY_ID) { phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */ lp->phy_mode = 0x8000; } else { /* PHY Mode Check */ phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP); phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE); if (PHY_MODE == 0x3100) lp->phy_mode = phy_mode_chk(dev);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?