Commit 3368c784 authored by David Daney's avatar David Daney Committed by Ralf Baechle

Staging: Octeon Ethernet: Convert to NAPI.

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.
Signed-off-by: default avatarDavid Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
To: gregkh@suse.de
Patchwork: http://patchwork.linux-mips.org/patch/839/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 6888fc87
...@@ -45,10 +45,6 @@ ...@@ -45,10 +45,6 @@
* Controls if the Octeon TCP/UDP checksum engine is used for packet * Controls if the Octeon TCP/UDP checksum engine is used for packet
* output. If this is zero, the kernel will perform the checksum in * output. If this is zero, the kernel will perform the checksum in
* software. * 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_ASYNC_IOBDMA
* Use asynchronous IO access to hardware. This uses Octeon's asynchronous * Use asynchronous IO access to hardware. This uses Octeon's asynchronous
* IOBDMAs to issue IO accesses without stalling. Set this to zero * IOBDMAs to issue IO accesses without stalling. Set this to zero
...@@ -79,15 +75,8 @@ ...@@ -79,15 +75,8 @@
#define REUSE_SKBUFFS_WITHOUT_FREE 1 #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_HW_TCPUDP_CHECKSUM 1
#define USE_MULTICORE_RECEIVE 1
/* Enable Random Early Dropping under load */ /* Enable Random Early Dropping under load */
#define USE_RED 1 #define USE_RED 1
#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0) #define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
...@@ -105,17 +94,10 @@ ...@@ -105,17 +94,10 @@
/* Use this to not have FPA frees control L2 */ /* Use this to not have FPA frees control L2 */
/*#define DONT_WRITEBACK(x) 0 */ /*#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. */ /* Maximum number of SKBs to try to free per xmit packet. */
#define MAX_SKB_TO_FREE 10 #define MAX_SKB_TO_FREE 10
#define MAX_OUT_QUEUE_DEPTH 1000 #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_TCP 6
#define IP_PROTOCOL_UDP 0x11 #define IP_PROTOCOL_UDP 0x11
......
This diff is collapsed.
...@@ -24,10 +24,29 @@ ...@@ -24,10 +24,29 @@
* This file may also be available under a different license from Cavium. * This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information * 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_poll_controller(struct net_device *dev);
void cvm_oct_tasklet_rx(unsigned long unused);
void cvm_oct_rx_initialize(void); void cvm_oct_rx_initialize(void);
void cvm_oct_rx_shutdown(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);
}
}
}
...@@ -104,6 +104,16 @@ MODULE_PARM_DESC(pow_send_list, "\n" ...@@ -104,6 +104,16 @@ MODULE_PARM_DESC(pow_send_list, "\n"
"\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n" "\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
"\tusing the pow_send_group."); "\tusing the pow_send_group.");
int max_rx_cpus = -1;
module_param(max_rx_cpus, int, 0444);
MODULE_PARM_DESC(max_rx_cpus, "\n"
"\t\tThe maximum number of CPUs to use for packet reception.\n"
"\t\tUse -1 to use all available CPUs.");
int rx_napi_weight = 32;
module_param(rx_napi_weight, int, 0444);
MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
/* /*
* The offset from mac_addr_base that should be used for the next port * 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 * that is configured. By convention, if any mgmt ports exist on the
...@@ -148,6 +158,15 @@ static void cvm_do_timer(unsigned long arg) ...@@ -148,6 +158,15 @@ static void cvm_do_timer(unsigned long arg)
mod_timer(&cvm_oct_poll_timer, jiffies + HZ/50); mod_timer(&cvm_oct_poll_timer, jiffies + HZ/50);
} else { } else {
port = 0; port = 0;
/*
* FPA 0 may have been drained, try to refill it if we
* need more than num_packet_buffers / 2, otherwise
* normal receive processing will refill it. If it
* were drained, no packets could be received so
* cvm_oct_napi_poll would never be invoked to do the
* refill.
*/
cvm_oct_rx_refill_pool(num_packet_buffers / 2);
/* /*
* All ports have been polled. Start the next iteration through * All ports have been polled. Start the next iteration through
* the ports in one second. * the ports in one second.
...@@ -161,7 +180,6 @@ static void cvm_do_timer(unsigned long arg) ...@@ -161,7 +180,6 @@ static void cvm_do_timer(unsigned long arg)
*/ */
static __init void cvm_oct_configure_common_hw(void) static __init void cvm_oct_configure_common_hw(void)
{ {
int r;
/* Setup the FPA */ /* Setup the FPA */
cvmx_fpa_enable(); cvmx_fpa_enable();
cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
...@@ -176,17 +194,6 @@ static __init void cvm_oct_configure_common_hw(void) ...@@ -176,17 +194,6 @@ static __init void cvm_oct_configure_common_hw(void)
cvmx_helper_setup_red(num_packet_buffers / 4, cvmx_helper_setup_red(num_packet_buffers / 4,
num_packet_buffers / 8); num_packet_buffers / 8);
/* 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",
cvm_oct_device);
#if defined(CONFIG_SMP) && 0
if (USE_MULTICORE_RECEIVE) {
irq_set_affinity(OCTEON_IRQ_WORKQ0 + pow_receive_group,
cpu_online_mask);
}
#endif
} }
/** /**
...@@ -616,7 +623,6 @@ static int __init cvm_oct_init_module(void) ...@@ -616,7 +623,6 @@ static int __init cvm_oct_init_module(void)
cvm_oct_mac_addr_offset = 0; cvm_oct_mac_addr_offset = 0;
cvm_oct_proc_initialize(); cvm_oct_proc_initialize();
cvm_oct_rx_initialize();
cvm_oct_configure_common_hw(); cvm_oct_configure_common_hw();
cvmx_helper_initialize_packet_io_global(); cvmx_helper_initialize_packet_io_global();
...@@ -781,25 +787,7 @@ static int __init cvm_oct_init_module(void) ...@@ -781,25 +787,7 @@ static int __init cvm_oct_init_module(void)
} }
} }
if (INTERRUPT_LIMIT) { cvm_oct_rx_initialize();
/*
* Set the POW timer rate to give an interrupt at most
* INTERRUPT_LIMIT times per second.
*/
cvmx_write_csr(CVMX_POW_WQ_INT_PC,
octeon_bootinfo->eclock_hz / (INTERRUPT_LIMIT *
16 * 256) << 8);
/*
* Enable POW timer interrupt. It will count when
* there are packets available.
*/
cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group),
0x1ful << 24);
} else {
/* Enable POW interrupt when our port has at least one packet */
cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
}
/* Enable the poll timer for checking RGMII status */ /* Enable the poll timer for checking RGMII status */
init_timer(&cvm_oct_poll_timer); init_timer(&cvm_oct_poll_timer);
......
...@@ -98,4 +98,7 @@ extern int pow_receive_group; ...@@ -98,4 +98,7 @@ extern int pow_receive_group;
extern char pow_send_list[]; extern char pow_send_list[];
extern struct net_device *cvm_oct_device[]; extern struct net_device *cvm_oct_device[];
extern int max_rx_cpus;
extern int rx_napi_weight;
#endif #endif
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