diff options
author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-16 13:24:41 +0000 |
---|---|---|
committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-16 13:24:41 +0000 |
commit | 3c86e2801fce91e80de3c06e94f086538fb1f6cc (patch) | |
tree | 88c31abd2abc9bafebd9c67d742113814c79edfe /target/linux | |
parent | 4c73b6629a09945637f20e93f073b4efbb35def4 (diff) |
This patch applies to the RDC 32xx ethernet driver (svn r10754, first patch applied) and fixes the following issues:
- re-added the parent parameter to specify a netdevice to steal the MAC address from (optional).
- fixed null pointer access in r6040_rx() (lp->dev init. was missing)
- fixed "scheduling while atomic" endless loop if tx_timeout() was called (caused by the re-allocs of the buffers)
- fixed tx timeouts (tx irq weren't re-enabled on rx irq)
It adds some defines and cleans the code a bit (IMHO).
Signed-Off by Joerg Albert <jal2@gmx.de>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11507 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/rdc/files/drivers/net/r6040.c | 241 |
1 files changed, 135 insertions, 106 deletions
diff --git a/target/linux/rdc/files/drivers/net/r6040.c b/target/linux/rdc/files/drivers/net/r6040.c index 032884e34..0b09f79d2 100644 --- a/target/linux/rdc/files/drivers/net/r6040.c +++ b/target/linux/rdc/files/drivers/net/r6040.c @@ -128,6 +128,15 @@ MODULE_PARM_DESC(debug, "debug mask (-1 for all)"); #define MISR 0x3C /* Status register */ #define MIER 0x40 /* INT enable register */ #define MSK_INT 0x0000 /* Mask off interrupts */ +#define RX_FINISH 0x0001 /* rx finished irq */ +#define RX_NO_DESC 0x0002 /* rx no descr. avail. irq */ +#define RX_FIFO_FULL 0x0004 /* rx fifo full irq */ +#define RX_EARLY 0x0008 /* rx early irq */ +#define TX_FINISH 0x0010 /* tx finished irq */ +#define TX_EARLY 0x0080 /* tx early irq */ +#define EVENT_OVRFL 0x0100 /* event counter overflow irq */ +#define LINK_CHANGED 0x0200 /* PHY link changed irq */ + #define ME_CISR 0x44 /* Event counter INT status */ #define ME_CIER 0x48 /* Event counter INT enable */ #define MR_CNT 0x50 /* Successfully received packet counter */ @@ -164,7 +173,12 @@ MODULE_PARM_DESC(debug, "debug mask (-1 for all)"); #define MAX_BUF_SIZE 0x600 #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 MBCR_DEFAULT 0x012A /* MAC Bus Control Register: + - wait 1 host clock until SDRAM bus request + becomes high priority + - RX FIFO: 32 byte + - TX FIFO: 64 byte + - FIFO transfer length: 16 byte */ #define MCAST_MAX 4 /* Max number multicast addresses to filter */ /* PHY settings */ @@ -176,10 +190,11 @@ MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>," MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver"); -#define RX_INT 0x0001 -#define TX_INT 0x0010 -#define RX_NO_DESC_INT 0x0002 -#define INT_MASK (RX_INT | TX_INT) +/*! which rx interrupts do we allow */ +#define RX_INTS (RX_FIFO_FULL|RX_NO_DESC|RX_FINISH) +/*! which tx interrupts do we allow */ +#define TX_INTS (TX_FINISH) +#define INT_MASK (RX_INTS | TX_INTS) struct r6040_descriptor { u16 status, len; /* 0-3 */ @@ -213,12 +228,20 @@ struct r6040_private { void __iomem *base; }; +struct net_device *parent_dev; +static char *parent; +module_param(parent, charp, 0444); +MODULE_PARM_DESC(parent, "Parent network device name to get the MAC address from"); + static char version[] __devinitdata = KERN_INFO DRV_NAME ": RDC R6040 NAPI net driver," "version "DRV_VERSION " (" DRV_RELDATE ")\n"; static int phy_table[] = { PHY1_ADDR, PHY2_ADDR }; +/* forward declarations */ +void r6040_multicast_list(struct net_device *dev); + /* jal2: comment out to get more symbols for debugging */ //#define STATIC static #define STATIC @@ -362,7 +385,7 @@ void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, desc_ring, desc_dma, size); while (size-- > 0) { - mapping += sizeof(sizeof(*desc)); + mapping += sizeof(*desc); desc->ndesc = cpu_to_le32(mapping); desc->vndescp = desc + 1; desc++; @@ -376,7 +399,6 @@ void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, STATIC void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) { struct r6040_descriptor *descptr; - void __iomem *ioaddr = lp->base; dbg(DBG_RX_BUF, "rx_insert %p rx_free_desc x%x dev %p\n", lp->rx_insert_ptr, lp->rx_free_desc, dev); @@ -399,8 +421,6 @@ STATIC void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) descptr, descptr->skb_ptr->data, descptr->buf, lp->rx_free_desc); descptr = descptr->vndescp; lp->rx_free_desc++; - /* Trigger RX DMA */ - iowrite16(lp->mcr0 | 0x0002, ioaddr); } lp->rx_insert_ptr = descptr; } @@ -432,7 +452,6 @@ dump_tx_ring(struct r6040_private *lp) void r6040_alloc_txbufs(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; lp->tx_free_desc = TX_DCNT; @@ -444,8 +463,6 @@ void r6040_alloc_txbufs(struct net_device *dev) dump_tx_ring(lp); } #endif - iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); - iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); } #if (DEBUG & DBG_RX_RING_DUMP) @@ -475,7 +492,6 @@ dump_rx_ring(struct r6040_private *lp) void r6040_alloc_rxbufs(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; lp->rx_free_desc = 0; @@ -489,9 +505,61 @@ void r6040_alloc_rxbufs(struct net_device *dev) dump_rx_ring(lp); } #endif +} + +/*! 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(0x0F06, ioaddr + MT_ICR); + iowrite16(0x0F06, 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) @@ -499,27 +567,18 @@ 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, status %4.4x, PHY status " - "%4.4x\n", - dev->name, ioread16(ioaddr + MIER), - mdio_read(dev, priv->mii_if.phy_id, MII_BMSR)); - - disable_irq(dev->irq); - napi_disable(&priv->napi); - spin_lock(&priv->lock); - /* Clear all descriptors */ - r6040_free_txbufs(dev); - r6040_free_rxbufs(dev); - r6040_alloc_txbufs(dev); - r6040_alloc_rxbufs(dev); - - /* Reset MAC */ - iowrite16(MAC_RST, ioaddr + MCR1); - spin_unlock(&priv->lock); - enable_irq(dev->irq); + /* 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++; - netif_wake_queue(dev); + + /* Reset MAC and re-init all registers */ + r6040_init_mac_regs(priv); } struct net_device_stats *r6040_get_stats(struct net_device *dev) @@ -543,28 +602,18 @@ void r6040_down(struct net_device *dev) void __iomem *ioaddr = lp->base; struct pci_dev *pdev = lp->pdev; int limit = 2048; - u16 *adrp; - u16 cmd; dbg(DBG_EXIT, "ENTER\n"); /* Stop MAC */ iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ iowrite16(MAC_RST, ioaddr + MCR1); /* Reset RDC MAC */ - while (limit--) { - cmd = ioread16(ioaddr + MCR1); - if (cmd & 0x1) - break; - } + udelay(100); + while ((ioread16(ioaddr+MCR1) & 1) && limit-- > 0); if (limit <= 0) - err("timeout while waiting for reset\n"); + err("timeout while waiting for reset done.\n"); - /* Restore MAC Address to MIDx */ - adrp = (u16 *) dev->dev_addr; - 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 */ @@ -670,8 +719,6 @@ int r6040_rx(struct net_device *dev, int limit) 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 */ @@ -803,7 +850,7 @@ int r6040_poll(struct napi_struct *napi, int budget) if (work_done < budget) { netif_rx_complete(dev, napi); /* Enable RX interrupt */ - iowrite16(ioread16(ioaddr + MIER) | RX_INT, ioaddr + MIER); + iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER); } return work_done; } @@ -816,8 +863,6 @@ irqreturn_t r6040_interrupt(int irq, void *dev_id) void __iomem *ioaddr = lp->base; u16 status; - /* Mask off RDC MAC interrupt */ - iowrite16(MSK_INT, ioaddr + MIER); /* Read MISR status and clear */ status = ioread16(ioaddr + MISR); @@ -826,12 +871,24 @@ irqreturn_t r6040_interrupt(int irq, void *dev_id) if (status == 0x0000 || status == 0xffff) return IRQ_NONE; - /* RX interrupt request */ - if (status & 0x01) { + /* 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); - iowrite16(TX_INT, ioaddr + MIER); } + /* rx FIFO full */ + if (status & (1<<2)) { + dev->stats.rx_fifo_errors++; + } + /* TX interrupt request */ if (status & 0x10) r6040_tx(dev); @@ -860,8 +917,6 @@ void r6040_up(struct net_device *dev) r6040_alloc_txbufs(dev); r6040_alloc_rxbufs(dev); - /* Buffer Size Register */ - iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); /* Read the PHY ID */ lp->switch_sig = phy_read(ioaddr, 0, 2); @@ -878,16 +933,9 @@ void r6040_up(struct net_device *dev) else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; } - /* MAC Bus Control Register */ - iowrite16(MBCR_DEFAULT, ioaddr + MBCR); - - /* MAC TX/RX Enable */ + +/* configure 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)); @@ -895,8 +943,8 @@ void r6040_up(struct net_device *dev) phy_write(ioaddr, 0, 19, 0x0000); phy_write(ioaddr, 0, 30, 0x01F0); - /* Interrupt Mask Register */ - iowrite16(INT_MASK, ioaddr + MIER); + /* Reset MAC and init all registers */ + r6040_init_mac_regs(lp); } /* @@ -927,32 +975,6 @@ void r6040_timer(unsigned long data) mod_timer(&lp->timer, jiffies + round_jiffies(HZ)); } -/* Read/set MAC address routines */ -void r6040_mac_address(struct net_device *dev) -{ - struct r6040_private *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - u16 *adrp; - - /* MAC operation register */ - iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */ - iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */ - iowrite16(0, ioaddr + MAC_SM); - udelay(5000); - - /* Restore MAC Address */ - adrp = (u16 *) dev->dev_addr; - iowrite16(adrp[0], ioaddr + MID_0L); - iowrite16(adrp[1], ioaddr + MID_0M); - iowrite16(adrp[2], ioaddr + MID_0H); - - { - char obuf[3*ETH_ALEN] __attribute__ ((unused)); - dbg(DBG_MAC_ADDR, "set MAC addr %s\n", - hex2str(dev->dev_addr, obuf, ETH_ALEN, ':')); - } -} - int r6040_open(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); @@ -967,9 +989,6 @@ int r6040_open(struct net_device *dev) dbg(DBG_OPEN, "got irq %d\n", dev->irq); - /* Set MAC address */ - r6040_mac_address(dev); - /* Allocate Descriptor memory */ lp->rx_ring = pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma); @@ -1058,6 +1077,7 @@ int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } +/*! set MAC addresses and promiscous mode */ void r6040_multicast_list(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); @@ -1067,6 +1087,7 @@ void r6040_multicast_list(struct net_device *dev) unsigned long flags; struct dev_mc_list *dmi = dev->mc_list; int i; + char obuf[3*ETH_ALEN] __attribute__ ((unused)); /* MAC Address */ adrp = (u16 *)dev->dev_addr; @@ -1074,6 +1095,9 @@ void r6040_multicast_list(struct net_device *dev) iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); + dbg(DBG_MAC_ADDR, "%s: set MAC addr %s\n", + dev->name, hex2str(dev->dev_addr, obuf, ETH_ALEN, ':')); + /* Promiscous Mode */ spin_lock_irqsave(&lp->lock, flags); @@ -1195,7 +1219,6 @@ int __devinit r6040_init_one(struct pci_dev *pdev, static int card_idx = -1; int bar = 0; long pioaddr; - u16 *adrp; printk(KERN_INFO "%s\n", version); printk(KERN_INFO DRV_NAME ": debug %x\n", debug); @@ -1233,6 +1256,7 @@ int __devinit r6040_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); lp = netdev_priv(dev); lp->pdev = pdev; + lp->dev = dev; if (pci_request_regions(pdev, DRV_NAME)) { printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); @@ -1254,14 +1278,8 @@ int __devinit r6040_init_one(struct pci_dev *pdev, spin_lock_init(&lp->lock); pci_set_drvdata(pdev, dev); - /* Set MAC address */ card_idx++; - adrp = (u16 *)dev->dev_addr; - adrp[0] = ioread16(ioaddr + MID_0L); - adrp[1] = ioread16(ioaddr + MID_0M); - adrp[2] = ioread16(ioaddr + MID_0H); - /* Link new device into r6040_root_dev */ lp->pdev = pdev; @@ -1282,11 +1300,19 @@ int __devinit r6040_init_one(struct pci_dev *pdev, dev->watchdog_timeo = TX_TIMEOUT; { - /* jal2: added for debugging only: set fixed mac address. - Otherwise we need to call "ifconfig ethX hw ether XX:XX:..." - before we can invoke "ifconfig ethX up" */ + /* TODO: fix the setting of the MAC address. + Right now you must either specify a netdevice with "parent=", whose + address is copied or the (default) address of the Sitecom WL-153 + bootloader is used */ static const u8 dflt_addr[ETH_ALEN] = {0,0x50,0xfc,2,3,4}; - memcpy(dev->dev_addr, dflt_addr, ETH_ALEN); + if (parent_dev) { + memcpy(dev->dev_addr, parent_dev->dev_addr, ETH_ALEN); + } else { + printk(KERN_WARNING "%s: no parent - using default mac address\n", + dev->name); + memcpy(dev->dev_addr, dflt_addr, ETH_ALEN); + } + dev->dev_addr[ETH_ALEN-1] += card_idx; /* + 0 or 1 */ } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1348,6 +1374,9 @@ static struct pci_driver r6040_driver = { static int __init r6040_init(void) { + if (parent) + parent_dev = dev_get_by_name(&init_net, parent); + return pci_register_driver(&r6040_driver); } |