Skip to contentSkip to conversation

Staging: Improvments to Octeon Ethernet driver (second attempt).

PATCH In review David Daney 5 participants 16 messages Jan 7, 2010 – Jan 16, 2010

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover Staging: Improvments to Octeon Ethernet driver (second attempt).

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. At David Miller's suggestion I have factored the changes into many more individual patches than I had in the first version.

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 seven patches.

David Daney (7):
MIPS: Octeon: Fix EIO handling.
Staging: Octeon Ethernet: Remove unused code.
Staging: Octeon Ethernet: Fix memory allocation.
Staging: Octeon Ethernet: Rewrite transmit code.
Staging: Octeon Ethernet: Convert to NAPI.
Staging: Octeon Ethernet: Enable scatter-gather.
Staging: Octeon Ethernet: Use constants from in.h

 arch/mips/cavium-octeon/octeon-irq.c      |   40 +++-
 drivers/staging/octeon/Kconfig            |    1 +
 drivers/staging/octeon/ethernet-defines.h |   31 ---
 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      |  342 
+++++++++++++-------------
 drivers/staging/octeon/ethernet-tx.h      |   27 +--
 drivers/staging/octeon/ethernet.c         |  155 +++++--------
 drivers/staging/octeon/octeon-ethernet.h  |   48 +---
 10 files changed, 537 insertions(+), 598 deletions(-)
#1 lore raw

PATCH 1/7 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
index 6f2acf0..1460d08 100644
@@ -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
#2 lore raw

Re: [PATCH 1/7] MIPS: Octeon: Fix EIO handling.

Hello.

Quoted 10 lines · David Daney

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.

I guess the subject should read "EIO", not "EIO"...

WBR, Sergei

#3 lore raw

Re: [PATCH 1/7] MIPS: Octeon: Fix EIO handling.

Quoted 8 lines · Sergei Shtylyov

Hello.

Quoted 4 lines · David Daney

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.

Quoted 9 lines
Quoted 6 lines

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.

I guess the subject should read "EIO", not "EIO"...

Indeed. The compiler didn't catch that one.

Perhaps Ralf can fix it if he merges it, otherwise I can resubmit with corrected spelling.

David Daney

#4 lore raw

Re: [PATCH 1/7] MIPS: Octeon: Fix EIO handling.

Quoted 16 lines · David Daney
Quoted 15 lines · Sergei Shtylyov

Hello.

Quoted 10 lines · David Daney

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.

Quoted 7 lines
Quoted 2 lines

I guess the subject should read "EIO", not "EIO"...

Indeed. The compiler didn't catch that one.

Perhaps Ralf can fix it if he merges it, otherwise I can resubmit with corrected spelling.

I can change it when merging, don't worry about it.

thanks,

greg k-h

#5 lore raw

Re: [PATCH 1/7] MIPS: Octeon: Fix EIO handling.

Quoted 14 lines · Greg KH
Quoted 14 lines
Quoted 13 lines
Quoted 10 lines

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.

I guess the subject should read "EIO", not "EIO"...

Quoted 6 lines
Quoted 4 lines

Indeed. The compiler didn't catch that one.

Perhaps Ralf can fix it if he merges it, otherwise I can resubmit with corrected spelling.

I can change it when merging, don't worry about it.

This is a driver specific to a specific MIPS platform so I think this series should be merged via the MIPS tree and assuming Greg is ok with that I have merged this into my tree.

Ralf

#6 lore raw

Re: [PATCH 1/7] MIPS: Octeon: Fix EIO handling.

Quoted 18 lines · Ralf Baechle
Quoted 16 lines · Greg KH
Quoted 16 lines
Quoted 4 lines
Quoted 4 lines

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.

Quoted 9 lines
Quoted 6 lines

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.

I guess the subject should read "EIO", not "EIO"...

Indeed. The compiler didn't catch that one.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Perhaps Ralf can fix it if he merges it, otherwise I can resubmit with corrected spelling.

I can change it when merging, don't worry about it.

This is a driver specific to a specific MIPS platform so I think this series should be merged via the MIPS tree and assuming Greg is ok with that I have merged this into my tree.

No objection from me at all, merge away :)

thanks,

greg k-h

#7 lore raw

