Staging: Improvments to Octeon Ethernet driver.
Subsystems (4)
cover Staging: Improvments to Octeon Ethernet driver.
These patches attempt to cleanup and improve the octeon-ethernet driver in staging. The first patch fixes up octeon interrupt handling in preparation for the following patches. The second and third patches convert to NAPI and enable scatter-gather as well is cleaning up some ugly garbage.
Since Octeon is a MIPS based SOC, we might want to merge the entire series via Ralf's linux-mips.org tree.
I will reply with the three patches.
David Daney (3):
MIPS: Octeon: Fix EIO handling.
Staging: Octeon Ethernet: Clean up and convert to NAPI.
Staging: Octeon Ethernet: Enable scatter-gather.
arch/mips/cavium-octeon/octeon-irq.c | 40 +++- drivers/staging/octeon/Kconfig | 1 + drivers/staging/octeon/ethernet-defines.h | 28 --- drivers/staging/octeon/ethernet-mem.c | 89 +++----- drivers/staging/octeon/ethernet-rx.c | 377 ++++++++++++++++------------ drivers/staging/octeon/ethernet-rx.h | 25 ++- drivers/staging/octeon/ethernet-tx.c | 330 ++++++++++++------------- drivers/staging/octeon/ethernet-tx.h | 27 +-- drivers/staging/octeon/ethernet.c | 157 +++++-------- drivers/staging/octeon/octeon-ethernet.h | 48 +--- 10 files changed, 532 insertions(+), 590 deletions(-)
PATCH 1/3 MIPS: Octeon: Fix EIO handling.
If an interrupt handler disables interrupts, the EOI function will just reenable them. This will put us in an endless loop when the upcoming Ethernet driver patches are applied.
Only reenable the interrupt on EOI if it is not IRQ_DISABLED. This requires that the EIO function be separate from the ENABLE function. We also rename the ACK functions to correspond with their function.
--- arch/mips/cavium-octeon/octeon-irq.c | 40 ++++++++++++++++++++++++++++----- 1 files changed, 34 insertions(+), 6 deletions(-)
arch/mips/cavium-octeon/octeon-irq.c +34 -6
@@ -193,7 +193,7 @@ static void octeon_irq_ciu0_enable_v2(unsigned int irq)* Disable the irq on the current core for chips that have the EN*_W1{S,C} * registers. */ -static void octeon_irq_ciu0_disable_v2 (unsigned int irq) +static void octeon_irq_ciu0_ack_v2 (unsigned int irq) {int index =cvmx_get_core_num () *2 ;u64 mask =1ull << (irq -OCTEON_IRQ_WORKQ0 );
@@ -202,6 +202,20 @@ static void octeon_irq_ciu0_disable_v2(unsigned int irq) }/* +* Enable the irq on the current core for chips that have the EN*_W1{S,C} +* registers. +*/ +static void octeon_irq_ciu0_eoi_v2 (unsigned int irq) +{ +struct irq_desc *desc = irq_desc + irq; +int index =cvmx_get_core_num () *2 ; +u64 mask =1ull << (irq -OCTEON_IRQ_WORKQ0 ); + +if ((desc->status &IRQ_DISABLED ) ==0 ) +cvmx_write_csr (CVMX_CIU_INTX_EN0_W1S (index), mask); +} + +/* * Disable the irq on the all cores for chips that have the EN*_W1{S,C} * registers. */
@@ -272,8 +286,8 @@ static struct irq_chip octeon_irq_chip_ciu0_v2 = { .name = "CIU0", .enable = octeon_irq_ciu0_enable_v2, .disable = octeon_irq_ciu0_disable_all_v2, - .ack = octeon_irq_ciu0_disable_v2, - .eoi = octeon_irq_ciu0_enable_v2, + .ack = octeon_irq_ciu0_ack_v2, + .eoi = octeon_irq_ciu0_eoi_v2,#ifdef CONFIG_SMP .set_affinity = octeon_irq_ciu0_set_affinity_v2,#endif
@@ -374,7 +388,7 @@ static void octeon_irq_ciu1_enable_v2(unsigned int irq)* Disable the irq on the current core for chips that have the EN*_W1{S,C} * registers. */ -static void octeon_irq_ciu1_disable_v2 (unsigned int irq) +static void octeon_irq_ciu1_ack_v2 (unsigned int irq) {int index =cvmx_get_core_num () *2 +1 ;u64 mask =1ull << (irq -OCTEON_IRQ_WDOG0 );
@@ -383,6 +397,20 @@ static void octeon_irq_ciu1_disable_v2(unsigned int irq) }/* +* Enable the irq on the current core for chips that have the EN*_W1{S,C} +* registers. +*/ +static void octeon_irq_ciu1_eoi_v2 (unsigned int irq) +{ +struct irq_desc *desc = irq_desc + irq; +int index =cvmx_get_core_num () *2 +1 ; +u64 mask =1ull << (irq -OCTEON_IRQ_WDOG0 ); + +if ((desc->status &IRQ_DISABLED ) ==0 ) +cvmx_write_csr (CVMX_CIU_INTX_EN1_W1S (index), mask); +} + +/* * Disable the irq on the all cores for chips that have the EN*_W1{S,C} * registers. */
@@ -455,8 +483,8 @@ static struct irq_chip octeon_irq_chip_ciu1_v2 = { .name = "CIU0", .enable = octeon_irq_ciu1_enable_v2, .disable = octeon_irq_ciu1_disable_all_v2, - .ack = octeon_irq_ciu1_disable_v2, - .eoi = octeon_irq_ciu1_enable_v2, + .ack = octeon_irq_ciu1_ack_v2, + .eoi = octeon_irq_ciu1_eoi_v2,#ifdef CONFIG_SMP .set_affinity = octeon_irq_ciu1_set_affinity_v2,#endif
Signature · 1 line
1.6.0.6
PATCH 2/3 Staging: Octeon Ethernet: Clean up and convert to NAPI.
In reply to David DaneyConvert the driver to be a reasonably well behaved NAPI citizen. Also clean up memory allocation and tx buffer accounding code. Remove some configuration #defines and other unused code that are not applicable to the in-tree driver.
--- drivers/staging/octeon/Kconfig | 1 + drivers/staging/octeon/ethernet-defines.h | 28 --- drivers/staging/octeon/ethernet-mem.c | 89 +++----- drivers/staging/octeon/ethernet-rx.c | 377 ++++++++++++++++------------ drivers/staging/octeon/ethernet-rx.h | 25 ++- drivers/staging/octeon/ethernet-tx.c | 273 +++++++++------------ drivers/staging/octeon/ethernet-tx.h | 27 +-- drivers/staging/octeon/ethernet.c | 150 +++++------- drivers/staging/octeon/octeon-ethernet.h | 48 +--- 9 files changed, 443 insertions(+), 575 deletions(-)
drivers/staging/octeon/Kconfig +1 -0
@@ -3,6 +3,7 @@ config OCTEON_ETHERNET depends on CPU_CAVIUM_OCTEON select PHYLIB select MDIO_OCTEON + select HIGH_RES_TIMERS help This driver supports the builtin ethernet ports on Cavium Networks' products in the Octeon family. This driver supports the
drivers/staging/octeon/ethernet-defines.h +0 -28
@@ -41,17 +41,10 @@* Tells the driver to populate the packet buffers with kernel skbuffs. * This allows the driver to receive packets without copying them. It also * means that 32bit userspace can't access the packet buffers. -* USE_32BIT_SHARED -* This define tells the driver to allocate memory for buffers from the -* 32bit sahred region instead of the kernel memory space. * USE_HW_TCPUDP_CHECKSUM * Controls if the Octeon TCP/UDP checksum engine is used for packet * output. If this is zero, the kernel will perform the checksum in * software. -* USE_MULTICORE_RECEIVE -* Process receive interrupts on multiple cores. This spreads the network -* load across the first 8 processors. If ths is zero, only one core -* processes incomming packets. * USE_ASYNC_IOBDMA * Use asynchronous IO access to hardware. This uses Octeon's asynchronous * IOBDMAs to issue IO accesses without stalling. Set this to zero
@@ -75,29 +68,15 @@#define CONFIG_CAVIUM_RESERVE32 0#endif -#if CONFIG_CAVIUM_RESERVE32 -#define USE_32BIT_SHARED 1 -#define USE_SKBUFFS_IN_HW 0 -#define REUSE_SKBUFFS_WITHOUT_FREE 0 -#else -#define USE_32BIT_SHARED 0#define USE_SKBUFFS_IN_HW 1#ifdef CONFIG_NETFILTER #define REUSE_SKBUFFS_WITHOUT_FREE 0#else #define REUSE_SKBUFFS_WITHOUT_FREE 1#endif -#endif - -/* Max interrupts per second per core */ -#define INTERRUPT_LIMIT 10000 -/* Don't limit the number of interrupts */ -/*#define INTERRUPT_LIMIT 0 */ #define USE_HW_TCPUDP_CHECKSUM 1 -#define USE_MULTICORE_RECEIVE 1 -/* Enable Random Early Dropping under load */ #define USE_RED 1#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
@@ -115,17 +94,10 @@/* Use this to not have FPA frees control L2 */ /*#define DONT_WRITEBACK(x) 0 */ -/* Maximum number of packets to process per interrupt. */ -#define MAX_RX_PACKETS 120/* Maximum number of SKBs to try to free per xmit packet. */ #define MAX_SKB_TO_FREE 10#define MAX_OUT_QUEUE_DEPTH 1000 -#ifndef CONFIG_SMP -#undef USE_MULTICORE_RECEIVE -#define USE_MULTICORE_RECEIVE 0 -#endif -#define IP_PROTOCOL_TCP 6#define IP_PROTOCOL_UDP 0x11
drivers/staging/octeon/ethernet-mem.c +28 -61
132 lines not on this page · raw message
drivers/staging/octeon/ethernet-rx.c +215 -162
544 lines not on this page · raw message
drivers/staging/octeon/ethernet-rx.h +22 -3
@@ -24,10 +24,29 @@* This file may also be available under a different license from Cavium. * Contact Cavium Networks for more information *********************************************************************/ +#include "cvmx-fau.h" -irqreturn_t cvm_oct_do_interrupt (int cpl,void *dev_id);void cvm_oct_poll_controller (struct net_device *dev); -void cvm_oct_tasklet_rx (unsigned long unused); -void cvm_oct_rx_initialize (void );void cvm_oct_rx_shutdown (void ); + +static inline void cvm_oct_rx_refill_pool (int fill_threshold) +{ +int number_to_free; +int num_freed; +/* Refill the packet buffer pool */ + number_to_free = +cvmx_fau_fetch_and_add32 (FAU_NUM_PACKET_BUFFERS_TO_FREE ,0 ); + +if (number_to_free > fill_threshold) { +cvmx_fau_atomic_add32 (FAU_NUM_PACKET_BUFFERS_TO_FREE , + -number_to_free); + num_freed =cvm_oct_mem_fill_fpa (CVMX_FPA_PACKET_POOL , +CVMX_FPA_PACKET_POOL_SIZE , + number_to_free); +if (num_freed != number_to_free) { +cvmx_fau_atomic_add32 (FAU_NUM_PACKET_BUFFERS_TO_FREE , + number_to_free - num_freed); + } + } +}
drivers/staging/octeon/ethernet-tx.c +111 -162
358 lines not on this page · raw message
drivers/staging/octeon/ethernet-tx.h +2 -25
@@ -30,28 +30,5 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev);int cvm_oct_transmit_qos (struct net_device *dev,void *work_queue_entry,int do_free,int qos);void cvm_oct_tx_shutdown (struct net_device *dev); - -/** -* Free dead transmit skbs. -* -* @priv: The driver data -* @skb_to_free: The number of SKBs to free (free none if negative). -* @qos: The queue to free from. -* @take_lock: If true, acquire the skb list lock. -*/ -static inline void cvm_oct_free_tx_skbs (struct octeon_ethernet *priv, -int skb_to_free, -int qos,int take_lock) -{ -/* Free skbuffs not in use by the hardware. */ -if (skb_to_free >0 ) { -if (take_lock) -spin_lock (&priv->tx_free_list[qos].lock); -while (skb_to_free >0 ) { -dev_kfree_skb (__skb_dequeue (&priv->tx_free_list[qos])); - skb_to_free--; - } -if (take_lock) -spin_unlock (&priv->tx_free_list[qos].lock); - } -} +void cvm_oct_free_tx_skbs (struct octeon_ethernet *priv); +enum hrtimer_restart cvm_oct_restart_tx (struct hrtimer *timer);
drivers/staging/octeon/ethernet.c +57 -93
229 lines not on this page · raw message
drivers/staging/octeon/octeon-ethernet.h +7 -41
70 lines not on this page · raw message
Signature · 1 line
1.6.0.6
David Miller
maintainerRe: [PATCH 2/3] Staging: Octeon Ethernet: Clean up and convert to NAPI.
From: David Daney <[email protected]>
Date: Wed, 6 Jan 2010 16:57:15 -0800
Quoted 6 lines
Convert the driver to be a reasonably well behaved NAPI citizen. Also clean up memory allocation and tx buffer accounding code. Remove some configuration #defines and other unused code that are not applicable to the in-tree driver.
Signed-off-by David Daney <[email protected]>
Please seperate the cleanups and conversion to NAPI into seperate patches.
Doing both at the same time makes your patch impossible to review.
PATCH 3/3 Staging: Octeon Ethernet: Enable scatter-gather.
In reply to David DaneyOcteon ethernet hardware can handle NETIF_F_SG, so we enable it.
--- drivers/staging/octeon/ethernet-tx.c | 57 +++++++++++++++++++++++++++++---- drivers/staging/octeon/ethernet.c | 7 +++- 2 files changed, 55 insertions(+), 9 deletions(-)
drivers/staging/octeon/ethernet-tx.c +50 -7
@@ -53,6 +53,8 @@#include "cvmx-gmxx-defs.h" +#define CVM_OCT_SKB_CB (skb) ((u64 *)((skb)->cb)) +/* * You can define GET_SKBUFF_QOS() to override how the skbuff output * function determines which output queue is used. The default
@@ -121,6 +123,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)uint64_t old_scratch;uint64_t old_scratch2;int qos; +int i;enum {QUEUE_CORE ,QUEUE_HW ,QUEUE_DROP } queue_type;struct octeon_ethernet *priv =netdev_priv (dev);struct sk_buff *to_free_list;
@@ -171,6 +174,28 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) }/* +* We have space for 6 segment pointers, If there will be more +* than that, we must linearize. +*/ +if (unlikely (skb_shinfo (skb)->nr_frags >5 )) { +if (unlikely (__skb_linearize (skb))) { + queue_type =QUEUE_DROP ; +if (USE_ASYNC_IOBDMA ) { +/* Get the number of skbuffs in use by the hardware */ +CVMX_SYNCIOBDMA ; + skb_to_free =cvmx_scratch_read64 (CVMX_SCR_SCRATCH ); + }else { +/* Get the number of skbuffs in use by the hardware */ + skb_to_free =cvmx_fau_fetch_and_add32 (priv->fau + qos *4 , +MAX_SKB_TO_FREE ); + } + skb_to_free =cvm_oct_adjust_skb_to_free (skb_to_free, priv->fau + qos *4 ); +spin_lock_irqsave (&priv->tx_free_list[qos].lock, flags); + goto skip_xmit; + } + } + +/* * The CN3XXX series of parts has an errata (GMX-401) which * causes the GMX block to hang if a collision occurs towards * the end of a <68 byte packet. As a workaround for this, we
@@ -198,13 +223,6 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) } } -/* Build the PKO buffer pointer */ - hw_buffer.u64 =0 ; - hw_buffer.s.addr =cvmx_ptr_to_phys (skb->data); - hw_buffer.s.pool =0 ; - hw_buffer.s.size = - (unsigned long )skb_end_pointer (skb) - (unsigned long )skb->head; -/* Build the PKO command */ pko_command.u64 =0 ; pko_command.s.n2 =1 ;/* Don't pollute L2 with the outgoing packet */
@@ -215,6 +233,31 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) pko_command.s.dontfree =1 ; pko_command.s.reg0 = priv->fau + qos *4 ; + +/* Build the PKO buffer pointer */ + hw_buffer.u64 =0 ; +if (skb_shinfo (skb)->nr_frags ==0 ) { + hw_buffer.s.addr =XKPHYS_TO_PHYS (skb->data); + hw_buffer.s.pool =0 ; + hw_buffer.s.size = skb->len; + }else { + hw_buffer.s.addr =XKPHYS_TO_PHYS (skb->data); + hw_buffer.s.pool =0 ; + hw_buffer.s.size =skb_headlen (skb); +CVM_OCT_SKB_CB (skb)[0 ] = hw_buffer.u64; +for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++) { +struct skb_frag_struct *fs =skb_shinfo (skb)->frags + i; + hw_buffer.s.addr =XKPHYS_TO_PHYS (page_address (fs->page) + fs->page_offset); + hw_buffer.s.size = fs->size; +CVM_OCT_SKB_CB (skb)[i +1 ] = hw_buffer.u64; + } + hw_buffer.s.addr =XKPHYS_TO_PHYS (CVM_OCT_SKB_CB (skb)); + hw_buffer.s.size =skb_shinfo (skb)->nr_frags +1 ; + pko_command.s.segs =skb_shinfo (skb)->nr_frags +1 ; + pko_command.s.gather =1 ; + goto dont_put_skbuff_in_hw; + } +/* * See if we can put this skb in the FPA pool. Any strange * behavior from the Linux networking stack will most likely
drivers/staging/octeon/ethernet.c +5 -2
@@ -485,8 +485,11 @@ int cvm_oct_common_init(struct net_device *dev) && (always_use_pow || strstr(pow_send_list, dev->name))) priv->queue = -1; -if (priv->queue !=-1 &&USE_HW_TCPUDP_CHECKSUM ) - dev->features |=NETIF_F_IP_CSUM ; +if (priv->queue !=-1 ) { + dev->features |=NETIF_F_SG ; +if (USE_HW_TCPUDP_CHECKSUM ) + dev->features |=NETIF_F_IP_CSUM ; + }/* We do our own locking, Linux doesn't need to */ dev->features |=NETIF_F_LLTX ;
Signature · 1 line
1.6.0.6