X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fr6040.c;h=6f97b47d74a6931c83294644640d724fd21207de;hb=f001a70cdc61c01452d42e8b32fd7c7842ef62d5;hp=6a6329e641233383a35aff009c7d61ace132c9eb;hpb=5125a786680df0d6d31aad53bc23e19f51a30509;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 6a6329e..6f97b47 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Sten Wang * Copyright (C) 2007 - * Daniel Gimpelevich + * Daniel Gimpelevich * Florian Fainelli * * This program is free software; you can redistribute it and/or @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -50,18 +49,17 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.16" -#define DRV_RELDATE "10Nov2007" +#define DRV_VERSION "0.22" +#define DRV_RELDATE "25Mar2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ -#define PHY2_ADDR 2 /* For MAC2 */ +#define PHY2_ADDR 3 /* For MAC2 */ #define PHY_MODE 0x3100 /* PHY CHIP Register 0 */ #define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (6000 * HZ / 1000) -#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ +#define TX_TIMEOUT (6000 * HZ / 1000) /* RDC MAC I/O Size */ #define R6040_IO_SIZE 256 @@ -92,6 +90,14 @@ #define MISR 0x3C /* Status register */ #define MIER 0x40 /* INT enable register */ #define MSK_INT 0x0000 /* Mask off interrupts */ +#define RX_FINISH 0x0001 /* RX finished */ +#define RX_NO_DESC 0x0002 /* No RX descriptor available */ +#define RX_FIFO_FULL 0x0004 /* RX FIFO full */ +#define RX_EARLY 0x0008 /* RX early */ +#define TX_FINISH 0x0010 /* TX finished */ +#define TX_EARLY 0x0080 /* TX early */ +#define EVENT_OVRFL 0x0100 /* Event counter overflow */ +#define LINK_CHANGED 0x0200 /* PHY link changed */ #define ME_CISR 0x44 /* Event counter INT status */ #define ME_CIER 0x48 /* Event counter INT enable */ #define MR_CNT 0x50 /* Successfully received packet counter */ @@ -126,11 +132,26 @@ #define TX_DCNT 0x80 /* TX descriptor count */ #define RX_DCNT 0x80 /* RX descriptor count */ #define MAX_BUF_SIZE 0x600 -#define ALLOC_DESC_SIZE ((TX_DCNT+RX_DCNT) * \ - sizeof(struct r6040_descriptor) + 0x10) +#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor)) +#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor)) #define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */ #define MCAST_MAX 4 /* Max number multicast addresses to filter */ +/* Descriptor status */ +#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */ +#define DSC_RX_OK 0x4000 /* RX was successful */ +#define DSC_RX_ERR 0x0800 /* RX PHY error */ +#define DSC_RX_ERR_DRI 0x0400 /* RX dribble packet */ +#define DSC_RX_ERR_BUF 0x0200 /* RX length exceeds buffer size */ +#define DSC_RX_ERR_LONG 0x0100 /* RX length > maximum packet length */ +#define DSC_RX_ERR_RUNT 0x0080 /* RX packet length < 64 byte */ +#define DSC_RX_ERR_CRC 0x0040 /* RX CRC error */ +#define DSC_RX_BCAST 0x0020 /* RX broadcast (no error) */ +#define DSC_RX_MCAST 0x0010 /* RX multicast (no error) */ +#define DSC_RX_MCH_HIT 0x0008 /* RX multicast hit in hash table (no error) */ +#define DSC_RX_MIDH_HIT 0x0004 /* RX MID table hit (no error) */ +#define DSC_RX_IDX_MID_MASK 3 /* RX mask for the index of matched MIDx */ + /* PHY settings */ #define ICPLUS_PHY_ID 0x0243 @@ -139,11 +160,12 @@ MODULE_AUTHOR("Sten Wang ," "Florian Fainelli "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver"); +MODULE_VERSION(DRV_VERSION " " DRV_RELDATE); -#define RX_INT 0x0001 -#define TX_INT 0x0010 -#define RX_NO_DESC_INT 0x0002 -#define INT_MASK (RX_INT | TX_INT) +/* RX and TX interrupts that we handle */ +#define RX_INTS (RX_FIFO_FULL | RX_NO_DESC | RX_FINISH) +#define TX_INTS (TX_FINISH) +#define INT_MASK (RX_INTS | TX_INTS) struct r6040_descriptor { u16 status, len; /* 0-3 */ @@ -164,27 +186,27 @@ struct r6040_private { struct r6040_descriptor *rx_remove_ptr; struct r6040_descriptor *tx_insert_ptr; struct r6040_descriptor *tx_remove_ptr; - u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode; + struct r6040_descriptor *rx_ring; + struct r6040_descriptor *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + u16 tx_free_desc, phy_addr, phy_mode; u16 mcr0, mcr1; - dma_addr_t desc_dma; - char *desc_pool; u16 switch_sig; struct net_device *dev; struct mii_if_info mii_if; struct napi_struct napi; - struct net_device_stats stats; - u16 napi_rx_running; void __iomem *base; }; static char version[] __devinitdata = KERN_INFO DRV_NAME ": RDC R6040 NAPI net driver," - "version "DRV_VERSION " (" DRV_RELDATE ")\n"; + "version "DRV_VERSION " (" DRV_RELDATE ")"; static int phy_table[] = { PHY1_ADDR, PHY2_ADDR }; /* Read a word data from PHY Chip */ -static int phy_read(void __iomem *ioaddr, int phy_addr, int reg) +static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) { int limit = 2048; u16 cmd; @@ -193,7 +215,7 @@ static int phy_read(void __iomem *ioaddr, int phy_addr, int reg) /* Wait for the read bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_READ) + if (!(cmd & MDIO_READ)) break; } @@ -201,7 +223,7 @@ static int phy_read(void __iomem *ioaddr, int phy_addr, int reg) } /* Write a word data from PHY Chip */ -static void phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val) +static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val) { int limit = 2048; u16 cmd; @@ -212,65 +234,191 @@ static void phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val) /* Wait for the write bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_WRITE) + if (!(cmd & MDIO_WRITE)) break; } } -static int mdio_read(struct net_device *dev, int mii_id, int reg) +static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - return (phy_read(ioaddr, lp->phy_addr, reg)); + return (r6040_phy_read(ioaddr, lp->phy_addr, reg)); } -static void mdio_write(struct net_device *dev, int mii_id, int reg, int val) +static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - phy_write(ioaddr, lp->phy_addr, reg, val); + r6040_phy_write(ioaddr, lp->phy_addr, reg, val); } -static void -r6040_tx_timeout(struct net_device *dev) +static void r6040_free_txbufs(struct net_device *dev) { - struct r6040_private *priv = netdev_priv(dev); + struct r6040_private *lp = netdev_priv(dev); + int i; - disable_irq(dev->irq); - napi_disable(&priv->napi); - spin_lock(&priv->lock); - dev->stats.tx_errors++; - spin_unlock(&priv->lock); + for (i = 0; i < TX_DCNT; i++) { + if (lp->tx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, + le32_to_cpu(lp->tx_insert_ptr->buf), + MAX_BUF_SIZE, PCI_DMA_TODEVICE); + dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); + lp->tx_insert_ptr->skb_ptr = NULL; + } + lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; + } +} - netif_stop_queue(dev); +static void r6040_free_rxbufs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + int i; + + for (i = 0; i < RX_DCNT; i++) { + if (lp->rx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, + le32_to_cpu(lp->rx_insert_ptr->buf), + MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); + lp->rx_insert_ptr->skb_ptr = NULL; + } + lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; + } } -/* Allocate skb buffer for rx descriptor */ -static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) +static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, + dma_addr_t desc_dma, int size) { - struct r6040_descriptor *descptr; + struct r6040_descriptor *desc = desc_ring; + dma_addr_t mapping = desc_dma; + + while (size-- > 0) { + mapping += sizeof(*desc); + desc->ndesc = cpu_to_le32(mapping); + desc->vndescp = desc + 1; + desc++; + } + desc--; + desc->ndesc = cpu_to_le32(desc_dma); + desc->vndescp = desc_ring; +} + +static void r6040_init_txbufs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + + lp->tx_free_desc = TX_DCNT; + + lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; + r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); +} + +static 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); + + /* Allocate skbs for the rx descriptors */ + desc = lp->rx_ring; + do { + skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); + if (!skb) { + printk(KERN_ERR DRV_NAME "%s: failed to alloc skb for rx\n", dev->name); + 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 = DSC_OWNER_MAC; + desc = desc->vndescp; + } while (desc != lp->rx_ring); + + return 0; + +err_exit: + /* Deallocate all previously allocated skbs */ + r6040_free_rxbufs(dev); + return rc; +} + +static void r6040_init_mac_regs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; + int limit = 2048; + u16 cmd; - descptr = lp->rx_insert_ptr; - while (lp->rx_free_desc < RX_DCNT) { - descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); + /* Mask Off Interrupt */ + iowrite16(MSK_INT, ioaddr + MIER); - if (!descptr->skb_ptr) + /* Reset RDC MAC */ + iowrite16(MAC_RST, ioaddr + MCR1); + while (limit--) { + cmd = ioread16(ioaddr + MCR1); + if (cmd & 0x1) break; - descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, - descptr->skb_ptr->data, - MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); - descptr->status = 0x8000; - descptr = descptr->vndescp; - lp->rx_free_desc++; - /* Trigger RX DMA */ - iowrite16(lp->mcr0 | 0x0002, ioaddr); } - lp->rx_insert_ptr = descptr; + /* Reset internal state machine */ + iowrite16(2, ioaddr + MAC_SM); + iowrite16(0, ioaddr + MAC_SM); + mdelay(5); + + /* 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); } +static void r6040_tx_timeout(struct net_device *dev) +{ + struct r6040_private *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + + 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), + r6040_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(dev); +} static struct net_device_stats *r6040_get_stats(struct net_device *dev) { @@ -279,11 +427,11 @@ static struct net_device_stats *r6040_get_stats(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - priv->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); - priv->stats.multicast += ioread8(ioaddr + ME_CNT0); + dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); + dev->stats.multicast += ioread8(ioaddr + ME_CNT0); spin_unlock_irqrestore(&priv->lock, flags); - return &priv->stats; + return &dev->stats; } /* Stop RDC MAC and Free the allocated resource */ @@ -291,7 +439,6 @@ static void r6040_down(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - int i; int limit = 2048; u16 *adrp; u16 cmd; @@ -310,68 +457,63 @@ static void r6040_down(struct net_device *dev) iowrite16(adrp[0], ioaddr + MID_0L); iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); - free_irq(dev->irq, dev); - /* Free RX buffer */ - for (i = 0; i < RX_DCNT; i++) { - if (lp->rx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, - MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); - dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); - lp->rx_insert_ptr->skb_ptr = NULL; - } - lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; - } - - /* Free TX buffer */ - for (i = 0; i < TX_DCNT; i++) { - if (lp->tx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, - MAX_BUF_SIZE, PCI_DMA_TODEVICE); - dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); - lp->rx_insert_ptr->skb_ptr = NULL; - } - lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; - } - - /* Free Descriptor memory */ - pci_free_consistent(lp->pdev, ALLOC_DESC_SIZE, - lp->desc_pool, lp->desc_dma); } -static int -r6040_close(struct net_device *dev) +static int r6040_close(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); + struct pci_dev *pdev = lp->pdev; /* deleted timer */ del_timer_sync(&lp->timer); spin_lock_irq(&lp->lock); + napi_disable(&lp->napi); netif_stop_queue(dev); r6040_down(dev); + + free_irq(dev->irq, dev); + + /* Free RX buffer */ + r6040_free_rxbufs(dev); + + /* Free TX buffer */ + r6040_free_txbufs(dev); + spin_unlock_irq(&lp->lock); + /* Free Descriptor memory */ + if (lp->rx_ring) { + pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); + lp->rx_ring = NULL; + } + + if (lp->tx_ring) { + pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma); + lp->tx_ring = NULL; + } + return 0; } /* Status of PHY CHIP */ -static int phy_mode_chk(struct net_device *dev) +static int r6040_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); + phy_dat = r6040_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); + phy_dat = r6040_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); + phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5); + phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4); if (phy_dat & 0x140) /* Force full duplex */ phy_dat = 0x8000; @@ -379,7 +521,7 @@ static int phy_mode_chk(struct net_device *dev) phy_dat = 0; } else { /* Force Mode */ - phy_dat = phy_read(ioaddr, lp->phy_addr, 0); + phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0); if (phy_dat & 0x100) phy_dat = 0x8000; else @@ -391,18 +533,18 @@ static int phy_mode_chk(struct net_device *dev) static void r6040_set_carrier(struct mii_if_info *mii) { - if (phy_mode_chk(mii->dev)) { + if (r6040_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); + r6040_phy_mode_chk(mii->dev); } static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct r6040_private *lp = netdev_priv(dev); - struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data; + struct mii_ioctl_data *data = if_mii(rq); int rc; if (!netif_running(dev)) @@ -417,68 +559,71 @@ static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int r6040_rx(struct net_device *dev, int limit) { struct r6040_private *priv = netdev_priv(dev); - int count; - void __iomem *ioaddr = priv->base; + struct r6040_descriptor *descptr = priv->rx_remove_ptr; + struct sk_buff *skb_ptr, *new_skb; + int count = 0; u16 err; - for (count = 0; count < limit; ++count) { - struct r6040_descriptor *descptr = priv->rx_remove_ptr; - struct sk_buff *skb_ptr; - - /* Disable RX interrupt */ - iowrite16(ioread16(ioaddr + MIER) & (~RX_INT), ioaddr + MIER); - descptr = priv->rx_remove_ptr; - - /* Check for errors */ - err = ioread16(ioaddr + MLSR); - if (err & 0x0400) priv->stats.rx_errors++; - /* RX FIFO over-run */ - if (err & 0x8000) priv->stats.rx_fifo_errors++; - /* RX descriptor unavailable */ - if (err & 0x0080) priv->stats.rx_frame_errors++; - /* Received packet with length over buffer lenght */ - if (err & 0x0020) priv->stats.rx_over_errors++; - /* Received packet with too long or short */ - if (err & (0x0010|0x0008)) priv->stats.rx_length_errors++; - /* Received packet with CRC errors */ - if (err & 0x0004) { - spin_lock(&priv->lock); - priv->stats.rx_crc_errors++; - spin_unlock(&priv->lock); - } - - while (priv->rx_free_desc) { - /* No RX packet */ - if (descptr->status & 0x8000) - break; - skb_ptr = descptr->skb_ptr; - if (!skb_ptr) { - printk(KERN_ERR "%s: Inconsistent RX" - "descriptor chain\n", - dev->name); - break; + /* Limit not reached and the descriptor belongs to the CPU */ + while (count < limit && !(descptr->status & DSC_OWNER_MAC)) { + /* Read the descriptor status */ + err = descptr->status; + /* Global error status set */ + if (err & DSC_RX_ERR) { + /* RX dribble */ + if (err & DSC_RX_ERR_DRI) + dev->stats.rx_frame_errors++; + /* Buffer lenght exceeded */ + if (err & DSC_RX_ERR_BUF) + dev->stats.rx_length_errors++; + /* Packet too long */ + if (err & DSC_RX_ERR_LONG) + dev->stats.rx_length_errors++; + /* Packet < 64 bytes */ + if (err & DSC_RX_ERR_RUNT) + dev->stats.rx_length_errors++; + /* CRC error */ + if (err & DSC_RX_ERR_CRC) { + spin_lock(&priv->lock); + dev->stats.rx_crc_errors++; + spin_unlock(&priv->lock); } - descptr->skb_ptr = NULL; - skb_ptr->dev = priv->dev; - /* Do not count the CRC */ - skb_put(skb_ptr, descptr->len - 4); - pci_unmap_single(priv->pdev, descptr->buf, - MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); - skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); - /* Send to upper layer */ - netif_receive_skb(skb_ptr); - dev->last_rx = jiffies; - priv->dev->stats.rx_packets++; - priv->dev->stats.rx_bytes += descptr->len; - /* To next descriptor */ - descptr = descptr->vndescp; - priv->rx_free_desc--; + goto next_descr; } - priv->rx_remove_ptr = descptr; + + /* Packet successfully received */ + 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); + + /* Send to upper layer */ + netif_receive_skb(skb_ptr); + 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 = DSC_OWNER_MAC; + descptr = descptr->vndescp; + count++; } - /* Allocate new RX buffer */ - if (priv->rx_free_desc < RX_DCNT) - rx_buf_alloc(priv, priv->dev); + priv->rx_remove_ptr = descptr; return count; } @@ -497,13 +642,15 @@ static void r6040_tx(struct net_device *dev) /* Check for errors */ err = ioread16(ioaddr + MLSR); - if (err & 0x0200) priv->stats.rx_fifo_errors++; - if (err & (0x2000 | 0x4000)) priv->stats.tx_carrier_errors++; + if (err & 0x0200) + dev->stats.rx_fifo_errors++; + if (err & (0x2000 | 0x4000)) + dev->stats.tx_carrier_errors++; - if (descptr->status & 0x8000) - break; /* Not complte */ + if (descptr->status & DSC_OWNER_MAC) + break; /* Not complete */ skb_ptr = descptr->skb_ptr; - pci_unmap_single(priv->pdev, descptr->buf, + pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf), skb_ptr->len, PCI_DMA_TODEVICE); /* Free buffer */ dev_kfree_skb_irq(skb_ptr); @@ -530,9 +677,9 @@ static int r6040_poll(struct napi_struct *napi, int budget) work_done = r6040_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + napi_complete(napi); /* Enable RX interrupt */ - iowrite16(ioread16(ioaddr + MIER) | RX_INT, ioaddr + MIER); + iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER); } return work_done; } @@ -543,9 +690,10 @@ static 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; - int handled = 1; + u16 misr, status; + /* Save MIER */ + misr = ioread16(ioaddr + MIER); /* Mask off RDC MAC interrupt */ iowrite16(MSK_INT, ioaddr + MIER); /* Read MISR status and clear */ @@ -555,127 +703,82 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) return IRQ_NONE; /* RX interrupt request */ - if (status & 0x01) { - netif_rx_schedule(dev, &lp->napi); - iowrite16(TX_INT, ioaddr + MIER); + if (status & RX_INTS) { + if (status & RX_NO_DESC) { + /* RX descriptor unavailable */ + dev->stats.rx_dropped++; + dev->stats.rx_missed_errors++; + } + if (status & RX_FIFO_FULL) + dev->stats.rx_fifo_errors++; + + /* Mask off RX interrupt */ + misr &= ~RX_INTS; + napi_schedule(&lp->napi); } /* TX interrupt request */ - if (status & 0x10) + if (status & TX_INTS) r6040_tx(dev); - return IRQ_RETVAL(handled); + /* Restore RDC MAC interrupt */ + iowrite16(misr, ioaddr + MIER); + + return IRQ_HANDLED; } #ifdef CONFIG_NET_POLL_CONTROLLER static void r6040_poll_controller(struct net_device *dev) { disable_irq(dev->irq); - r6040_interrupt(dev->irq, (void *)dev); + r6040_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif - /* Init RDC MAC */ -static void r6040_up(struct net_device *dev) +static int r6040_up(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); - struct r6040_descriptor *descptr; void __iomem *ioaddr = lp->base; - int i; - __le32 tmp_addr; - dma_addr_t desc_dma, start_dma; - - /* Initialize */ - lp->tx_free_desc = TX_DCNT; - lp->rx_free_desc = 0; - /* Init descriptor */ - memset(lp->desc_pool, 0, ALLOC_DESC_SIZE); /* Let all descriptor = 0 */ - lp->tx_insert_ptr = (struct r6040_descriptor *)lp->desc_pool; - lp->tx_remove_ptr = lp->tx_insert_ptr; - lp->rx_insert_ptr = (struct r6040_descriptor *)lp->tx_insert_ptr + - TX_DCNT; - lp->rx_remove_ptr = lp->rx_insert_ptr; - /* Init TX descriptor */ - descptr = lp->tx_insert_ptr; - desc_dma = lp->desc_dma; - start_dma = desc_dma; - for (i = 0; i < TX_DCNT; i++) { - descptr->ndesc = cpu_to_le32(desc_dma + - sizeof(struct r6040_descriptor)); - descptr->vndescp = (descptr + 1); - descptr = (descptr + 1); - desc_dma += sizeof(struct r6040_descriptor); - } - (descptr - 1)->ndesc = cpu_to_le32(start_dma); - (descptr - 1)->vndescp = lp->tx_insert_ptr; + int ret; - /* Init RX descriptor */ - start_dma = desc_dma; - descptr = lp->rx_insert_ptr; - for (i = 0; i < RX_DCNT; i++) { - descptr->ndesc = cpu_to_le32(desc_dma + - sizeof(struct r6040_descriptor)); - descptr->vndescp = (descptr + 1); - descptr = (descptr + 1); - desc_dma += sizeof(struct r6040_descriptor); - } - (descptr - 1)->ndesc = cpu_to_le32(start_dma); - (descptr - 1)->vndescp = lp->rx_insert_ptr; - - /* Allocate buffer for RX descriptor */ - rx_buf_alloc(lp, dev); - - /* TX and RX descriptor start Register */ - tmp_addr = cpu_to_le32((u32)lp->tx_insert_ptr); - tmp_addr = virt_to_bus((volatile void *)tmp_addr); - /* Lower 16-bits to MTD_SA0 */ - iowrite16(tmp_addr, ioaddr + MTD_SA0); - /* Higher 16-bits to MTD_SA1 */ - iowrite16((u16)(tmp_addr >> 16), ioaddr + MTD_SA1); - tmp_addr = cpu_to_le32((u32)lp->rx_insert_ptr); - tmp_addr = virt_to_bus((volatile void *)tmp_addr); - iowrite16(tmp_addr, ioaddr + MRD_SA0); - iowrite16((u16)(tmp_addr >> 16), ioaddr + MRD_SA1); + /* Initialise and alloc RX/TX buffers */ + r6040_init_txbufs(dev); + ret = r6040_alloc_rxbufs(dev); + if (ret) + return ret; - /* Buffer Size Register */ - iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); /* Read the PHY ID */ - lp->switch_sig = phy_read(ioaddr, 0, 2); + lp->switch_sig = r6040_phy_read(ioaddr, 0, 2); if (lp->switch_sig == ICPLUS_PHY_ID) { - phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */ + r6040_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); + r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP); + r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE); if (PHY_MODE == 0x3100) - lp->phy_mode = phy_mode_chk(dev); + lp->phy_mode = r6040_phy_mode_chk(dev); else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; } - /* MAC Bus Control Register */ - iowrite16(MBCR_DEFAULT, ioaddr + MBCR); - /* MAC TX/RX Enable */ + /* Set duplex mode */ lp->mcr0 |= lp->phy_mode; - iowrite16(lp->mcr0, ioaddr); - - /* set interrupt waiting time and packet numbers */ - iowrite16(0x0F06, ioaddr + MT_ICR); - iowrite16(0x0F06, ioaddr + MR_ICR); /* improve performance (by RDC guys) */ - phy_write(ioaddr, 30, 17, (phy_read(ioaddr, 30, 17) | 0x4000)); - phy_write(ioaddr, 30, 17, ~((~phy_read(ioaddr, 30, 17)) | 0x2000)); - phy_write(ioaddr, 0, 19, 0x0000); - phy_write(ioaddr, 0, 30, 0x01F0); + r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000)); + r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000)); + r6040_phy_write(ioaddr, 0, 19, 0x0000); + r6040_phy_write(ioaddr, 0, 30, 0x01F0); - /* Interrupt Mask Register */ - iowrite16(INT_MASK, ioaddr + MIER); + /* Initialize all MAC registers */ + r6040_init_mac_regs(dev); + + return 0; } /* @@ -685,13 +788,13 @@ static void r6040_up(struct net_device *dev) static void r6040_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct r6040_private *lp = netdev_priv(dev->priv); + struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; u16 phy_mode; /* Polling PHY Chip Status */ if (PHY_MODE == 0x3100) - phy_mode = phy_mode_chk(dev); + phy_mode = r6040_phy_mode_chk(dev); else phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; @@ -703,8 +806,7 @@ static void r6040_timer(unsigned long data) } /* Timer active again */ - lp->timer.expires = TIMER_WUT; - add_timer(&lp->timer); + mod_timer(&lp->timer, round_jiffies(jiffies + HZ)); } /* Read/set MAC address routines */ @@ -718,7 +820,7 @@ static void r6040_mac_address(struct net_device *dev) iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */ iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */ iowrite16(0, ioaddr + MAC_SM); - udelay(5000); + mdelay(5); /* Restore MAC Address */ adrp = (u16 *) dev->dev_addr; @@ -727,10 +829,9 @@ static void r6040_mac_address(struct net_device *dev) iowrite16(adrp[2], ioaddr + MID_0H); } -static int -r6040_open(struct net_device *dev) +static int r6040_open(struct net_device *dev) { - struct r6040_private *lp = dev->priv; + struct r6040_private *lp = netdev_priv(dev); int ret; /* Request IRQ and Register interrupt handler */ @@ -743,29 +844,39 @@ r6040_open(struct net_device *dev) r6040_mac_address(dev); /* Allocate Descriptor memory */ - lp->desc_pool = pci_alloc_consistent(lp->pdev, - ALLOC_DESC_SIZE, &lp->desc_dma); - if (!lp->desc_pool) + lp->rx_ring = + pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma); + if (!lp->rx_ring) + return -ENOMEM; + + lp->tx_ring = + pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma); + if (!lp->tx_ring) { + pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring, + lp->rx_ring_dma); return -ENOMEM; + } - r6040_up(dev); + ret = r6040_up(dev); + if (ret) { + pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring, + lp->tx_ring_dma); + pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring, + lp->rx_ring_dma); + return ret; + } napi_enable(&lp->napi); netif_start_queue(dev); - if (lp->switch_sig != ICPLUS_PHY_ID) { - /* set and active a timer process */ - init_timer(&lp->timer); - lp->timer.expires = TIMER_WUT; - lp->timer.data = (unsigned long)dev; - lp->timer.function = &r6040_timer; - add_timer(&lp->timer); - } + /* set and active a timer process */ + setup_timer(&lp->timer, r6040_timer, (unsigned long) dev); + if (lp->switch_sig != ICPLUS_PHY_ID) + mod_timer(&lp->timer, jiffies + HZ); return 0; } -static int -r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); struct r6040_descriptor *descptr; @@ -799,7 +910,7 @@ r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) descptr->skb_ptr = skb; descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); - descptr->status = 0x8000; + descptr->status = DSC_OWNER_MAC; /* Trigger the MAC to check the TX descriptor */ iowrite16(0x01, ioaddr + MTPR); lp->tx_insert_ptr = descptr->vndescp; @@ -813,8 +924,7 @@ r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } -static void -r6040_multicast_list(struct net_device *dev) +static void r6040_multicast_list(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; @@ -934,13 +1044,28 @@ static u32 netdev_get_link(struct net_device *dev) return mii_link_ok(&rp->mii_if); } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, .get_link = netdev_get_link, }; +static const struct net_device_ops r6040_netdev_ops = { + .ndo_open = r6040_open, + .ndo_stop = r6040_close, + .ndo_start_xmit = r6040_start_xmit, + .ndo_get_stats = r6040_get_stats, + .ndo_set_multicast_list = r6040_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_do_ioctl = r6040_ioctl, + .ndo_tx_timeout = r6040_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = r6040_poll_controller, +#endif +}; static int __devinit r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -958,24 +1083,27 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, err = pci_enable_device(pdev); if (err) - return err; + goto err_out; /* this should always be supported */ - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses" "not supported by the card\n"); - return -ENODEV; + goto err_out; } - if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses" "not supported by the card\n"); - return -ENODEV; + goto err_out; } /* IO Size check */ if (pci_resource_len(pdev, 0) < io_size) { - printk(KERN_ERR "Insufficient PCI resources, aborting\n"); - return -EIO; + printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n"); + err = -EIO; + goto err_out; } pioaddr = pci_resource_start(pdev, 0); /* IO map base address */ @@ -983,25 +1111,31 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct r6040_private)); if (!dev) { - printk(KERN_ERR "Failed to allocate etherdev\n"); - return -ENOMEM; + printk(KERN_ERR DRV_NAME ": Failed to allocate etherdev\n"); + err = -ENOMEM; + goto err_out; } SET_NETDEV_DEV(dev, &pdev->dev); lp = netdev_priv(dev); - lp->pdev = pdev; - if (pci_request_regions(pdev, DRV_NAME)) { + err = pci_request_regions(pdev, DRV_NAME); + + if (err) { printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); - err = -ENODEV; - goto err_out_disable; + goto err_out_free_dev; } ioaddr = pci_iomap(pdev, bar, io_size); if (!ioaddr) { - printk(KERN_ERR "ioremap failed for device %s\n", + printk(KERN_ERR DRV_NAME ": ioremap failed for device %s\n", pci_name(pdev)); - return -EIO; + err = -EIO; + goto err_out_free_res; } + /* If PHY status change register is still set to zero it means the + * bootloader didn't initialize it */ + if (ioread16(ioaddr + PHY_CC) == 0) + iowrite16(0x9f07, ioaddr + PHY_CC); /* Init system & device */ lp->base = ioaddr; @@ -1018,8 +1152,16 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, adrp[1] = ioread16(ioaddr + MID_0M); adrp[2] = ioread16(ioaddr + MID_0H); + /* Some bootloader/BIOSes do not initialize + * MAC address, warn about that */ + if (!(adrp[0] || adrp[1] || adrp[2])) { + printk(KERN_WARNING DRV_NAME ": MAC address not initialized, generating random\n"); + random_ether_addr(dev->dev_addr); + } + /* Link new device into r6040_root_dev */ lp->pdev = pdev; + lp->dev = dev; /* Init RDC private data */ lp->mcr0 = 0x1002; @@ -1027,22 +1169,14 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, lp->switch_sig = 0; /* The RDC-specific entries in the device structure. */ - dev->open = &r6040_open; - dev->hard_start_xmit = &r6040_start_xmit; - dev->stop = &r6040_close; - dev->get_stats = r6040_get_stats; - dev->set_multicast_list = &r6040_multicast_list; - dev->do_ioctl = &r6040_ioctl; + dev->netdev_ops = &r6040_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &r6040_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = r6040_poll_controller; -#endif + netif_napi_add(dev, &lp->napi, r6040_poll, 64); lp->mii_if.dev = dev; - lp->mii_if.mdio_read = mdio_read; - lp->mii_if.mdio_write = mdio_write; + lp->mii_if.mdio_read = r6040_mdio_read; + lp->mii_if.mdio_write = r6040_mdio_write; lp->mii_if.phy_id = lp->phy_addr; lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; @@ -1051,17 +1185,17 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, err = register_netdev(dev); if (err) { printk(KERN_ERR DRV_NAME ": Failed to register net device\n"); - goto err_out_res; + goto err_out_unmap; } return 0; -err_out_res: +err_out_unmap: + pci_iounmap(pdev, ioaddr); +err_out_free_res: pci_release_regions(pdev); -err_out_disable: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); +err_out_free_dev: free_netdev(dev); - +err_out: return err; } @@ -1078,13 +1212,13 @@ static void __devexit r6040_remove_one(struct pci_dev *pdev) static struct pci_device_id r6040_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6040) }, - {0 } + { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) }, + { 0 } }; MODULE_DEVICE_TABLE(pci, r6040_pci_tbl); static struct pci_driver r6040_driver = { - .name = "r6040", + .name = DRV_NAME, .id_table = r6040_pci_tbl, .probe = r6040_init_one, .remove = __devexit_p(r6040_remove_one),