PATCH 2/7 Staging: Octeon Ethernet: Remove unused code.

In reply to David Daney

Remove unused code, reindent, and join some spilt strings.

---
 drivers/staging/octeon/ethernet-defines.h |   10 ---
 drivers/staging/octeon/ethernet-mem.c     |   81 +++++++-----------------
 drivers/staging/octeon/ethernet-rx.c      |   77 +++++++---------------
 drivers/staging/octeon/ethernet-tx.c      |   99 -----------------------------
 drivers/staging/octeon/ethernet.c         |   31 ++-------
 drivers/staging/octeon/octeon-ethernet.h  |   41 ------------
 6 files changed, 55 insertions(+), 284 deletions(-)
drivers/staging/octeon/ethernet-defines.h +0 -10
index f13131b..6b8065f 100644
@@ -41,9 +41,6 @@
  *      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
@@ -75,19 +72,12 @@
 #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
drivers/staging/octeon/ethernet-mem.c +24 -57

101 lines not on this page · raw message

drivers/staging/octeon/ethernet-rx.c +25 -52

150 lines not on this page · raw message

drivers/staging/octeon/ethernet-tx.c +0 -99

111 lines not on this page · raw message

drivers/staging/octeon/ethernet.c +6 -25
index 4cfd4b1..4e05426 100644
@@ -104,14 +104,6 @@ MODULE_PARM_DESC(pow_send_list, "\n"
 	"\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
 	"\tusing the pow_send_group.");
 
-static int disable_core_queueing = 1;
-module_param(disable_core_queueing, int, 0444);
-MODULE_PARM_DESC(disable_core_queueing, "\n"
-	"\tWhen set the networking core's tx_queue_len is set to zero.  This\n"
-	"\tallows packets to be sent without lock contention in the packet\n"
-	"\tscheduler resulting in some cases in improved throughput.\n");
-
-
 /*
  * The offset from mac_addr_base that should be used for the next port
  * that is configured.  By convention, if any mgmt ports exist on the
@@ -205,10 +197,6 @@ static __init void cvm_oct_configure_common_hw(void)
 		cvmx_helper_setup_red(num_packet_buffers / 4,
 				      num_packet_buffers / 8);
 
-	/* Enable the MII interface */
-	if (!octeon_is_simulation())
-		cvmx_write_csr(CVMX_SMIX_EN(0), 1);
-
 	/* Register an IRQ hander for to receive POW interrupts */
 	r = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group,
 			cvm_oct_do_interrupt, IRQF_SHARED, "Ethernet",
@@ -689,7 +677,6 @@ static int __init cvm_oct_init_module(void)
 		if (dev) {
 			/* Initialize the device private structure. */
 			struct octeon_ethernet *priv = netdev_priv(dev);
-			memset(priv, 0, sizeof(struct octeon_ethernet));
 
 			dev->netdev_ops = &cvm_oct_pow_netdev_ops;
 			priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
@@ -700,19 +687,16 @@ static int __init cvm_oct_init_module(void)
 				skb_queue_head_init(&priv->tx_free_list[qos]);
 
 			if (register_netdev(dev) < 0) {
-				pr_err("Failed to register ethernet "
-					 "device for POW\n");
+				pr_err("Failed to register ethernet device for POW\n");
 				kfree(dev);
 			} else {
 				cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = dev;
-				pr_info("%s: POW send group %d, receive "
-					"group %d\n",
-				     dev->name, pow_send_group,
-				     pow_receive_group);
+				pr_info("%s: POW send group %d, receive group %d\n",
+					dev->name, pow_send_group,
+					pow_receive_group);
 			}
 		} else {
-			pr_err("Failed to allocate ethernet device "
-				 "for POW\n");
+			pr_err("Failed to allocate ethernet device for POW\n");
 		}
 	}
 
@@ -730,12 +714,9 @@ static int __init cvm_oct_init_module(void)
 			struct net_device *dev =
 			    alloc_etherdev(sizeof(struct octeon_ethernet));
 			if (!dev) {
-				pr_err("Failed to allocate ethernet device "
-					 "for port %d\n", port);
+				pr_err("Failed to allocate ethernet device for port %d\n", port);
 				continue;
 			}
-			if (disable_core_queueing)
-				dev->tx_queue_len = 0;
 
 			/* Initialize the device private structure. */
 			priv = netdev_priv(dev);
drivers/staging/octeon/octeon-ethernet.h +0 -41

47 lines not on this page · raw message

Signature · 1 line
1.6.0.6
#8 lore raw

PATCH 3/7 Staging: Octeon Ethernet: Fix memory allocation.

In reply to David Daney

kmalloc already returns aligned blocks. No need to try to realign them.

There are no guarantees about the alignment of SKB data, so we need to handle worst case alignment.

Since right shifts over subtraction have no distributive property, we need to fix the back pointer calculation.

---
 drivers/staging/octeon/ethernet-mem.c |   14 ++++++--------
 drivers/staging/octeon/ethernet-tx.c  |    6 +++---
 2 files changed, 9 insertions(+), 11 deletions(-)
drivers/staging/octeon/ethernet-mem.c +6 -8
index 7090521..7f1372f 100644
@@ -4,7 +4,7 @@
  * Contact: [email protected]
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -45,7 +45,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
 	int freed = elements;
 	while (freed) {
 
-		struct sk_buff *skb = dev_alloc_skb(size + 128);
+		struct sk_buff *skb = dev_alloc_skb(size + 256);
 		if (unlikely(skb == NULL)) {
 			pr_warning
 			    ("Failed to allocate skb for hardware pool %d\n",
@@ -53,7 +53,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
 			break;
 		}
 
-		skb_reserve(skb, 128 - (((unsigned long)skb->data) & 0x7f));
+		skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
 		*(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
 		cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128));
 		freed--;
@@ -106,14 +106,12 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
 	int freed = elements;
 
 	while (freed) {
-		/* We need to force alignment to 128 bytes here */
-		memory = kmalloc(size + 127, GFP_ATOMIC);
+		memory = kmalloc(size, GFP_ATOMIC);
 		if (unlikely(memory == NULL)) {
 			pr_warning("Unable to allocate %u bytes for FPA pool %d\n",
 				   elements * size, pool);
 			break;
 		}
-		memory = (char *)(((unsigned long)memory + 127) & -128);
 		cvmx_fpa_free(memory, pool, 0);
 		freed--;
 	}
@@ -149,7 +147,7 @@ static void cvm_oct_free_hw_memory(int pool, int size, int elements)
 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
 {
 	int freed;
-	if (USE_SKBUFFS_IN_HW)
+	if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
 		freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
 	else
 		freed = cvm_oct_fill_hw_memory(pool, size, elements);
@@ -158,7 +156,7 @@ int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
 
 void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
 {
-	if (USE_SKBUFFS_IN_HW)
+	if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
 		cvm_oct_free_hw_skbuff(pool, size, elements);
 	else
 		cvm_oct_free_hw_memory(pool, size, elements);
drivers/staging/octeon/ethernet-tx.c +3 -3
index a3594bb..e5695d9 100644
@@ -4,7 +4,7 @@
  * Contact: [email protected]
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2007 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -186,7 +186,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 	 * shown a 25% increase in performance under some loads.
 	 */
 #if REUSE_SKBUFFS_WITHOUT_FREE
-	fpa_head = skb->head + 128 - ((unsigned long)skb->head & 0x7f);
+	fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f);
 	if (unlikely(skb->data < fpa_head)) {
 		/*
 		 * printk("TX buffer beginning can't meet FPA
@@ -247,7 +247,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
 	pko_command.s.reg0 = 0;
 	pko_command.s.dontfree = 0;
 
-	hw_buffer.s.back = (skb->data - fpa_head) >> 7;
+	hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7);
 	*(struct sk_buff **)(fpa_head - sizeof(void *)) = skb;
 
 	/*
Signature · 1 line
1.6.0.6
#9 lore raw

PATCH 4/7 Staging: Octeon Ethernet: Rewrite transmit code.

In reply to David Daney

Stop the queue if too many packets are queued. Restart it from a high resolution timer.

Rearrange and simplify locking and SKB freeing code

---
 drivers/staging/octeon/Kconfig           |    1 +
 drivers/staging/octeon/ethernet-tx.c     |  172 +++++++++++++++++++-----------
 drivers/staging/octeon/ethernet-tx.h     |   27 +-----
 drivers/staging/octeon/ethernet.c        |   69 ++++++-------
 drivers/staging/octeon/octeon-ethernet.h |    4 +
 5 files changed, 150 insertions(+), 123 deletions(-)
drivers/staging/octeon/Kconfig +1 -0
index 638ad6b..579b8f1 100644
@@ -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-tx.c +112 -60

227 lines not on this page · raw message

drivers/staging/octeon/ethernet-tx.h +2 -25
index c0bebf7..b628d8c 100644
@@ -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 +31 -38

99 lines not on this page · raw message

drivers/staging/octeon/octeon-ethernet.h +4 -0
index 208da27..203c6a9 100644
@@ -31,6 +31,8 @@
 #ifndef OCTEON_ETHERNET_H
 #define OCTEON_ETHERNET_H
 
+#include <linux/hrtimer.h>
+
 /**
  * This is the definition of the Ethernet driver's private
  * driver state stored in netdev_priv(dev).
@@ -57,6 +59,8 @@ struct octeon_ethernet {
 	uint64_t link_info;
 	/* Called periodically to check link status */
 	void (*poll) (struct net_device *dev);
+	struct hrtimer		tx_restart_timer;
+	ktime_t			tx_restart_interval;
 };
 
 /**
Signature · 1 line
1.6.0.6
#10 lore raw

PATCH 5/7 Staging: Octeon Ethernet: Convert to NAPI.

In reply to David Daney

Convert the driver to be a reasonably well behaved NAPI citizen.

There is one NAPI instance per CPU shared between all input ports. As receive backlog increases, NAPI is scheduled on additional CPUs.

Receive buffer refill code factored out so it can also be called from the periodic timer. This is needed to recover from temporary buffer starvation conditions.

---
 drivers/staging/octeon/ethernet-defines.h |   18 --
 drivers/staging/octeon/ethernet-rx.c      |  300 ++++++++++++++++++-----------
 drivers/staging/octeon/ethernet-rx.h      |   25 ++-
 drivers/staging/octeon/ethernet.c         |   52 ++---
 drivers/staging/octeon/octeon-ethernet.h  |    3 +
 5 files changed, 235 insertions(+), 163 deletions(-)
drivers/staging/octeon/ethernet-defines.h +0 -18
index 6b8065f..9c4910e 100644
@@ -45,10 +45,6 @@
  *      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
@@ -79,15 +75,8 @@
 #define REUSE_SKBUFFS_WITHOUT_FREE  1
 #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)
@@ -105,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-rx.c +190 -110

404 lines not on this page · raw message

drivers/staging/octeon/ethernet-rx.h +22 -3
index a9b72b8..a0743b8 100644
@@ -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.c +20 -32

88 lines not on this page · raw message

drivers/staging/octeon/octeon-ethernet.h +3 -0
index 203c6a9..40b6956 100644
@@ -98,4 +98,7 @@ extern int pow_receive_group;
 extern char pow_send_list[];
 extern struct net_device *cvm_oct_device[];
 
+extern int max_rx_cpus;
+extern int rx_napi_weight;
+
 #endif
Signature · 1 line
1.6.0.6
#11 lore raw

PATCH 6/7 Staging: Octeon Ethernet: Enable scatter-gather.

In reply to David Daney

Octeon ethernet hardware can handle NETIF_F_SG, so we enable it.

A gather list of up to six fragments will fit in the SKB's CB structure, so no extra memory is required. If a SKB has more than six fragments, we must linearize 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
index 05b58f8..bc67e41 100644
@@ -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((u64)skb->data);
+		hw_buffer.s.pool = 0;
+		hw_buffer.s.size = skb->len;
+	} else {
+		hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)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((u64)(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((u64)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
index 9f5b741..9d63202 100644
@@ -484,8 +484,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
#12 lore raw

PATCH 7/7 Staging: Octeon Ethernet: Use constants from in.h

In reply to David Daney
---
 drivers/staging/octeon/ethernet-defines.h |    3 ---
 drivers/staging/octeon/ethernet-tx.c      |    8 ++++----
 2 files changed, 4 insertions(+), 7 deletions(-)
drivers/staging/octeon/ethernet-defines.h +0 -3
index 9c4910e..00a8561 100644
@@ -98,9 +98,6 @@
 #define MAX_SKB_TO_FREE 10
 #define MAX_OUT_QUEUE_DEPTH 1000
 
-#define IP_PROTOCOL_TCP             6
-#define IP_PROTOCOL_UDP             0x11
-
 #define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END - sizeof(uint32_t))
 #define TOTAL_NUMBER_OF_PORTS       (CVMX_PIP_NUM_INPUT_PORTS+1)
 
drivers/staging/octeon/ethernet-tx.c +4 -4
index bc67e41..62258bd 100644
@@ -359,8 +359,8 @@ dont_put_skbuff_in_hw:
 	if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol == htons(ETH_P_IP)) &&
 	    (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) &&
 	    ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))
-	    && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
-		|| (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) {
+	    && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
+		|| (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
 		/* Use hardware checksum calc */
 		pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
 	}
@@ -550,8 +550,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
 		work->word2.s.dec_ipcomp = 0;	/* FIXME */
 #endif
 		work->word2.s.tcp_or_udp =
-		    (ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
-		    || (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP);
+		    (ip_hdr(skb)->protocol == IPPROTO_TCP)
+		    || (ip_hdr(skb)->protocol == IPPROTO_UDP);
 #if 0
 		/* FIXME */
 		work->word2.s.dec_ipsec = 0;
Signature · 1 line
1.6.0.6
#13 lore raw

Re: [PATCH 7/7] Staging: Octeon Ethernet: Use constants from in.h

Quoted 29 lines · On Thu, 7 Jan 2010 11:05:06 -0800 David Daney <[email protected]>…
---
 drivers/staging/octeon/ethernet-defines.h |    3 ---
 drivers/staging/octeon/ethernet-tx.c      |    8 ++++----
 2 files changed, 4 insertions(+), 7 deletions(-)
(quoted diff) +0 -0

b/drivers/staging/octeon/ethernet-defines.h index 9c4910e..00a8561 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h

drivers/staging/octeon/ethernet-defines.h +0 -3
@@ -98,9 +98,6 @@
 #define MAX_SKB_TO_FREE 10
 #define MAX_OUT_QUEUE_DEPTH 1000
 
-#define IP_PROTOCOL_TCP             6
-#define IP_PROTOCOL_UDP             0x11
-
 #define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END -

sizeof(uint32_t)) #define TOTAL_NUMBER_OF_PORTS
(CVMX_PIP_NUM_INPUT_PORTS+1)

(quoted diff) +0 -0

b/drivers/staging/octeon/ethernet-tx.c index bc67e41..62258bd 100644

drivers/staging/octeon/ethernet-tx.c +0 -0
@@ -359,8 +359,8 @@ dont_put_skbuff_in_hw:
 	if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol ==

htons(ETH_P_IP)) && (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))

