Commit 21d0556c authored by David S. Miller's avatar David S. Miller

Merge branch 'korina-performance-fixes-and-cleanup'

Roman Yeryomin says:

====================
korina: performance fixes and cleanup

Changes from v1:
- use GRO instead of increasing ring size
- use NAPI_POLL_WEIGHT instead of defining own NAPI_WEIGHT
- optimize rx descriptor flags processing
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ca444073 da1d2def
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright 2004 IDT Inc. (rischelp@idt.com) * Copyright 2004 IDT Inc. (rischelp@idt.com)
* Copyright 2006 Felix Fietkau <nbd@openwrt.org> * Copyright 2006 Felix Fietkau <nbd@openwrt.org>
* Copyright 2008 Florian Fainelli <florian@openwrt.org> * Copyright 2008 Florian Fainelli <florian@openwrt.org>
* Copyright 2017 Roman Yeryomin <roman@advem.lv>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -65,8 +66,8 @@ ...@@ -65,8 +66,8 @@
#include <asm/mach-rc32434/dma_v.h> #include <asm/mach-rc32434/dma_v.h>
#define DRV_NAME "korina" #define DRV_NAME "korina"
#define DRV_VERSION "0.10" #define DRV_VERSION "0.20"
#define DRV_RELDATE "04Mar2008" #define DRV_RELDATE "15Sep2017"
#define STATION_ADDRESS_HIGH(dev) (((dev)->dev_addr[0] << 8) | \ #define STATION_ADDRESS_HIGH(dev) (((dev)->dev_addr[0] << 8) | \
((dev)->dev_addr[1])) ((dev)->dev_addr[1]))
...@@ -92,7 +93,11 @@ ...@@ -92,7 +93,11 @@
#define TX_TIMEOUT (6000 * HZ / 1000) #define TX_TIMEOUT (6000 * HZ / 1000)
enum chain_status { desc_filled, desc_empty }; enum chain_status {
desc_filled,
desc_empty
};
#define IS_DMA_FINISHED(X) (((X) & (DMA_DESC_FINI)) != 0) #define IS_DMA_FINISHED(X) (((X) & (DMA_DESC_FINI)) != 0)
#define IS_DMA_DONE(X) (((X) & (DMA_DESC_DONE)) != 0) #define IS_DMA_DONE(X) (((X) & (DMA_DESC_DONE)) != 0)
#define RCVPKT_LENGTH(X) (((X) & ETH_RX_LEN) >> ETH_RX_LEN_BIT) #define RCVPKT_LENGTH(X) (((X) & ETH_RX_LEN) >> ETH_RX_LEN_BIT)
...@@ -122,8 +127,6 @@ struct korina_private { ...@@ -122,8 +127,6 @@ struct korina_private {
int rx_irq; int rx_irq;
int tx_irq; int tx_irq;
int ovr_irq;
int und_irq;
spinlock_t lock; /* NIC xmit lock */ spinlock_t lock; /* NIC xmit lock */
...@@ -365,11 +368,18 @@ static int korina_rx(struct net_device *dev, int limit) ...@@ -365,11 +368,18 @@ static int korina_rx(struct net_device *dev, int limit)
if ((KORINA_RBSIZE - (u32)DMA_COUNT(rd->control)) == 0) if ((KORINA_RBSIZE - (u32)DMA_COUNT(rd->control)) == 0)
break; break;
/* check that this is a whole packet
* WARNING: DMA_FD bit incorrectly set
* in Rc32434 (errata ref #077) */
if (!(devcs & ETH_RX_LD))
goto next;
if (!(devcs & ETH_RX_ROK)) {
/* Update statistics counters */ /* Update statistics counters */
dev->stats.rx_errors++;
dev->stats.rx_dropped++;
if (devcs & ETH_RX_CRC) if (devcs & ETH_RX_CRC)
dev->stats.rx_crc_errors++; dev->stats.rx_crc_errors++;
if (devcs & ETH_RX_LOR)
dev->stats.rx_length_errors++;
if (devcs & ETH_RX_LE) if (devcs & ETH_RX_LE)
dev->stats.rx_length_errors++; dev->stats.rx_length_errors++;
if (devcs & ETH_RX_OVR) if (devcs & ETH_RX_OVR)
...@@ -377,17 +387,11 @@ static int korina_rx(struct net_device *dev, int limit) ...@@ -377,17 +387,11 @@ static int korina_rx(struct net_device *dev, int limit)
if (devcs & ETH_RX_CV) if (devcs & ETH_RX_CV)
dev->stats.rx_frame_errors++; dev->stats.rx_frame_errors++;
if (devcs & ETH_RX_CES) if (devcs & ETH_RX_CES)
dev->stats.rx_length_errors++; dev->stats.rx_frame_errors++;
if (devcs & ETH_RX_MP)
dev->stats.multicast++; goto next;
}
if ((devcs & ETH_RX_LD) != ETH_RX_LD) {
/* check that this is a whole packet
* WARNING: DMA_FD bit incorrectly set
* in Rc32434 (errata ref #077) */
dev->stats.rx_errors++;
dev->stats.rx_dropped++;
} else if ((devcs & ETH_RX_ROK)) {
pkt_len = RCVPKT_LENGTH(devcs); pkt_len = RCVPKT_LENGTH(devcs);
/* must be the (first and) last /* must be the (first and) last
...@@ -407,7 +411,7 @@ static int korina_rx(struct net_device *dev, int limit) ...@@ -407,7 +411,7 @@ static int korina_rx(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
/* Pass the packet to upper layers */ /* Pass the packet to upper layers */
netif_receive_skb(skb); napi_gro_receive(&lp->napi, skb);
dev->stats.rx_packets++; dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len; dev->stats.rx_bytes += pkt_len;
...@@ -416,8 +420,8 @@ static int korina_rx(struct net_device *dev, int limit) ...@@ -416,8 +420,8 @@ static int korina_rx(struct net_device *dev, int limit)
dev->stats.multicast++; dev->stats.multicast++;
lp->rx_skb[lp->rx_next_done] = skb_new; lp->rx_skb[lp->rx_next_done] = skb_new;
}
next:
rd->devcs = 0; rd->devcs = 0;
/* Restore descriptor's curr_addr */ /* Restore descriptor's curr_addr */
...@@ -891,8 +895,6 @@ static void korina_restart_task(struct work_struct *work) ...@@ -891,8 +895,6 @@ static void korina_restart_task(struct work_struct *work)
*/ */
disable_irq(lp->rx_irq); disable_irq(lp->rx_irq);
disable_irq(lp->tx_irq); disable_irq(lp->tx_irq);
disable_irq(lp->ovr_irq);
disable_irq(lp->und_irq);
writel(readl(&lp->tx_dma_regs->dmasm) | writel(readl(&lp->tx_dma_regs->dmasm) |
DMA_STAT_FINI | DMA_STAT_ERR, DMA_STAT_FINI | DMA_STAT_ERR,
...@@ -911,40 +913,10 @@ static void korina_restart_task(struct work_struct *work) ...@@ -911,40 +913,10 @@ static void korina_restart_task(struct work_struct *work)
} }
korina_multicast_list(dev); korina_multicast_list(dev);
enable_irq(lp->und_irq);
enable_irq(lp->ovr_irq);
enable_irq(lp->tx_irq); enable_irq(lp->tx_irq);
enable_irq(lp->rx_irq); enable_irq(lp->rx_irq);
} }
static void korina_clear_and_restart(struct net_device *dev, u32 value)
{
struct korina_private *lp = netdev_priv(dev);
netif_stop_queue(dev);
writel(value, &lp->eth_regs->ethintfc);
schedule_work(&lp->restart_task);
}
/* Ethernet Tx Underflow interrupt */
static irqreturn_t korina_und_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct korina_private *lp = netdev_priv(dev);
unsigned int und;
spin_lock(&lp->lock);
und = readl(&lp->eth_regs->ethintfc);
if (und & ETH_INT_FC_UND)
korina_clear_and_restart(dev, und & ~ETH_INT_FC_UND);
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
static void korina_tx_timeout(struct net_device *dev) static void korina_tx_timeout(struct net_device *dev)
{ {
struct korina_private *lp = netdev_priv(dev); struct korina_private *lp = netdev_priv(dev);
...@@ -952,25 +924,6 @@ static void korina_tx_timeout(struct net_device *dev) ...@@ -952,25 +924,6 @@ static void korina_tx_timeout(struct net_device *dev)
schedule_work(&lp->restart_task); schedule_work(&lp->restart_task);
} }
/* Ethernet Rx Overflow interrupt */
static irqreturn_t
korina_ovr_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct korina_private *lp = netdev_priv(dev);
unsigned int ovr;
spin_lock(&lp->lock);
ovr = readl(&lp->eth_regs->ethintfc);
if (ovr & ETH_INT_FC_OVR)
korina_clear_and_restart(dev, ovr & ~ETH_INT_FC_OVR);
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
static void korina_poll_controller(struct net_device *dev) static void korina_poll_controller(struct net_device *dev)
{ {
...@@ -993,8 +946,7 @@ static int korina_open(struct net_device *dev) ...@@ -993,8 +946,7 @@ static int korina_open(struct net_device *dev)
} }
/* Install the interrupt handler /* Install the interrupt handler
* that handles the Done Finished * that handles the Done Finished */
* Ovr and Und Events */
ret = request_irq(lp->rx_irq, korina_rx_dma_interrupt, ret = request_irq(lp->rx_irq, korina_rx_dma_interrupt,
0, "Korina ethernet Rx", dev); 0, "Korina ethernet Rx", dev);
if (ret < 0) { if (ret < 0) {
...@@ -1010,31 +962,10 @@ static int korina_open(struct net_device *dev) ...@@ -1010,31 +962,10 @@ static int korina_open(struct net_device *dev)
goto err_free_rx_irq; goto err_free_rx_irq;
} }
/* Install handler for overrun error. */
ret = request_irq(lp->ovr_irq, korina_ovr_interrupt,
0, "Ethernet Overflow", dev);
if (ret < 0) {
printk(KERN_ERR "%s: unable to get OVR IRQ %d\n",
dev->name, lp->ovr_irq);
goto err_free_tx_irq;
}
/* Install handler for underflow error. */
ret = request_irq(lp->und_irq, korina_und_interrupt,
0, "Ethernet Underflow", dev);
if (ret < 0) {
printk(KERN_ERR "%s: unable to get UND IRQ %d\n",
dev->name, lp->und_irq);
goto err_free_ovr_irq;
}
mod_timer(&lp->media_check_timer, jiffies + 1); mod_timer(&lp->media_check_timer, jiffies + 1);
out: out:
return ret; return ret;
err_free_ovr_irq:
free_irq(lp->ovr_irq, dev);
err_free_tx_irq:
free_irq(lp->tx_irq, dev);
err_free_rx_irq: err_free_rx_irq:
free_irq(lp->rx_irq, dev); free_irq(lp->rx_irq, dev);
err_release: err_release:
...@@ -1052,8 +983,6 @@ static int korina_close(struct net_device *dev) ...@@ -1052,8 +983,6 @@ static int korina_close(struct net_device *dev)
/* Disable interrupts */ /* Disable interrupts */
disable_irq(lp->rx_irq); disable_irq(lp->rx_irq);
disable_irq(lp->tx_irq); disable_irq(lp->tx_irq);
disable_irq(lp->ovr_irq);
disable_irq(lp->und_irq);
korina_abort_tx(dev); korina_abort_tx(dev);
tmp = readl(&lp->tx_dma_regs->dmasm); tmp = readl(&lp->tx_dma_regs->dmasm);
...@@ -1073,8 +1002,6 @@ static int korina_close(struct net_device *dev) ...@@ -1073,8 +1002,6 @@ static int korina_close(struct net_device *dev)
free_irq(lp->rx_irq, dev); free_irq(lp->rx_irq, dev);
free_irq(lp->tx_irq, dev); free_irq(lp->tx_irq, dev);
free_irq(lp->ovr_irq, dev);
free_irq(lp->und_irq, dev);
return 0; return 0;
} }
...@@ -1113,8 +1040,6 @@ static int korina_probe(struct platform_device *pdev) ...@@ -1113,8 +1040,6 @@ static int korina_probe(struct platform_device *pdev)
lp->rx_irq = platform_get_irq_byname(pdev, "korina_rx"); lp->rx_irq = platform_get_irq_byname(pdev, "korina_rx");
lp->tx_irq = platform_get_irq_byname(pdev, "korina_tx"); lp->tx_irq = platform_get_irq_byname(pdev, "korina_tx");
lp->ovr_irq = platform_get_irq_byname(pdev, "korina_ovr");
lp->und_irq = platform_get_irq_byname(pdev, "korina_und");
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_regs"); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_regs");
dev->base_addr = r->start; dev->base_addr = r->start;
...@@ -1162,7 +1087,7 @@ static int korina_probe(struct platform_device *pdev) ...@@ -1162,7 +1087,7 @@ static int korina_probe(struct platform_device *pdev)
dev->netdev_ops = &korina_netdev_ops; dev->netdev_ops = &korina_netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops; dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
netif_napi_add(dev, &lp->napi, korina_poll, 64); netif_napi_add(dev, &lp->napi, korina_poll, NAPI_POLL_WEIGHT);
lp->phy_addr = (((lp->rx_irq == 0x2c? 1:0) << 8) | 0x05); lp->phy_addr = (((lp->rx_irq == 0x2c? 1:0) << 8) | 0x05);
lp->mii_if.dev = dev; lp->mii_if.dev = dev;
...@@ -1226,5 +1151,6 @@ module_platform_driver(korina_driver); ...@@ -1226,5 +1151,6 @@ module_platform_driver(korina_driver);
MODULE_AUTHOR("Philip Rischel <rischelp@idt.com>"); MODULE_AUTHOR("Philip Rischel <rischelp@idt.com>");
MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>"); MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_AUTHOR("Roman Yeryomin <roman@advem.lv>");
MODULE_DESCRIPTION("IDT RC32434 (Korina) Ethernet driver"); MODULE_DESCRIPTION("IDT RC32434 (Korina) Ethernet driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment