From 31b73ab3efaa9c69bc72e04605c85ff8c8047b11 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Wed, 28 Oct 2009 03:55:24 -0700 Subject: NET/KS8695: add support NAPI for Rx Add support NAPI Rx API for KS8695NET driver. v2, change the Rx function to NAPI. in : 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: Figo.zhang Signed-off-by: David S. Miller --- drivers/net/arm/ks8695net.c | 103 +++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 25 deletions(-) (limited to 'drivers/net/arm/ks8695net.c') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 2a7b7745cc55..ed0b0f3b7122 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -35,12 +35,15 @@ #include #include +#include +#include #include "ks8695net.h" #define MODULENAME "ks8695_ether" #define MODULEVERSION "1.01" + /* * Transmit and device reset timeout, default 5 seconds. */ @@ -152,6 +155,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 +177,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; }; @@ -396,25 +402,53 @@ ks8695_tx_irq(int irq, void *dev_id) * @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. + * Use NAPI to receive packets. */ + 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); + 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 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 +498,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 +512,44 @@ 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; - - /* And refill the buffers */ - ks8695_refill_rxbuffers(ksp); - - /* Kick the RX DMA engine, in case it became suspended */ - ks8695_writereg(ksp, KS8695_DRSC, 0); + 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); + } + return received; +} - return IRQ_HANDLED; +static int ks8695_poll(struct napi_struct *napi, int budget) +{ + struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi); + 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) SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + netif_napi_add(ndev, &ksp->napi, ks8695_poll, 64); + /* Retrieve the default MAC addr from the chip. */ /* The bootloader should have left it in there for us. */ @@ -1505,6 +1556,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 +1678,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); -- cgit v1.2.3 From 68d8287ce1e1da3c99881385a93e74f68c454fc2 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Fri, 30 Oct 2009 03:05:11 +0000 Subject: NET:KS8695: add API for get rx interrupt bit 1. Add API Add k8695_get_rx_enable_bit() for get Rx interrupt enable/status bit. 2. add some comment or document about some functions and variables. 3. update driver version to "1.02" 4. add napi_enable() and napi_disable() in open/close file method. Signed-off-by: Figo.zhang Signed-off-by: David S. Miller --- drivers/net/arm/ks8695net.c | 67 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 12 deletions(-) (limited to 'drivers/net/arm/ks8695net.c') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index ed0b0f3b7122..0073d198715b 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -41,8 +41,7 @@ #include "ks8695net.h" #define MODULENAME "ks8695_ether" -#define MODULEVERSION "1.01" - +#define MODULEVERSION "1.02" /* * Transmit and device reset timeout, default 5 seconds. @@ -98,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) @@ -123,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 @@ -146,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 { @@ -397,12 +401,31 @@ ks8695_tx_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * 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 * - * Use NAPI to receive packets. + * Inform NAPI that packet reception needs to be scheduled */ static irqreturn_t @@ -412,7 +435,7 @@ ks8695_rx_irq(int irq, void *dev_id) struct ks8695_priv *ksp = netdev_priv(ndev); unsigned long status; - unsigned long mask_bit = 1 << ksp->rx_irq; + unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp); spin_lock(&ksp->rx_lock); @@ -434,9 +457,15 @@ ks8695_rx_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int ks8695_rx(struct net_device *ndev, int budget) +/** + * 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 ks8695_priv *ksp = netdev_priv(ndev); + struct net_device *ndev = ksp->ndev; struct sk_buff *skb; int buff_n; u32 flags; @@ -526,20 +555,32 @@ rx_finished: /* And refill the buffers */ ks8695_refill_rxbuffers(ksp); + + /* Kick the RX DMA engine, in case it became + * suspended */ + ks8695_writereg(ksp, KS8695_DRSC, 0); } return received; } + +/** + * 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); - 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; - 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(dev, budget); + work_done = ks8695_rx(ksp, budget); if (work_done < budget) { unsigned long flags; @@ -1302,6 +1343,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); @@ -1336,6 +1378,7 @@ ks8695_open(struct net_device *ndev) return ret; } + napi_enable(&ksp->napi); netif_start_queue(ndev); return 0; @@ -1521,7 +1564,7 @@ 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, 64); + 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. */ -- cgit v1.2.3 From fa6cae143d58c74d800b8dbdd8b9f058614874f2 Mon Sep 17 00:00:00 2001 From: zeal Date: Mon, 16 Nov 2009 04:58:09 +0000 Subject: KS8695: fix ks8695_rx_irq() bug. ks8695 rx irq is edge-level. Before arriving at irq handler, the corresponding status bit has been clear(irq's ack). So we should not check it after that. Signed-off-by: zeal Signed-off-by: David S. Miller --- drivers/net/arm/ks8695net.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/net/arm/ks8695net.c') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 0073d198715b..e15451a85107 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -433,24 +433,16 @@ ks8695_rx_irq(int irq, void *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 << ks8695_get_rx_enable_bit(ksp); 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); - } + 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); -- cgit v1.2.3 From 5c427ff9e4cc61625d48172ea082ae99e21eea6a Mon Sep 17 00:00:00 2001 From: zeal Date: Mon, 16 Nov 2009 04:58:10 +0000 Subject: KS8695: fix ks8695_rx() unreasonable action. ks8695_rx() will call refill_buffers() for every incoming packet. Its not necessary. We just need do it after finishing receiving thing. And the 'RX dma engine' is in the same situation. This blocks our user space application. The following patch may fix it. Signed-off-by: zeal Signed-off-by: David S. Miller --- drivers/net/arm/ks8695net.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net/arm/ks8695net.c') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index e15451a85107..be256b34cea8 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -544,14 +544,13 @@ rx_finished: 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 */ - ks8695_writereg(ksp, KS8695_DRSC, 0); } + /* And refill the buffers */ + ks8695_refill_rxbuffers(ksp); + + /* Kick the RX DMA engine, in case it became + * suspended */ + ks8695_writereg(ksp, KS8695_DRSC, 0); return received; } -- cgit v1.2.3