drivers/staging/octeon/ethernet-tx.c dont_put_skbuff_in_hw: · line 366

Quoted 7 lines
drivers/staging/octeon/ethernet-tx.c +2 -2
-	    && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
-		|| (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) {
+	    && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
+		|| (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
 		/* Use hardware checksum calc */
 		pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
 	}

Why isn't skb->ip_summed checked here instead? It seems like the csum calculation needs to be skipped by the stack if this is actually going to help performance.

And does this end up re-writing a bad checksum on a routed packet, back to being a good checksum?

#14 lore raw

Re: [PATCH 7/7] Staging: Octeon Ethernet: Use constants from in.h

Quoted 32 lines · Andrew May
Quoted 29 lines · On Thu, 7 Jan 2010 11:05:06 -0800 David Daney <[email protected]>…
---
 drivers/staging/octeon/ethernet-defines.h |    3 ---
 drivers/staging/octeon/ethernet-tx.c      |    8 ++++----
 2 files changed, 4 insertions(+), 7 deletions(-)
(quoted diff) +0 -0

b/drivers/staging/octeon/ethernet-defines.h index 9c4910e..00a8561 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h

drivers/staging/octeon/ethernet-defines.h +0 -3
@@ -98,9 +98,6 @@
 #define MAX_SKB_TO_FREE 10
 #define MAX_OUT_QUEUE_DEPTH 1000
 
-#define IP_PROTOCOL_TCP             6
-#define IP_PROTOCOL_UDP             0x11
-
 #define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END -

sizeof(uint32_t)) #define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS+1) diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index bc67e41..62258bd 100644

