Commit 31b73ab3 authored by Figo.zhang's avatar Figo.zhang Committed by David S. Miller

NET/KS8695: add support NAPI for Rx

Add support NAPI Rx API for KS8695NET driver.

v2, change the Rx function to NAPI.

in <KS8695X Integrated Multi-port Gateway Solution Register Description
 v1.0>:

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

see arch/arm/mach-ks8695/devices.c:
ks8695_wan_resources[] and ks8695_lan_resources[]
have IORESOURCE_IRQ , it have define the RX irq,
for wan, irq = 29; for lan ,irq = 16.
so we can do this read the interrupt status:

unsigned long mask_bit = 1 << ksp->rx_irq;
status = readl(KS8695_IRQ_VA + KS8695_INTST);
Signed-off-by: default avatarFigo.zhang <figo1802@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d6b9076f
...@@ -35,12 +35,15 @@ ...@@ -35,12 +35,15 @@
#include <mach/regs-switch.h> #include <mach/regs-switch.h>
#include <mach/regs-misc.h> #include <mach/regs-misc.h>
#include <asm/mach/irq.h>
#include <mach/regs-irq.h>
#include "ks8695net.h" #include "ks8695net.h"
#define MODULENAME "ks8695_ether" #define MODULENAME "ks8695_ether"
#define MODULEVERSION "1.01" #define MODULEVERSION "1.01"
/* /*
* Transmit and device reset timeout, default 5 seconds. * Transmit and device reset timeout, default 5 seconds.
*/ */
...@@ -152,6 +155,8 @@ struct ks8695_priv { ...@@ -152,6 +155,8 @@ struct ks8695_priv {
enum ks8695_dtype dtype; enum ks8695_dtype dtype;
void __iomem *io_regs; void __iomem *io_regs;
struct napi_struct napi;
const char *rx_irq_name, *tx_irq_name, *link_irq_name; const char *rx_irq_name, *tx_irq_name, *link_irq_name;
int rx_irq, tx_irq, link_irq; int rx_irq, tx_irq, link_irq;
...@@ -172,6 +177,7 @@ struct ks8695_priv { ...@@ -172,6 +177,7 @@ struct ks8695_priv {
dma_addr_t rx_ring_dma; dma_addr_t rx_ring_dma;
struct ks8695_skbuff rx_buffers[MAX_RX_DESC]; struct ks8695_skbuff rx_buffers[MAX_RX_DESC];
int next_rx_desc_read; int next_rx_desc_read;
spinlock_t rx_lock;
int msg_enable; int msg_enable;
}; };
...@@ -396,25 +402,53 @@ ks8695_tx_irq(int irq, void *dev_id) ...@@ -396,25 +402,53 @@ ks8695_tx_irq(int irq, void *dev_id)
* @irq: The IRQ which went off (ignored) * @irq: The IRQ which went off (ignored)
* @dev_id: The net_device for the interrupt * @dev_id: The net_device for the interrupt
* *
* Process the RX ring, passing any received packets up to the * Use NAPI to receive packets.
* host. If we received anything other than errors, we then
* refill the ring.
*/ */
static irqreturn_t static irqreturn_t
ks8695_rx_irq(int irq, void *dev_id) ks8695_rx_irq(int irq, void *dev_id)
{ {
struct net_device *ndev = (struct net_device *)dev_id; struct net_device *ndev = (struct net_device *)dev_id;
struct ks8695_priv *ksp = netdev_priv(ndev);
unsigned long status;
unsigned long mask_bit = 1 << ksp->rx_irq;
spin_lock(&ksp->rx_lock);
status = readl(KS8695_IRQ_VA + KS8695_INTST);
/*clean rx status bit*/
writel(status | mask_bit , KS8695_IRQ_VA + KS8695_INTST);
if (status & mask_bit) {
if (napi_schedule_prep(&ksp->napi)) {
/*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;
}
static int ks8695_rx(struct net_device *ndev, int budget)
{
struct ks8695_priv *ksp = netdev_priv(ndev); struct ks8695_priv *ksp = netdev_priv(ndev);
struct sk_buff *skb; struct sk_buff *skb;
int buff_n; int buff_n;
u32 flags; u32 flags;
int pktlen; int pktlen;
int last_rx_processed = -1; int last_rx_processed = -1;
int received = 0;
buff_n = ksp->next_rx_desc_read; buff_n = ksp->next_rx_desc_read;
do { while (received < budget
if (ksp->rx_buffers[buff_n].skb && && ksp->rx_buffers[buff_n].skb
!(ksp->rx_ring[buff_n].status & cpu_to_le32(RDES_OWN))) { && (!(ksp->rx_ring[buff_n].status &
cpu_to_le32(RDES_OWN)))) {
rmb(); rmb();
flags = le32_to_cpu(ksp->rx_ring[buff_n].status); flags = le32_to_cpu(ksp->rx_ring[buff_n].status);
/* Found an SKB which we own, this means we /* Found an SKB which we own, this means we
...@@ -464,7 +498,7 @@ ks8695_rx_irq(int irq, void *dev_id) ...@@ -464,7 +498,7 @@ ks8695_rx_irq(int irq, void *dev_id)
/* Relinquish the SKB to the network layer */ /* Relinquish the SKB to the network layer */
skb_put(skb, pktlen); skb_put(skb, pktlen);
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
netif_rx(skb); netif_receive_skb(skb);
/* Record stats */ /* Record stats */
ndev->stats.rx_packets++; ndev->stats.rx_packets++;
...@@ -478,29 +512,44 @@ ks8695_rx_irq(int irq, void *dev_id) ...@@ -478,29 +512,44 @@ ks8695_rx_irq(int irq, void *dev_id)
/* Give the ring entry back to the hardware */ /* Give the ring entry back to the hardware */
ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
rx_finished: rx_finished:
received++;
/* And note this as processed so we can start /* And note this as processed so we can start
* from here next time * from here next time
*/ */
last_rx_processed = buff_n; last_rx_processed = buff_n;
} else {
/* Ran out of things to process, stop now */
break;
}
buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; 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 */
/* And note which RX descriptor we last did anything with */
if (likely(last_rx_processed != -1)) if (likely(last_rx_processed != -1))
ksp->next_rx_desc_read = ksp->next_rx_desc_read =
(last_rx_processed + 1) & MAX_RX_DESC_MASK; (last_rx_processed + 1) &
MAX_RX_DESC_MASK;
/* And refill the buffers */ /* And refill the buffers */
ks8695_refill_rxbuffers(ksp); ks8695_refill_rxbuffers(ksp);
}
return received;
}
/* Kick the RX DMA engine, in case it became suspended */ static int ks8695_poll(struct napi_struct *napi, int budget)
ks8695_writereg(ksp, KS8695_DRSC, 0); {
struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi);
return IRQ_HANDLED; struct net_device *dev = ksp->ndev;
unsigned long mask_bit = 1 << ksp->rx_irq;
unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN);
unsigned long work_done ;
work_done = ks8695_rx(dev, 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;
} }
/** /**
...@@ -1472,6 +1521,8 @@ ks8695_probe(struct platform_device *pdev) ...@@ -1472,6 +1521,8 @@ ks8695_probe(struct platform_device *pdev)
SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
netif_napi_add(ndev, &ksp->napi, ks8695_poll, 64);
/* Retrieve the default MAC addr from the chip. */ /* Retrieve the default MAC addr from the chip. */
/* The bootloader should have left it in there for us. */ /* The bootloader should have left it in there for us. */
...@@ -1505,6 +1556,7 @@ ks8695_probe(struct platform_device *pdev) ...@@ -1505,6 +1556,7 @@ ks8695_probe(struct platform_device *pdev)
/* And initialise the queue's lock */ /* And initialise the queue's lock */
spin_lock_init(&ksp->txq_lock); spin_lock_init(&ksp->txq_lock);
spin_lock_init(&ksp->rx_lock);
/* Specify the RX DMA ring buffer */ /* Specify the RX DMA ring buffer */
ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE; ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE;
...@@ -1626,6 +1678,7 @@ ks8695_drv_remove(struct platform_device *pdev) ...@@ -1626,6 +1678,7 @@ ks8695_drv_remove(struct platform_device *pdev)
struct ks8695_priv *ksp = netdev_priv(ndev); struct ks8695_priv *ksp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
netif_napi_del(&ksp->napi);
unregister_netdev(ndev); unregister_netdev(ndev);
ks8695_release_device(ksp); ks8695_release_device(ksp);
......
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