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

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
Loading
Loading
Loading
Loading
+78 −152
Original line number Original line Diff line number Diff line
@@ -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 @@
#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 @@


#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 {


	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)
		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)
			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)
		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)
			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)
	 */
	 */
	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)
	}
	}
	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)
	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)
	}
	}


	/* 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)
		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)
	/* 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)


	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)


	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)
	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);
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");