drivers/staging/octeon/ethernet-tx.c +0 -0
@@ -359,8 +359,8 @@ dont_put_skbuff_in_hw:
 	if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol ==

htons(ETH_P_IP)) && (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))

drivers/staging/octeon/ethernet-tx.c +0 -1
-	    && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
Quoted 8 lines

drivers/staging/octeon/ethernet-tx.c dont_put_skbuff_in_hw: · line 366

Quoted 6 lines
drivers/staging/octeon/ethernet-tx.c +2 -1
-		|| (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) {
+	    && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
+		|| (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
 		/* Use hardware checksum calc */
 		pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
 	}

Why isn't skb->ip_summed checked here instead?

That may indeed be the correct thing to do, but the main point of this particular patch is to remove local definitions that mirror definitions provided by core include files.

So in order to not let 'the perfect be the enemy of the good' I think this patch should be applied.

Quoted 3 lines

It seems like the csum
calculation needs to be skipped by the stack if this is actually going to help performance.

FWIW: We do set NETIF_F_IP_CSUM. We are certainly open to suggestions as to how the code could be improved, so I may look at this again in the future. Patches from others are also welcome.

Quoted 3 lines

And does this end up re-writing a bad checksum on a routed packet, back to being a good checksum?

Indeed it does. Actually it writes a good checksum on *all* IP packets without regard to their source.

David Daney

#15 lore raw

Re: [PATCH 7/7] Staging: Octeon Ethernet: Use constants from in.h

Quoted 43 lines · On Fri, 15 Jan 2010 11:41:40 -0800 David Daney <[email protected]>…
Quoted 33 lines · Andrew May
Quoted 30 lines · On Thu, 7 Jan 2010 11:05:06 -0800 David Daney <[email protected]>…
---
 drivers/staging/octeon/ethernet-defines.h |    3 ---
 drivers/staging/octeon/ethernet-tx.c      |    8 ++++----
 2 files changed, 4 insertions(+), 7 deletions(-)
(quoted diff) +0 -0

b/drivers/staging/octeon/ethernet-defines.h index 9c4910e..00a8561 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h

drivers/staging/octeon/ethernet-defines.h +0 -3
@@ -98,9 +98,6 @@
 #define MAX_SKB_TO_FREE 10
 #define MAX_OUT_QUEUE_DEPTH 1000
 
-#define IP_PROTOCOL_TCP             6
-#define IP_PROTOCOL_UDP             0x11
-
 #define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END -

sizeof(uint32_t)) #define TOTAL_NUMBER_OF_PORTS
(CVMX_PIP_NUM_INPUT_PORTS+1)

