aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/arm/ks8695net.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/arm/ks8695net.c')
-rw-r--r--drivers/net/arm/ks8695net.c131
1 files changed, 109 insertions, 22 deletions
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index 2a7b7745cc5..be256b34cea 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -35,11 +35,13 @@
#include <mach/regs-switch.h>
#include <mach/regs-misc.h>
+#include <asm/mach/irq.h>
+#include <mach/regs-irq.h>
#include "ks8695net.h"
#define MODULENAME "ks8695_ether"
-#define MODULEVERSION "1.01"
+#define MODULEVERSION "1.02"
/*
* Transmit and device reset timeout, default 5 seconds.
@@ -95,6 +97,9 @@ struct ks8695_skbuff {
#define MAX_RX_DESC 16
#define MAX_RX_DESC_MASK 0xf
+/*napi_weight have better more than rx DMA buffers*/
+#define NAPI_WEIGHT 64
+
#define MAX_RXBUF_SIZE 0x700
#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC)
@@ -120,6 +125,7 @@ enum ks8695_dtype {
* @dev: The platform device object for this interface
* @dtype: The type of this device
* @io_regs: The ioremapped registers for this interface
+ * @napi : Add support NAPI for Rx
* @rx_irq_name: The textual name of the RX IRQ from the platform data
* @tx_irq_name: The textual name of the TX IRQ from the platform data
* @link_irq_name: The textual name of the link IRQ from the
@@ -143,6 +149,7 @@ enum ks8695_dtype {
* @rx_ring_dma: The DMA mapped equivalent of rx_ring
* @rx_buffers: The sk_buff mappings for the RX ring
* @next_rx_desc_read: The next RX descriptor to read from on IRQ
+ * @rx_lock: A lock to protect Rx irq function
* @msg_enable: The flags for which messages to emit
*/
struct ks8695_priv {
@@ -152,6 +159,8 @@ struct ks8695_priv {
enum ks8695_dtype dtype;
void __iomem *io_regs;
+ struct napi_struct napi;
+
const char *rx_irq_name, *tx_irq_name, *link_irq_name;
int rx_irq, tx_irq, link_irq;
@@ -172,6 +181,7 @@ struct ks8695_priv {
dma_addr_t rx_ring_dma;
struct ks8695_skbuff rx_buffers[MAX_RX_DESC];
int next_rx_desc_read;
+ spinlock_t rx_lock;
int msg_enable;
};
@@ -392,29 +402,74 @@ ks8695_tx_irq(int irq, void *dev_id)
}
/**
+ * ks8695_get_rx_enable_bit - Get rx interrupt enable/status bit
+ * @ksp: Private data for the KS8695 Ethernet
+ *
+ * For KS8695 document:
+ * Interrupt Enable Register (offset 0xE204)
+ * Bit29 : WAN MAC Receive Interrupt Enable
+ * Bit16 : LAN MAC Receive Interrupt Enable
+ * Interrupt Status Register (Offset 0xF208)
+ * Bit29: WAN MAC Receive Status
+ * Bit16: LAN MAC Receive Status
+ * So, this Rx interrrupt enable/status bit number is equal
+ * as Rx IRQ number.
+ */
+static inline u32 ks8695_get_rx_enable_bit(struct ks8695_priv *ksp)
+{
+ return ksp->rx_irq;
+}
+
+/**
* ks8695_rx_irq - Receive IRQ handler
* @irq: The IRQ which went off (ignored)
* @dev_id: The net_device for the interrupt
*
- * Process the RX ring, passing any received packets up to the
- * host. If we received anything other than errors, we then
- * refill the ring.
+ * Inform NAPI that packet reception needs to be scheduled
*/
+
static irqreturn_t
ks8695_rx_irq(int irq, void *dev_id)
{
struct net_device *ndev = (struct net_device *)dev_id;
struct ks8695_priv *ksp = netdev_priv(ndev);
+
+ spin_lock(&ksp->rx_lock);
+
+ if (napi_schedule_prep(&ksp->napi)) {
+ unsigned long status = readl(KS8695_IRQ_VA + KS8695_INTEN);
+ unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
+ /*disable rx interrupt*/
+ status &= ~mask_bit;
+ writel(status , KS8695_IRQ_VA + KS8695_INTEN);
+ __napi_schedule(&ksp->napi);
+ }
+
+ spin_unlock(&ksp->rx_lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * ks8695_rx - Receive packets called by NAPI poll method
+ * @ksp: Private data for the KS8695 Ethernet
+ * @budget: The max packets would be receive
+ */
+
+static int ks8695_rx(struct ks8695_priv *ksp, int budget)
+{
+ struct net_device *ndev = ksp->ndev;
struct sk_buff *skb;
int buff_n;
u32 flags;
int pktlen;
int last_rx_processed = -1;
+ int received = 0;
buff_n = ksp->next_rx_desc_read;
- do {
- if (ksp->rx_buffers[buff_n].skb &&
- !(ksp->rx_ring[buff_n].status & cpu_to_le32(RDES_OWN))) {
+ while (received < budget
+ && ksp->rx_buffers[buff_n].skb
+ && (!(ksp->rx_ring[buff_n].status &
+ cpu_to_le32(RDES_OWN)))) {
rmb();
flags = le32_to_cpu(ksp->rx_ring[buff_n].status);
/* Found an SKB which we own, this means we
@@ -464,7 +519,7 @@ ks8695_rx_irq(int irq, void *dev_id)
/* Relinquish the SKB to the network layer */
skb_put(skb, pktlen);
skb->protocol = eth_type_trans(skb, ndev);
- netif_rx(skb);
+ netif_receive_skb(skb);
/* Record stats */
ndev->stats.rx_packets++;
@@ -478,29 +533,55 @@ rx_failure:
/* Give the ring entry back to the hardware */
ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
rx_finished:
+ received++;
/* And note this as processed so we can start
* from here next time
*/
last_rx_processed = buff_n;
- } else {
- /* Ran out of things to process, stop now */
- break;
- }
- buff_n = (buff_n + 1) & MAX_RX_DESC_MASK;
- } while (buff_n != ksp->next_rx_desc_read);
-
- /* And note which RX descriptor we last did anything with */
- if (likely(last_rx_processed != -1))
- ksp->next_rx_desc_read =
- (last_rx_processed + 1) & MAX_RX_DESC_MASK;
-
+ buff_n = (buff_n + 1) & MAX_RX_DESC_MASK;
+ /*And note which RX descriptor we last did */
+ if (likely(last_rx_processed != -1))
+ ksp->next_rx_desc_read =
+ (last_rx_processed + 1) &
+ MAX_RX_DESC_MASK;
+ }
/* And refill the buffers */
ks8695_refill_rxbuffers(ksp);
- /* Kick the RX DMA engine, in case it became suspended */
+ /* Kick the RX DMA engine, in case it became
+ * suspended */
ks8695_writereg(ksp, KS8695_DRSC, 0);
+ return received;
+}
- return IRQ_HANDLED;
+
+/**
+ * ks8695_poll - Receive packet by NAPI poll method
+ * @ksp: Private data for the KS8695 Ethernet
+ * @budget: The remaining number packets for network subsystem
+ *
+ * Invoked by the network core when it requests for new
+ * packets from the driver
+ */
+static int ks8695_poll(struct napi_struct *napi, int budget)
+{
+ struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi);
+ unsigned long work_done;
+
+ unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN);
+ unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
+
+ work_done = ks8695_rx(ksp, budget);
+
+ if (work_done < budget) {
+ unsigned long flags;
+ spin_lock_irqsave(&ksp->rx_lock, flags);
+ /*enable rx interrupt*/
+ writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN);
+ __napi_complete(napi);
+ spin_unlock_irqrestore(&ksp->rx_lock, flags);
+ }
+ return work_done;
}
/**
@@ -1253,6 +1334,7 @@ ks8695_stop(struct net_device *ndev)
struct ks8695_priv *ksp = netdev_priv(ndev);
netif_stop_queue(ndev);
+ napi_disable(&ksp->napi);
netif_carrier_off(ndev);
ks8695_shutdown(ksp);
@@ -1287,6 +1369,7 @@ ks8695_open(struct net_device *ndev)
return ret;
}
+ napi_enable(&ksp->napi);
netif_start_queue(ndev);
return 0;
@@ -1472,6 +1555,8 @@ ks8695_probe(struct platform_device *pdev)
SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
+ netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
+
/* Retrieve the default MAC addr from the chip. */
/* The bootloader should have left it in there for us. */
@@ -1505,6 +1590,7 @@ ks8695_probe(struct platform_device *pdev)
/* And initialise the queue's lock */
spin_lock_init(&ksp->txq_lock);
+ spin_lock_init(&ksp->rx_lock);
/* Specify the RX DMA ring buffer */
ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE;
@@ -1626,6 +1712,7 @@ ks8695_drv_remove(struct platform_device *pdev)
struct ks8695_priv *ksp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
+ netif_napi_del(&ksp->napi);
unregister_netdev(ndev);
ks8695_release_device(ksp);