(quoted diff) +0 -0

b/drivers/staging/octeon/ethernet-tx.c index bc67e41..62258bd 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c

(quoted diff) +0 -0
@@ -359,8 +359,8 @@ dont_put_skbuff_in_hw:
 	if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol ==

htons(ETH_P_IP)) && (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))

drivers/staging/octeon/ethernet-tx.c +0 -1
-	    && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP)
Quoted 8 lines

drivers/staging/octeon/ethernet-tx.c dont_put_skbuff_in_hw: · line 366

Quoted 6 lines
drivers/staging/octeon/ethernet-tx.c +2 -1
-		|| (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) {
+	    && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
+		|| (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
 		/* Use hardware checksum calc */
 		pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
 	}

Why isn't skb->ip_summed checked here instead?

Quoted 6 lines

That may indeed be the correct thing to do, but the main point of this particular patch is to remove local definitions that mirror definitions provided by core include files.

So in order to not let 'the perfect be the enemy of the good' I think this patch should be applied.

I am not against the patch being applied. I also don't think I have any sort of influence to get it rejected. But in seeing the code it is just something that jumps out at me, and I wanted to make sure I wasn't missing something else.

Quoted 2 lines

Indeed it does. Actually it writes a good checksum on *all* IP packets without regard to their source.

That seems like a very bad thing. Maybe the entire section of code should be removed along with the defines for now.

I don't actually have one of these chips at home to play with and test.