* Re: [PATCH] r8169: Reduce looping in the interrupt handler.
From: David Dillow @ 2009-08-28 1:29 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Francois Romieu, Michael Riepe, Michael Buesch, Rui Santos,
Michael B??ker, linux-kernel, netdev
In-Reply-To: <m1d46gka9e.fsf@fess.ebiederm.org>
On Thu, 2009-08-27 at 18:17 -0700, Eric W. Biederman wrote:
> Francois Romieu <romieu@fr.zoreil.com> writes:
>
> > Eric W. Biederman <ebiederm@xmission.com> :
> > [...]
> >> Sounds good.
> >
> > Gah, I was not able to test it with a decent packet load. Patch below against
> > the current tree:
>
> This kills the loop which was my concern.
>
> I will double check it works on my configuration.
> Then we have the question of does it work for those folks who have cards
> where the msi appeared to get lost.
>
> David any chance you can test this patch?
It'll be this weekend, but I can see cases where it can lock my chip up
-- they should be rare, but then I thought your case would be extremely
rare...
I think we'll need to go to a full separation between MSI and
level-triggered interrupt handlers, or at the very least mask everything
and handle it all in NAPI. That seems more viable now that I know
Francois is not terribly worried about diverging from the vendor driver
there.
^ permalink raw reply
* Re: [PATCH] r8169: Reduce looping in the interrupt handler.
From: Eric W. Biederman @ 2009-08-28 1:17 UTC (permalink / raw)
To: Francois Romieu
Cc: David Dillow, Michael Riepe, Michael Buesch, Rui Santos,
Michael B??ker, linux-kernel, netdev
In-Reply-To: <20090827232024.GA30119@electric-eye.fr.zoreil.com>
Francois Romieu <romieu@fr.zoreil.com> writes:
> Eric W. Biederman <ebiederm@xmission.com> :
> [...]
>> Sounds good.
>
> Gah, I was not able to test it with a decent packet load. Patch below against
> the current tree:
This kills the loop which was my concern.
I will double check it works on my configuration.
Then we have the question of does it work for those folks who have cards
where the msi appeared to get lost.
David any chance you can test this patch?
Eric
^ permalink raw reply
* [PATCH 03/14] pktgen: mark read-only/mostly variables
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-ro.patch --]
[-- Type: text/plain, Size: 1134 bytes --]
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:30:11.932524803 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:12.299687034 -0700
@@ -414,7 +414,7 @@ static __u64 getCurUs(void)
/* old include end */
-static char version[] __initdata = VERSION;
+static const char version[] __initconst = VERSION;
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
@@ -432,10 +432,10 @@ static unsigned int scan_ip6(const char
static unsigned int fmt_ip6(char *s, const char ip[16]);
/* Module parameters, defaults. */
-static int pg_count_d = 1000; /* 1000 pkts by default */
-static int pg_delay_d;
-static int pg_clone_skb_d;
-static int debug;
+static int pg_count_d __read_mostly = 1000;
+static int pg_delay_d __read_mostly;
+static int pg_clone_skb_d __read_mostly;
+static int debug __read_mostly;
static DEFINE_MUTEX(pktgen_thread_lock);
static LIST_HEAD(pktgen_threads);
--
^ permalink raw reply
* [PATCH 13/14] pktgen: cleanup checkpatch warnings
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-checkpatch.patch --]
[-- Type: text/plain, Size: 23511 bytes --]
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/core/pktgen.c 2009-08-27 16:29:53.826372401 -0700
+++ b/net/core/pktgen.c 2009-08-27 16:30:05.614687981 -0700
@@ -163,13 +163,14 @@
#include <asm/byteorder.h>
#include <linux/rcupdate.h>
#include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/timex.h>
+#include <linux/uaccess.h>
#include <asm/dma.h>
-#include <asm/uaccess.h>
#include <asm/div64.h> /* do_div */
-#include <asm/timex.h>
-#define VERSION "pktgen v2.70: Packet Generator for packet performance testing.\n"
+#define VERSION \
+ "pktgen v2.70: Packet Generator for packet performance testing.\n"
#define IP_NAME_SZ 32
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
@@ -207,7 +208,7 @@
#define PKTGEN_MAGIC 0xbe9be955
#define PG_PROC_DIR "pktgen"
#define PGCTRL "pgctrl"
-static struct proc_dir_entry *pg_proc_dir = NULL;
+static struct proc_dir_entry *pg_proc_dir;
#define MAX_CFLOWS 65536
@@ -232,9 +233,9 @@ struct pktgen_dev {
*/
struct proc_dir_entry *entry; /* proc file */
struct pktgen_thread *pg_thread;/* the owner */
- struct list_head list; /* Used for chaining in the thread's run-queue */
+ struct list_head list; /* chaining in the thread's run-queue */
- int running; /* if this changes to false, the test will stop */
+ int running; /* if false, the test will stop */
/* If min != max, then we will either do a linear iteration, or
* we will do a random selection from within the range.
@@ -252,15 +253,16 @@ struct pktgen_dev {
__u64 count; /* Default No packets to send */
__u64 sofar; /* How many pkts we've sent so far */
__u64 tx_bytes; /* How many bytes we've transmitted */
- __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
+ __u64 errors; /* Errors when trying to transmit,
+ pkts will be re-sent */
/* runtime counters relating to clone_skb */
__u64 allocated_skbs;
__u32 clone_count;
int last_ok; /* Was last skb sent?
- * Or a failed transmit of some sort? This will keep
- * sequence numbers in order, for example.
+ * Or a failed transmit of some sort?
+ * This will keep sequence numbers in order
*/
ktime_t next_tx;
ktime_t started_at;
@@ -269,11 +271,14 @@ struct pktgen_dev {
__u32 seq_num;
- int clone_skb; /* Use multiple SKBs during packet gen. If this number
- * is greater than 1, then that many copies of the same
- * packet will be sent before a new packet is allocated.
- * For instance, if you want to send 1024 identical packets
- * before creating a new packet, set clone_skb to 1024.
+ int clone_skb; /*
+ * Use multiple SKBs during packet gen.
+ * If this number is greater than 1, then
+ * that many copies of the same packet will be
+ * sent before a new packet is allocated.
+ * If you want to send 1024 identical packets
+ * before creating a new packet,
+ * set clone_skb to 1024.
*/
char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */
@@ -305,8 +310,10 @@ struct pktgen_dev {
__u16 udp_dst_max; /* exclusive, dest UDP port */
/* DSCP + ECN */
- __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */
- __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */
+ __u8 tos; /* six MSB of (former) IPv4 TOS
+ are for dscp codepoint */
+ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6
+ (see RFC 3260, sec. 4) */
/* MPLS */
unsigned nr_labels; /* Depth of stack, 0 = no MPLS */
@@ -347,15 +354,17 @@ struct pktgen_dev {
*/
__u16 pad; /* pad out the hh struct to an even 16 bytes */
- struct sk_buff *skb; /* skb we are to transmit next, mainly used for when we
+ struct sk_buff *skb; /* skb we are to transmit next, used for when we
* are transmitting the same one multiple times
*/
- struct net_device *odev; /* The out-going device. Note that the device should
- * have it's pg_info pointer pointing back to this
- * device. This will be set when the user specifies
- * the out-going device name (not when the inject is
- * started as it used to do.)
- */
+ struct net_device *odev; /* The out-going device.
+ * Note that the device should have it's
+ * pg_info pointer pointing back to this
+ * device.
+ * Set when the user specifies the out-going
+ * device name (not when the inject is
+ * started as it used to do.)
+ */
struct flow_state *flows;
unsigned cflows; /* Concurrent flows (config) */
unsigned lflow; /* Flow length (config) */
@@ -380,13 +389,14 @@ struct pktgen_hdr {
};
struct pktgen_thread {
- spinlock_t if_lock;
+ spinlock_t if_lock; /* for list of devices */
struct list_head if_list; /* All device here */
struct list_head th_list;
struct task_struct *tsk;
char result[512];
- /* Field for thread to receive "posted" events terminate, stop ifs etc. */
+ /* Field for thread to receive "posted" events terminate,
+ stop ifs etc. */
u32 control;
int cpu;
@@ -453,8 +463,8 @@ static int pgctrl_show(struct seq_file *
return 0;
}
-static ssize_t pgctrl_write(struct file *file, const char __user * buf,
- size_t count, loff_t * ppos)
+static ssize_t pgctrl_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
int err = 0;
char data[128];
@@ -545,11 +555,14 @@ static int pktgen_if_show(struct seq_fil
" daddr: %s min_daddr: %s max_daddr: %s\n", b1,
b2, b3);
- } else
+ } else {
+ seq_printf(seq,
+ " dst_min: %s dst_max: %s\n",
+ pkt_dev->dst_min, pkt_dev->dst_max);
seq_printf(seq,
- " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n",
- pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min,
- pkt_dev->src_max);
+ " src_min: %s src_max: %s\n",
+ pkt_dev->src_min, pkt_dev->src_max);
+ }
seq_puts(seq, " src_mac: ");
@@ -561,7 +574,8 @@ static int pktgen_if_show(struct seq_fil
seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
seq_printf(seq,
- " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n",
+ " udp_src_min: %d udp_src_max: %d"
+ " udp_dst_min: %d udp_dst_max: %d\n",
pkt_dev->udp_src_min, pkt_dev->udp_src_max,
pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
@@ -577,23 +591,21 @@ static int pktgen_if_show(struct seq_fil
i == pkt_dev->nr_labels-1 ? "\n" : ", ");
}
- if (pkt_dev->vlan_id != 0xffff) {
+ if (pkt_dev->vlan_id != 0xffff)
seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n",
- pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi);
- }
+ pkt_dev->vlan_id, pkt_dev->vlan_p,
+ pkt_dev->vlan_cfi);
- if (pkt_dev->svlan_id != 0xffff) {
+ if (pkt_dev->svlan_id != 0xffff)
seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n",
- pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi);
- }
+ pkt_dev->svlan_id, pkt_dev->svlan_p,
+ pkt_dev->svlan_cfi);
- if (pkt_dev->tos) {
+ if (pkt_dev->tos)
seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos);
- }
- if (pkt_dev->traffic_class) {
+ if (pkt_dev->traffic_class)
seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class);
- }
seq_printf(seq, " Flags: ");
@@ -696,7 +708,8 @@ static int pktgen_if_show(struct seq_fil
}
-static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
+static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
+ __u32 *num)
{
int i = 0;
*num = 0;
@@ -846,9 +859,9 @@ static ssize_t pktgen_if_write(struct fi
/* Read variable name */
len = strn_len(&user_buffer[i], sizeof(name) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
memset(name, 0, sizeof(name));
if (copy_from_user(name, &user_buffer[i], len))
return -EFAULT;
@@ -872,9 +885,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "min_pkt_size")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value < 14 + 20 + 8)
value = 14 + 20 + 8;
@@ -889,9 +902,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "max_pkt_size")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value < 14 + 20 + 8)
value = 14 + 20 + 8;
@@ -908,9 +921,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "pkt_size")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value < 14 + 20 + 8)
value = 14 + 20 + 8;
@@ -925,9 +938,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "debug")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
debug = value;
sprintf(pg_result, "OK: debug=%u", debug);
@@ -936,9 +949,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "frags")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->nfrags = value;
sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
@@ -946,9 +959,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "delay")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value == 0x7FFFFFFF)
pkt_dev->delay = ULLONG_MAX;
@@ -961,9 +974,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "udp_src_min")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value != pkt_dev->udp_src_min) {
pkt_dev->udp_src_min = value;
@@ -974,9 +987,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "udp_dst_min")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value != pkt_dev->udp_dst_min) {
pkt_dev->udp_dst_min = value;
@@ -987,9 +1000,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "udp_src_max")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value != pkt_dev->udp_src_max) {
pkt_dev->udp_src_max = value;
@@ -1000,9 +1013,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "udp_dst_max")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value != pkt_dev->udp_dst_max) {
pkt_dev->udp_dst_max = value;
@@ -1013,9 +1026,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "clone_skb")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->clone_skb = value;
@@ -1024,9 +1037,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "count")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->count = value;
sprintf(pg_result, "OK: count=%llu",
@@ -1035,9 +1048,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "src_mac_count")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (pkt_dev->src_mac_count != value) {
pkt_dev->src_mac_count = value;
@@ -1049,9 +1062,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "dst_mac_count")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (pkt_dev->dst_mac_count != value) {
pkt_dev->dst_mac_count = value;
@@ -1065,9 +1078,9 @@ static ssize_t pktgen_if_write(struct fi
char f[32];
memset(f, 0, 32);
len = strn_len(&user_buffer[i], sizeof(f) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
if (copy_from_user(f, &user_buffer[i], len))
return -EFAULT;
i += len;
@@ -1166,9 +1179,8 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
if (copy_from_user(buf, &user_buffer[i], len))
return -EFAULT;
@@ -1188,9 +1200,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "dst_max")) {
len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
if (copy_from_user(buf, &user_buffer[i], len))
return -EFAULT;
@@ -1301,9 +1313,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "src_min")) {
len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
if (copy_from_user(buf, &user_buffer[i], len))
return -EFAULT;
buf[len] = 0;
@@ -1322,9 +1334,9 @@ static ssize_t pktgen_if_write(struct fi
}
if (!strcmp(name, "src_max")) {
len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
if (copy_from_user(buf, &user_buffer[i], len))
return -EFAULT;
buf[len] = 0;
@@ -1348,9 +1360,9 @@ static ssize_t pktgen_if_write(struct fi
memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
memset(valstr, 0, sizeof(valstr));
if (copy_from_user(valstr, &user_buffer[i], len))
return -EFAULT;
@@ -1390,9 +1402,9 @@ static ssize_t pktgen_if_write(struct fi
memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
memset(valstr, 0, sizeof(valstr));
if (copy_from_user(valstr, &user_buffer[i], len))
return -EFAULT;
@@ -1433,9 +1445,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "flows")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value > MAX_CFLOWS)
value = MAX_CFLOWS;
@@ -1447,9 +1459,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "flowlen")) {
len = num_arg(&user_buffer[i], 10, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->lflow = value;
sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
@@ -1458,9 +1470,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "queue_map_min")) {
len = num_arg(&user_buffer[i], 5, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->queue_map_min = value;
sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
@@ -1469,9 +1481,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "queue_map_max")) {
len = num_arg(&user_buffer[i], 5, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
pkt_dev->queue_map_max = value;
sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
@@ -1503,9 +1515,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "vlan_id")) {
len = num_arg(&user_buffer[i], 4, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (value <= 4095) {
pkt_dev->vlan_id = value; /* turn on VLAN */
@@ -1530,9 +1542,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "vlan_p")) {
len = num_arg(&user_buffer[i], 1, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
pkt_dev->vlan_p = value;
@@ -1545,9 +1557,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "vlan_cfi")) {
len = num_arg(&user_buffer[i], 1, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
pkt_dev->vlan_cfi = value;
@@ -1560,9 +1572,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "svlan_id")) {
len = num_arg(&user_buffer[i], 4, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
pkt_dev->svlan_id = value; /* turn on SVLAN */
@@ -1587,9 +1599,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "svlan_p")) {
len = num_arg(&user_buffer[i], 1, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
pkt_dev->svlan_p = value;
@@ -1602,9 +1614,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "svlan_cfi")) {
len = num_arg(&user_buffer[i], 1, &value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
pkt_dev->svlan_cfi = value;
@@ -1618,9 +1630,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "tos")) {
__u32 tmp_value = 0;
len = hex32_arg(&user_buffer[i], 2, &tmp_value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (len == 2) {
pkt_dev->tos = tmp_value;
@@ -1634,9 +1646,9 @@ static ssize_t pktgen_if_write(struct fi
if (!strcmp(name, "traffic_class")) {
__u32 tmp_value = 0;
len = hex32_arg(&user_buffer[i], 2, &tmp_value);
- if (len < 0) {
+ if (len < 0)
return len;
- }
+
i += len;
if (len == 2) {
pkt_dev->traffic_class = tmp_value;
@@ -1906,13 +1918,14 @@ static int pktgen_device_event(struct no
return NOTIFY_DONE;
}
-static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, const char *ifname)
+static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
+ const char *ifname)
{
char b[IFNAMSIZ+5];
int i = 0;
- for(i=0; ifname[i] != '@'; i++) {
- if(i == IFNAMSIZ)
+ for (i = 0; ifname[i] != '@'; i++) {
+ if (i == IFNAMSIZ)
break;
b[i] = ifname[i];
@@ -1979,7 +1992,7 @@ static void pktgen_setup_inject(struct p
printk(KERN_WARNING "pktgen: WARNING: Requested "
"queue_map_min (zero-based) (%d) exceeds valid range "
"[0 - %d] for (%d) queues on %s, resetting\n",
- pkt_dev->queue_map_min, (ntxq ?: 1)- 1, ntxq,
+ pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
pkt_dev->odev->name);
pkt_dev->queue_map_min = ntxq - 1;
}
@@ -1987,7 +2000,7 @@ static void pktgen_setup_inject(struct p
printk(KERN_WARNING "pktgen: WARNING: Requested "
"queue_map_max (zero-based) (%d) exceeds valid range "
"[0 - %d] for (%d) queues on %s, resetting\n",
- pkt_dev->queue_map_max, (ntxq ?: 1)- 1, ntxq,
+ pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
pkt_dev->odev->name);
pkt_dev->queue_map_max = ntxq - 1;
}
@@ -2028,7 +2041,8 @@ static void pktgen_setup_inject(struct p
*/
rcu_read_lock();
- if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
+ idev = __in6_dev_get(pkt_dev->odev);
+ if (idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
@@ -2181,7 +2195,7 @@ static void get_ipsec_sa(struct pktgen_d
if (x) {
pkt_dev->flows[flow].x = x;
set_pkt_overhead(pkt_dev);
- pkt_dev->pkt_overhead+=x->props.header_len;
+ pkt_dev->pkt_overhead += x->props.header_len;
}
}
@@ -2320,18 +2334,18 @@ static void mod_cur_headers(struct pktge
if (!(pkt_dev->flags & F_IPV6)) {
- if ((imn = ntohl(pkt_dev->saddr_min)) < (imx =
- ntohl(pkt_dev->
- saddr_max))) {
+ imn = ntohl(pkt_dev->saddr_min);
+ imx = ntohl(pkt_dev->saddr_max);
+ if (imn < imx) {
__u32 t;
if (pkt_dev->flags & F_IPSRC_RND)
t = random32() % (imx - imn) + imn;
else {
t = ntohl(pkt_dev->cur_saddr);
t++;
- if (t > imx) {
+ if (t > imx)
t = imn;
- }
+
}
pkt_dev->cur_saddr = htonl(t);
}
@@ -2442,7 +2456,7 @@ static int pktgen_output_ipsec(struct sk
if (err)
goto error;
- x->curlft.bytes +=skb->len;
+ x->curlft.bytes += skb->len;
x->curlft.packets++;
error:
spin_unlock(&x->lock);
@@ -2474,11 +2488,11 @@ static int process_ipsec(struct pktgen_d
int ret;
__u8 *eth;
nhead = x->props.header_len - skb_headroom(skb);
- if (nhead >0) {
+ if (nhead > 0) {
ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
if (ret < 0) {
printk(KERN_ERR "Error expanding "
- "ipsec packet %d\n",ret);
+ "ipsec packet %d\n", ret);
goto err;
}
}
@@ -2488,13 +2502,13 @@ static int process_ipsec(struct pktgen_d
ret = pktgen_output_ipsec(skb, pkt_dev);
if (ret) {
printk(KERN_ERR "Error creating ipsec "
- "packet %d\n",ret);
+ "packet %d\n", ret);
goto err;
}
/* restore ll */
eth = (__u8 *) skb_push(skb, ETH_HLEN);
memcpy(eth, pkt_dev->hh, 12);
- *(u16 *) & eth[12] = protocol;
+ *(u16 *) ð[12] = protocol;
}
}
return 1;
@@ -2507,9 +2521,9 @@ err:
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
unsigned i;
- for (i = 0; i < pkt_dev->nr_labels; i++) {
+ for (i = 0; i < pkt_dev->nr_labels; i++)
*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
- }
+
mpls--;
*mpls |= MPLS_STACK_BOTTOM;
}
@@ -2676,8 +2690,9 @@ static struct sk_buff *fill_packet_ipv4(
}
}
- /* Stamp the time, and sequence number, convert them to network byte order */
-
+ /* Stamp the time, and sequence number,
+ * convert them to network byte order
+ */
if (pgh) {
struct timeval timestamp;
@@ -2931,7 +2946,7 @@ static struct sk_buff *fill_packet_ipv6(
udph = udp_hdr(skb);
memcpy(eth, pkt_dev->hh, 12);
- *(__be16 *) & eth[12] = protocol;
+ *(__be16 *) ð[12] = protocol;
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 -
@@ -3025,8 +3040,10 @@ static struct sk_buff *fill_packet_ipv6(
}
}
- /* Stamp the time, and sequence number, convert them to network byte order */
- /* should we update cloned packets too ? */
+ /* Stamp the time, and sequence number,
+ * convert them to network byte order
+ * should we update cloned packets too ?
+ */
if (pgh) {
struct timeval timestamp;
@@ -3174,7 +3191,8 @@ static void pktgen_run_all_threads(void)
mutex_unlock(&pktgen_thread_lock);
- schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */
+ /* Propagate thread->control */
+ schedule_timeout_interruptible(msecs_to_jiffies(125));
pktgen_wait_all_threads_run();
}
@@ -3192,7 +3210,8 @@ static void pktgen_reset_all_threads(voi
mutex_unlock(&pktgen_thread_lock);
- schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */
+ /* Propagate thread->control */
+ schedule_timeout_interruptible(msecs_to_jiffies(125));
pktgen_wait_all_threads_run();
}
@@ -3485,7 +3504,8 @@ static int pktgen_thread_worker(void *ar
init_waitqueue_head(&t->queue);
complete(&t->start_done);
- pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current));
+ pr_debug("pktgen: starting pktgen/%d: pid=%d\n",
+ cpu, task_pid_nr(current));
set_current_state(TASK_INTERRUPTIBLE);
--
^ permalink raw reply
* [PATCH 04/14] pktgen: stop_device cleanup
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-stop-dev.patch --]
[-- Type: text/plain, Size: 1863 bytes --]
All the callers were freeing skb after stopping device.
Remove unneeded forward decl.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:35:23.949541813 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:11.370662155 -0700
@@ -424,7 +424,7 @@ static int pktgen_device_event(struct no
static void pktgen_run_all_threads(void);
static void pktgen_reset_all_threads(void);
static void pktgen_stop_all_threads_ifs(void);
-static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
+
static void pktgen_stop(struct pktgen_thread *t);
static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
@@ -3221,7 +3221,6 @@ static void show_results(struct pktgen_d
}
/* Set stopped-at timer, remove from running list, do counters & statistics */
-
static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
{
int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
@@ -3232,6 +3231,8 @@ static int pktgen_stop_device(struct pkt
return -EINVAL;
}
+ kfree_skb(pkt_dev->skb);
+ pkt_dev->skb = NULL;
pkt_dev->stopped_at = getCurUs();
pkt_dev->running = 0;
@@ -3268,9 +3269,6 @@ static void pktgen_stop(struct pktgen_th
list_for_each_entry(pkt_dev, &t->if_list, list) {
pktgen_stop_device(pkt_dev);
- kfree_skb(pkt_dev->skb);
-
- pkt_dev->skb = NULL;
}
if_unlock(t);
@@ -3382,8 +3380,6 @@ static void pktgen_xmit(struct pktgen_de
if (!netif_running(odev)) {
pktgen_stop_device(pkt_dev);
- kfree_skb(pkt_dev->skb);
- pkt_dev->skb = NULL;
goto out;
}
if (need_resched())
@@ -3486,8 +3482,6 @@ static void pktgen_xmit(struct pktgen_de
/* Done with this */
pktgen_stop_device(pkt_dev);
- kfree_skb(pkt_dev->skb);
- pkt_dev->skb = NULL;
}
out:;
}
--
^ permalink raw reply
* [PATCH 10/14] pktgen: convert to use ktime_t
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-ktime.patch --]
[-- Type: text/plain, Size: 10921 bytes --]
The kernel ktime_t is a nice generic infrastructure for mananging
high resolution times, as is done in pktgen.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 185 ++++++++++++++++++++++++------------------------------
1 file changed, 85 insertions(+), 100 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 12:04:15.087541783 -0700
+++ b/net/core/pktgen.c 2009-08-27 12:43:35.843546115 -0700
@@ -246,16 +246,14 @@ struct pktgen_dev {
int max_pkt_size; /* = ETH_ZLEN; */
int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
int nfrags;
- __u32 delay_us; /* Default delay */
- __u32 delay_ns;
+ u64 delay; /* nano-seconds */
+
__u64 count; /* Default No packets to send */
__u64 sofar; /* How many pkts we've sent so far */
__u64 tx_bytes; /* How many bytes we've transmitted */
__u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
/* runtime counters relating to clone_skb */
- __u64 next_tx_us; /* timestamp of when to tx next */
- __u32 next_tx_ns;
__u64 allocated_skbs;
__u32 clone_count;
@@ -263,9 +261,11 @@ struct pktgen_dev {
* Or a failed transmit of some sort? This will keep
* sequence numbers in order, for example.
*/
- __u64 started_at; /* micro-seconds */
- __u64 stopped_at; /* micro-seconds */
- __u64 idle_acc; /* micro-seconds */
+ ktime_t next_tx;
+ ktime_t started_at;
+ ktime_t stopped_at;
+ u64 idle_acc; /* nano-seconds */
+
__u32 seq_num;
int clone_skb; /* Use multiple SKBs during packet gen. If this number
@@ -397,23 +397,20 @@ struct pktgen_thread {
#define REMOVE 1
#define FIND 0
-/** Convert to micro-seconds */
-static inline __u64 tv_to_us(const struct timeval *tv)
+static inline ktime_t ktime_now(void)
{
- __u64 us = tv->tv_usec;
- us += (__u64) tv->tv_sec * (__u64) 1000000;
- return us;
+ struct timespec ts;
+ ktime_get_ts(&ts);
+
+ return timespec_to_ktime(ts);
}
-static __u64 getCurUs(void)
+/* This works even if 32 bit because of careful byte order choice */
+static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
{
- struct timeval tv;
- do_gettimeofday(&tv);
- return tv_to_us(&tv);
+ return cmp1.tv64 < cmp2.tv64;
}
-/* old include end */
-
static const char version[] __initconst = VERSION;
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
@@ -510,9 +507,8 @@ static const struct file_operations pktg
static int pktgen_if_show(struct seq_file *seq, void *v)
{
const struct pktgen_dev *pkt_dev = seq->private;
- __u64 sa;
- __u64 stopped;
- __u64 now = getCurUs();
+ ktime_t stopped;
+ u64 idle;
seq_printf(seq,
"Params: count %llu min_pkt_size: %u max_pkt_size: %u\n",
@@ -520,9 +516,8 @@ static int pktgen_if_show(struct seq_fil
pkt_dev->max_pkt_size);
seq_printf(seq,
- " frags: %d delay: %u clone_skb: %d ifname: %s\n",
- pkt_dev->nfrags,
- 1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
+ " frags: %d delay: %llu clone_skb: %d ifname: %s\n",
+ pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
pkt_dev->clone_skb, pkt_dev->odev->name);
seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows,
@@ -654,17 +649,21 @@ static int pktgen_if_show(struct seq_fil
seq_puts(seq, "\n");
- sa = pkt_dev->started_at;
- stopped = pkt_dev->stopped_at;
- if (pkt_dev->running)
- stopped = now; /* not really stopped, more like last-running-at */
+ /* not really stopped, more like last-running-at */
+ stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at;
+ idle = pkt_dev->idle_acc;
+ do_div(idle, NSEC_PER_USEC);
seq_printf(seq,
- "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n",
+ "Current:\n pkts-sofar: %llu errors: %llu\n",
(unsigned long long)pkt_dev->sofar,
- (unsigned long long)pkt_dev->errors, (unsigned long long)sa,
- (unsigned long long)stopped,
- (unsigned long long)pkt_dev->idle_acc);
+ (unsigned long long)pkt_dev->errors);
+
+ seq_printf(seq,
+ " started: %lluus stopped: %lluus idle: %lluus\n",
+ (unsigned long long) ktime_to_us(pkt_dev->started_at),
+ (unsigned long long) ktime_to_us(stopped),
+ (unsigned long long) idle);
seq_printf(seq,
" seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n",
@@ -950,15 +949,13 @@ static ssize_t pktgen_if_write(struct fi
return len;
}
i += len;
- if (value == 0x7FFFFFFF) {
- pkt_dev->delay_us = 0x7FFFFFFF;
- pkt_dev->delay_ns = 0;
- } else {
- pkt_dev->delay_us = value / 1000;
- pkt_dev->delay_ns = value % 1000;
- }
- sprintf(pg_result, "OK: delay=%u",
- 1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
+ if (value == 0x7FFFFFFF)
+ pkt_dev->delay = ULLONG_MAX;
+ else
+ pkt_dev->delay = (u64)value * NSEC_PER_USEC;
+
+ sprintf(pg_result, "OK: delay=%llu",
+ (unsigned long long) pkt_dev->delay);
return count;
}
if (!strcmp(name, "udp_src_min")) {
@@ -2089,27 +2086,33 @@ static void pktgen_setup_inject(struct p
pkt_dev->nflows = 0;
}
-static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
+static inline s64 delta_ns(ktime_t a, ktime_t b)
+{
+ return ktime_to_ns(ktime_sub(a, b));
+}
+
+static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
{
- __u64 start;
- __u64 now;
+ ktime_t start, now;
+ s64 dt;
- start = now = getCurUs();
- while (now < spin_until_us) {
+ start = now = ktime_now();
+
+ while ((dt = delta_ns(spin_until, now)) > 0) {
/* TODO: optimize sleeping behavior */
- if (spin_until_us - now > jiffies_to_usecs(1) + 1)
+ if (dt > TICK_NSEC)
schedule_timeout_interruptible(1);
- else if (spin_until_us - now > 100) {
+ else if (dt > 100*NSEC_PER_USEC) {
if (!pkt_dev->running)
return;
if (need_resched())
schedule();
}
- now = getCurUs();
+ now = ktime_now();
}
- pkt_dev->idle_acc += now - start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start));
}
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
@@ -3070,9 +3073,9 @@ static void pktgen_run(struct pktgen_thr
pktgen_clear_counters(pkt_dev);
pkt_dev->running = 1; /* Cranke yeself! */
pkt_dev->skb = NULL;
- pkt_dev->started_at = getCurUs();
- pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */
- pkt_dev->next_tx_ns = 0;
+ pkt_dev->started_at =
+ pkt_dev->next_tx = ktime_now();
+
set_pkt_overhead(pkt_dev);
strcpy(pkt_dev->result, "Starting");
@@ -3188,28 +3191,21 @@ static void pktgen_reset_all_threads(voi
static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
{
- __u64 total_us, bps, mbps, pps, idle;
+ __u64 bps, mbps, pps;
char *p = pkt_dev->result;
-
- total_us = pkt_dev->stopped_at - pkt_dev->started_at;
-
- idle = pkt_dev->idle_acc;
-
- p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
- (unsigned long long)total_us,
- (unsigned long long)(total_us - idle),
- (unsigned long long)idle,
+ ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
+ pkt_dev->started_at);
+ ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
+
+ p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
+ (unsigned long long)ktime_to_us(elapsed),
+ (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
+ (unsigned long long)ktime_to_us(idle),
(unsigned long long)pkt_dev->sofar,
pkt_dev->cur_pkt_size, nr_frags);
- pps = pkt_dev->sofar * USEC_PER_SEC;
-
- while ((total_us >> 32) != 0) {
- pps >>= 1;
- total_us >>= 1;
- }
-
- do_div(pps, total_us);
+ pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
+ ktime_to_ns(elapsed));
bps = pps * 8 * pkt_dev->cur_pkt_size;
@@ -3235,7 +3231,7 @@ static int pktgen_stop_device(struct pkt
kfree_skb(pkt_dev->skb);
pkt_dev->skb = NULL;
- pkt_dev->stopped_at = getCurUs();
+ pkt_dev->stopped_at = ktime_now();
pkt_dev->running = 0;
show_results(pkt_dev, nr_frags);
@@ -3254,7 +3250,7 @@ static struct pktgen_dev *next_to_run(st
continue;
if (best == NULL)
best = pkt_dev;
- else if (pkt_dev->next_tx_us < best->next_tx_us)
+ else if (ktime_lt(pkt_dev->next_tx, best->next_tx))
best = pkt_dev;
}
if_unlock(t);
@@ -3343,16 +3339,17 @@ static void pktgen_rem_thread(struct pkt
static void idle(struct pktgen_dev *pkt_dev)
{
- u64 idle_start = getCurUs();
+ ktime_t idle_start = ktime_now();
if (need_resched())
schedule();
else
cpu_relax();
- pkt_dev->idle_acc += getCurUs() - idle_start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
}
+
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
struct net_device *odev = pkt_dev->odev;
@@ -3362,19 +3359,15 @@ static void pktgen_xmit(struct pktgen_de
u16 queue_map;
int ret;
- if (pkt_dev->delay_us || pkt_dev->delay_ns) {
- u64 now;
-
- now = getCurUs();
- if (now < pkt_dev->next_tx_us)
- spin(pkt_dev, pkt_dev->next_tx_us);
+ if (pkt_dev->delay) {
+ if (ktime_lt(ktime_now(), pkt_dev->next_tx))
+ spin(pkt_dev, pkt_dev->next_tx);
/* This is max DELAY, this has special meaning of
* "never transmit"
*/
- if (pkt_dev->delay_us == 0x7FFFFFFF) {
- pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us;
- pkt_dev->next_tx_ns = pkt_dev->delay_ns;
+ if (pkt_dev->delay == ULLONG_MAX) {
+ pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX);
return;
}
}
@@ -3450,32 +3443,24 @@ static void pktgen_xmit(struct pktgen_de
pkt_dev->last_ok = 0;
}
- if (pkt_dev->delay_us || pkt_dev->delay_ns) {
- pkt_dev->next_tx_us = getCurUs();
- pkt_dev->next_tx_ns = 0;
-
- pkt_dev->next_tx_us += pkt_dev->delay_us;
- pkt_dev->next_tx_ns += pkt_dev->delay_ns;
-
- if (pkt_dev->next_tx_ns > 1000) {
- pkt_dev->next_tx_us++;
- pkt_dev->next_tx_ns -= 1000;
- }
- }
+ if (pkt_dev->delay)
+ pkt_dev->next_tx = ktime_add_ns(ktime_now(),
+ pkt_dev->delay);
}
__netif_tx_unlock_bh(txq);
/* If pkt_dev->count is zero, then run forever */
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
if (atomic_read(&(pkt_dev->skb->users)) != 1) {
- u64 idle_start = getCurUs();
+ ktime_t idle_start = ktime_now();
while (atomic_read(&(pkt_dev->skb->users)) != 1) {
if (signal_pending(current)) {
break;
}
schedule();
}
- pkt_dev->idle_acc += getCurUs() - idle_start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(),
+ idle_start));
}
/* Done with this */
@@ -3634,8 +3619,7 @@ static int pktgen_add_device(struct pktg
pkt_dev->max_pkt_size = ETH_ZLEN;
pkt_dev->nfrags = 0;
pkt_dev->clone_skb = pg_clone_skb_d;
- pkt_dev->delay_us = pg_delay_d / 1000;
- pkt_dev->delay_ns = pg_delay_d % 1000;
+ pkt_dev->delay = pg_delay_d;
pkt_dev->count = pg_count_d;
pkt_dev->sofar = 0;
pkt_dev->udp_src_min = 9; /* sink port */
--
^ permalink raw reply
* [PATCH 05/14] pktgen: xmit logic reorganization
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-reorg1.patch --]
[-- Type: text/plain, Size: 3236 bytes --]
Do some reorganization of transmit logic path:
* move transmit queue full idle to separate routine
* add a cpu_relax()
* eliminate some of the uneeded goto's
* if queue is still stopped, go back to main thread loop.
* don't give up transmitting if quantum is exhausted (be greedy)
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 55 +++++++++++++++++++++++-------------------------------
1 file changed, 24 insertions(+), 31 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:35:23.959966151 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:10.525500312 -0700
@@ -3339,6 +3339,18 @@ static void pktgen_rem_thread(struct pkt
mutex_unlock(&pktgen_thread_lock);
}
+static void idle(struct pktgen_dev *pkt_dev)
+{
+ u64 idle_start = getCurUs();
+
+ if (need_resched())
+ schedule();
+ else
+ cpu_relax();
+
+ pkt_dev->idle_acc += getCurUs() - idle_start;
+}
+
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
struct net_device *odev = pkt_dev->odev;
@@ -3361,7 +3373,7 @@ static void pktgen_xmit(struct pktgen_de
if (pkt_dev->delay_us == 0x7FFFFFFF) {
pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us;
pkt_dev->next_tx_ns = pkt_dev->delay_ns;
- goto out;
+ return;
}
}
@@ -3373,26 +3385,14 @@ static void pktgen_xmit(struct pktgen_de
}
txq = netdev_get_tx_queue(odev, queue_map);
- if (netif_tx_queue_stopped(txq) ||
- netif_tx_queue_frozen(txq) ||
- need_resched()) {
- u64 idle_start = getCurUs();
-
- if (!netif_running(odev)) {
+ /* Did we saturate the queue already? */
+ if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)) {
+ /* If device is down, then all queues are permnantly frozen */
+ if (netif_running(odev))
+ idle(pkt_dev);
+ else
pktgen_stop_device(pkt_dev);
- goto out;
- }
- if (need_resched())
- schedule();
-
- pkt_dev->idle_acc += getCurUs() - idle_start;
-
- if (netif_tx_queue_stopped(txq) ||
- netif_tx_queue_frozen(txq)) {
- pkt_dev->next_tx_us = getCurUs(); /* TODO */
- pkt_dev->next_tx_ns = 0;
- goto out; /* Try the next interface */
- }
+ return;
}
if (pkt_dev->last_ok || !pkt_dev->skb) {
@@ -3407,7 +3407,7 @@ static void pktgen_xmit(struct pktgen_de
"allocate skb in fill_packet.\n");
schedule();
pkt_dev->clone_count--; /* back out increment, OOM */
- goto out;
+ return;
}
pkt_dev->allocated_skbs++;
pkt_dev->clone_count = 0; /* reset counter */
@@ -3419,9 +3419,9 @@ static void pktgen_xmit(struct pktgen_de
txq = netdev_get_tx_queue(odev, queue_map);
__netif_tx_lock_bh(txq);
- if (!netif_tx_queue_stopped(txq) &&
- !netif_tx_queue_frozen(txq)) {
-
+ if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)))
+ pkt_dev->last_ok = 0;
+ else {
atomic_inc(&(pkt_dev->skb->users));
retry_now:
ret = (*xmit)(pkt_dev->skb, odev);
@@ -3458,13 +3458,6 @@ static void pktgen_xmit(struct pktgen_de
pkt_dev->next_tx_ns -= 1000;
}
}
-
- else { /* Retry it next time */
- pkt_dev->last_ok = 0;
- pkt_dev->next_tx_us = getCurUs(); /* TODO */
- pkt_dev->next_tx_ns = 0;
- }
-
__netif_tx_unlock_bh(txq);
/* If pkt_dev->count is zero, then run forever */
--
^ permalink raw reply
* [PATCH 08/14] pktgen: reorganize transmit loop
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-reorg2.patch --]
[-- Type: text/plain, Size: 1448 bytes --]
Handle standard (and non-standard) return values in a switch.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:45:40.162808571 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:56:46.356874524 -0700
@@ -3424,27 +3424,29 @@ static void pktgen_xmit(struct pktgen_de
pkt_dev->last_ok = 0;
else {
atomic_inc(&(pkt_dev->skb->users));
- retry_now:
+
+ retry_now:
ret = (*xmit)(pkt_dev->skb, odev);
- if (likely(ret == NETDEV_TX_OK)) {
+ switch (ret) {
+ case NETDEV_TX_OK:
txq_trans_update(txq);
pkt_dev->last_ok = 1;
pkt_dev->sofar++;
pkt_dev->seq_num++;
pkt_dev->tx_bytes += pkt_dev->cur_pkt_size;
-
- } else if (ret == NETDEV_TX_LOCKED
- && (odev->features & NETIF_F_LLTX)) {
+ break;
+ case NETDEV_TX_LOCKED:
cpu_relax();
goto retry_now;
- } else { /* Retry it next time */
-
- atomic_dec(&(pkt_dev->skb->users));
-
- if (debug && net_ratelimit())
- printk(KERN_INFO "pktgen: Hard xmit error\n");
-
+ default: /* Drivers are not supposed to return other values! */
+ if (net_ratelimit())
+ pr_info("pktgen: %s xmit error: %d\n",
+ odev->name, ret);
pkt_dev->errors++;
+ /* fallthru */
+ case NETDEV_TX_BUSY:
+ /* Retry it next time */
+ atomic_dec(&(pkt_dev->skb->users));
pkt_dev->last_ok = 0;
}
--
^ permalink raw reply
* [PATCH 09/14] pktgen: avoid calling gettimeofday
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-delay2.patch --]
[-- Type: text/plain, Size: 1155 bytes --]
If not using delay then no need to update next_tx after
each packet sent. This allows pktgen to send faster especially
on systems with slower clock sources.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:45:41.488749725 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:56:42.101504858 -0700
@@ -3450,15 +3450,17 @@ static void pktgen_xmit(struct pktgen_de
pkt_dev->last_ok = 0;
}
- pkt_dev->next_tx_us = getCurUs();
- pkt_dev->next_tx_ns = 0;
-
- pkt_dev->next_tx_us += pkt_dev->delay_us;
- pkt_dev->next_tx_ns += pkt_dev->delay_ns;
-
- if (pkt_dev->next_tx_ns > 1000) {
- pkt_dev->next_tx_us++;
- pkt_dev->next_tx_ns -= 1000;
+ if (pkt_dev->delay_us || pkt_dev->delay_ns) {
+ pkt_dev->next_tx_us = getCurUs();
+ pkt_dev->next_tx_ns = 0;
+
+ pkt_dev->next_tx_us += pkt_dev->delay_us;
+ pkt_dev->next_tx_ns += pkt_dev->delay_ns;
+
+ if (pkt_dev->next_tx_ns > 1000) {
+ pkt_dev->next_tx_us++;
+ pkt_dev->next_tx_ns -= 1000;
+ }
}
}
__netif_tx_unlock_bh(txq);
--
^ permalink raw reply
* [PATCH 07/14] pktgen: use netdev_alloc_skb
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-netdev-alloc.patch --]
[-- Type: text/plain, Size: 1240 bytes --]
netdev_alloc_skb is NUMA node aware.
Also, don't exhaust atomic emergency pool. Don't want pktgen
to cause OOM behaviour.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:45:39.080959255 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:08.683814034 -0700
@@ -2539,8 +2539,9 @@ static struct sk_buff *fill_packet_ipv4(
mod_cur_headers(pkt_dev);
datalen = (odev->hard_header_len + 16) & ~0xf;
- skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
- pkt_dev->pkt_overhead, GFP_ATOMIC);
+ skb = __netdev_alloc_skb(odev,
+ pkt_dev->cur_pkt_size + 64
+ + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
@@ -2878,8 +2879,9 @@ static struct sk_buff *fill_packet_ipv6(
queue_map = pkt_dev->cur_queue_map;
mod_cur_headers(pkt_dev);
- skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
- pkt_dev->pkt_overhead, GFP_ATOMIC);
+ skb = __netdev_alloc_skb(odev,
+ pkt_dev->cur_pkt_size + 64
+ + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
--
^ permalink raw reply
* [PATCH 02/14] pktgen: change inlining
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-deinline.patch --]
[-- Type: text/plain, Size: 2372 bytes --]
Don't force inlining where not needed. Gcc does better job
of deciding to inline local functions.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:30:10.108520235 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:13.510686707 -0700
@@ -2438,7 +2438,7 @@ error:
return err;
}
-static inline void free_SAs(struct pktgen_dev *pkt_dev)
+static void free_SAs(struct pktgen_dev *pkt_dev)
{
if (pkt_dev->cflows) {
/* let go of the SAs if we have them */
@@ -2453,7 +2453,7 @@ static inline void free_SAs(struct pktge
}
}
-static inline int process_ipsec(struct pktgen_dev *pkt_dev,
+static int process_ipsec(struct pktgen_dev *pkt_dev,
struct sk_buff *skb, __be16 protocol)
{
if (pkt_dev->flags & F_IPSEC_ON) {
@@ -3029,8 +3029,8 @@ static struct sk_buff *fill_packet_ipv6(
return skb;
}
-static inline struct sk_buff *fill_packet(struct net_device *odev,
- struct pktgen_dev *pkt_dev)
+static struct sk_buff *fill_packet(struct net_device *odev,
+ struct pktgen_dev *pkt_dev)
{
if (pkt_dev->flags & F_IPV6)
return fill_packet_ipv6(odev, pkt_dev);
@@ -3341,13 +3341,12 @@ static void pktgen_rem_thread(struct pkt
mutex_unlock(&pktgen_thread_lock);
}
-static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
+static void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
struct net_device *odev = pkt_dev->odev;
int (*xmit)(struct sk_buff *, struct net_device *)
= odev->netdev_ops->ndo_start_xmit;
struct netdev_queue *txq;
- __u64 idle_start = 0;
u16 queue_map;
int ret;
@@ -3379,7 +3378,7 @@ static __inline__ void pktgen_xmit(struc
if (netif_tx_queue_stopped(txq) ||
netif_tx_queue_frozen(txq) ||
need_resched()) {
- idle_start = getCurUs();
+ u64 idle_start = getCurUs();
if (!netif_running(odev)) {
pktgen_stop_device(pkt_dev);
@@ -3475,7 +3474,7 @@ static __inline__ void pktgen_xmit(struc
/* If pkt_dev->count is zero, then run forever */
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
if (atomic_read(&(pkt_dev->skb->users)) != 1) {
- idle_start = getCurUs();
+ u64 idle_start = getCurUs();
while (atomic_read(&(pkt_dev->skb->users)) != 1) {
if (signal_pending(current)) {
break;
--
^ permalink raw reply
* [PATCH 00/14] pktgen update for net-next (2.6.32)
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
The biggest change is switching to monotonic clock (ktime) and
high resolution timers for the interpacket delay.
--
^ permalink raw reply
* [PATCH 11/14] pktgen: spin using hrtimer
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-hrtimer-spin.patch --]
[-- Type: text/plain, Size: 2972 bytes --]
This changes how the pktgen thread spins/waits between
packets if delay is configured. It uses a high res timer to
wait for time to arrive.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
kernel/hrtimer.c | 1 +
net/core/pktgen.c | 49 ++++++++++++++++++++++++++++---------------------
2 files changed, 29 insertions(+), 21 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 16:00:52.538250235 -0700
+++ b/net/core/pktgen.c 2009-08-27 16:28:17.520270294 -0700
@@ -131,6 +131,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/capability.h>
+#include <linux/hrtimer.h>
#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/timer.h>
@@ -2086,33 +2087,40 @@ static void pktgen_setup_inject(struct p
pkt_dev->nflows = 0;
}
-static inline s64 delta_ns(ktime_t a, ktime_t b)
-{
- return ktime_to_ns(ktime_sub(a, b));
-}
static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
{
- ktime_t start, now;
- s64 dt;
+ ktime_t start;
+ s32 remaining;
+ struct hrtimer_sleeper t;
- start = now = ktime_now();
+ hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ hrtimer_set_expires(&t.timer, spin_until);
- while ((dt = delta_ns(spin_until, now)) > 0) {
- /* TODO: optimize sleeping behavior */
- if (dt > TICK_NSEC)
- schedule_timeout_interruptible(1);
- else if (dt > 100*NSEC_PER_USEC) {
- if (!pkt_dev->running)
- return;
- if (need_resched())
+ remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer));
+ if (remaining <= 0)
+ return;
+
+ start = ktime_now();
+ if (remaining < 100)
+ udelay(remaining); /* really small just spin */
+ else {
+ /* see do_nanosleep */
+ hrtimer_init_sleeper(&t, current);
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+ hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
+ if (!hrtimer_active(&t.timer))
+ t.task = NULL;
+
+ if (likely(t.task))
schedule();
- }
- now = ktime_now();
+ hrtimer_cancel(&t.timer);
+ } while (t.task && pkt_dev->running && !signal_pending(current));
+ __set_current_state(TASK_RUNNING);
}
-
- pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start));
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), start));
}
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
@@ -3360,8 +3368,7 @@ static void pktgen_xmit(struct pktgen_de
int ret;
if (pkt_dev->delay) {
- if (ktime_lt(ktime_now(), pkt_dev->next_tx))
- spin(pkt_dev, pkt_dev->next_tx);
+ spin(pkt_dev, pkt_dev->next_tx);
/* This is max DELAY, this has special meaning of
* "never transmit"
--- a/kernel/hrtimer.c 2009-08-27 16:00:52.547269763 -0700
+++ b/kernel/hrtimer.c 2009-08-27 16:02:04.543287103 -0700
@@ -1477,6 +1477,7 @@ void hrtimer_init_sleeper(struct hrtimer
sl->timer.function = hrtimer_wakeup;
sl->task = task;
}
+EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
{
--
^ permalink raw reply
* [PATCH 06/14] pktgen: cleanup clone count test
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-clone-count.patch --]
[-- Type: text/plain, Size: 1690 bytes --]
The if statement to test for "should a new packet be used"
can be simplified.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:35:26.831941925 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:09.804814960 -0700
@@ -3395,23 +3395,22 @@ static void pktgen_xmit(struct pktgen_de
return;
}
- if (pkt_dev->last_ok || !pkt_dev->skb) {
- if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
- || (!pkt_dev->skb)) {
- /* build a new pkt */
- kfree_skb(pkt_dev->skb);
-
- pkt_dev->skb = fill_packet(odev, pkt_dev);
- if (pkt_dev->skb == NULL) {
- printk(KERN_ERR "pktgen: ERROR: couldn't "
- "allocate skb in fill_packet.\n");
- schedule();
- pkt_dev->clone_count--; /* back out increment, OOM */
- return;
- }
- pkt_dev->allocated_skbs++;
- pkt_dev->clone_count = 0; /* reset counter */
+ if (!pkt_dev->skb || (pkt_dev->last_ok &&
+ ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
+ /* build a new pkt */
+ kfree_skb(pkt_dev->skb);
+
+ pkt_dev->skb = fill_packet(odev, pkt_dev);
+ if (pkt_dev->skb == NULL) {
+ printk(KERN_ERR "pktgen: ERROR: couldn't "
+ "allocate skb in fill_packet.\n");
+ schedule();
+ pkt_dev->clone_count--; /* back out increment, OOM */
+ return;
}
+
+ pkt_dev->allocated_skbs++;
+ pkt_dev->clone_count = 0; /* reset counter */
}
/* fill_packet() might have changed the queue */
@@ -3476,7 +3475,6 @@ static void pktgen_xmit(struct pktgen_de
/* Done with this */
pktgen_stop_device(pkt_dev);
}
-out:;
}
/*
--
^ permalink raw reply
* [PATCH 14/14] pktgen: increase version
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-version.patch --]
[-- Type: text/plain, Size: 1929 bytes --]
Increase module version, and cleanup module info.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/core/pktgen.c 2009-08-27 16:30:05.614687981 -0700
+++ b/net/core/pktgen.c 2009-08-27 16:34:18.584537961 -0700
@@ -169,9 +169,7 @@
#include <asm/dma.h>
#include <asm/div64.h> /* do_div */
-#define VERSION \
- "pktgen v2.70: Packet Generator for packet performance testing.\n"
-
+#define VERSION "2.72"
#define IP_NAME_SZ 32
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
#define MPLS_STACK_BOTTOM htonl(0x00000100)
@@ -422,7 +420,8 @@ static inline int ktime_lt(const ktime_t
return cmp1.tv64 < cmp2.tv64;
}
-static const char version[] __initconst = VERSION;
+static const char version[] =
+ "pktgen " VERSION ": Packet Generator for packet performance testing.\n";
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
@@ -459,7 +458,7 @@ static struct notifier_block pktgen_noti
static int pgctrl_show(struct seq_file *seq, void *v)
{
- seq_puts(seq, VERSION);
+ seq_puts(seq, version);
return 0;
}
@@ -3852,10 +3851,15 @@ static void __exit pg_cleanup(void)
module_init(pg_init);
module_exit(pg_cleanup);
-MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
+MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
MODULE_DESCRIPTION("Packet Generator tool");
MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
module_param(pg_count_d, int, 0);
+MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
module_param(pg_delay_d, int, 0);
+MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
module_param(pg_clone_skb_d, int, 0);
+MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
--
^ permalink raw reply
* [PATCH 12/14] pktgen: use common idle routine
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-idle-common.patch --]
[-- Type: text/plain, Size: 976 bytes --]
Simpler to have one place that spins and accounts for delays,
this will also make the last packet be detected faster for more
repeatable timing.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/core/pktgen.c 2009-08-27 16:28:17.520270294 -0700
+++ b/net/core/pktgen.c 2009-08-27 16:29:53.826372401 -0700
@@ -3458,16 +3458,10 @@ static void pktgen_xmit(struct pktgen_de
/* If pkt_dev->count is zero, then run forever */
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
- if (atomic_read(&(pkt_dev->skb->users)) != 1) {
- ktime_t idle_start = ktime_now();
- while (atomic_read(&(pkt_dev->skb->users)) != 1) {
- if (signal_pending(current)) {
- break;
- }
- schedule();
- }
- pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(),
- idle_start));
+ while (atomic_read(&(pkt_dev->skb->users)) != 1) {
+ if (signal_pending(current))
+ break;
+ idle(pkt_dev);
}
/* Done with this */
--
^ permalink raw reply
* [PATCH 01/14] pktgen: minor cleanup
From: Stephen Hemminger @ 2009-08-27 23:55 UTC (permalink / raw)
To: David Miller, Robert Olsson; +Cc: netdev, Thomas Gleixner
In-Reply-To: <20090827235506.624381734@vyatta.com>
[-- Attachment #1: pktgen-fseen.patch --]
[-- Type: text/plain, Size: 1870 bytes --]
A couple of minor functions can be written more compactly.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/core/pktgen.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
--- a/net/core/pktgen.c 2009-08-27 11:03:07.270217291 -0700
+++ b/net/core/pktgen.c 2009-08-27 11:57:14.759765248 -0700
@@ -509,7 +509,7 @@ static const struct file_operations pktg
static int pktgen_if_show(struct seq_file *seq, void *v)
{
- struct pktgen_dev *pkt_dev = seq->private;
+ const struct pktgen_dev *pkt_dev = seq->private;
__u64 sa;
__u64 stopped;
__u64 now = getCurUs();
@@ -1670,7 +1670,7 @@ static const struct file_operations pktg
static int pktgen_thread_show(struct seq_file *seq, void *v)
{
struct pktgen_thread *t = seq->private;
- struct pktgen_dev *pkt_dev;
+ const struct pktgen_dev *pkt_dev;
BUG_ON(!t);
@@ -2120,13 +2120,9 @@ static inline void set_pkt_overhead(stru
pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
}
-static inline int f_seen(struct pktgen_dev *pkt_dev, int flow)
+static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
{
-
- if (pkt_dev->flows[flow].flags & F_INIT)
- return 1;
- else
- return 0;
+ return !!(pkt_dev->flows[flow].flags & F_INIT);
}
static inline int f_pick(struct pktgen_dev *pkt_dev)
@@ -3101,17 +3097,14 @@ static void pktgen_stop_all_threads_ifs(
mutex_unlock(&pktgen_thread_lock);
}
-static int thread_is_running(struct pktgen_thread *t)
+static int thread_is_running(const struct pktgen_thread *t)
{
- struct pktgen_dev *pkt_dev;
- int res = 0;
+ const struct pktgen_dev *pkt_dev;
list_for_each_entry(pkt_dev, &t->if_list, list)
- if (pkt_dev->running) {
- res = 1;
- break;
- }
- return res;
+ if (pkt_dev->running)
+ return 1;
+ return 0;
}
static int pktgen_wait_thread_run(struct pktgen_thread *t)
--
^ permalink raw reply
* Re: [PATCH] r8169: Reduce looping in the interrupt handler.
From: Francois Romieu @ 2009-08-27 23:20 UTC (permalink / raw)
To: Eric W. Biederman
Cc: David Dillow, Michael Riepe, Michael Buesch, Rui Santos,
Michael B??ker, linux-kernel, netdev
In-Reply-To: <m1ocq1ke9u.fsf@fess.ebiederm.org>
Eric W. Biederman <ebiederm@xmission.com> :
[...]
> Sounds good.
Gah, I was not able to test it with a decent packet load. Patch below against
the current tree:
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index b82780d..6596ef6 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -3549,21 +3549,39 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
return count;
}
+static void rtl_napi_cond_schedule(struct rtl8169_private *tp, u16 status)
+{
+ if (status & tp->napi_event) {
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+ mmiowb();
+ napi_schedule(&tp->napi);
+ }
+}
+
static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
int handled = 0;
- int status;
+ u16 status;
/* loop handling interrupts until we have no new ones or
* we hit a invalid/hotplug case.
*/
status = RTL_R16(IntrStatus);
while (status && status != 0xffff) {
+ u16 acked;
+
handled = 1;
+ acked = (status & RxFIFOOver) ? (status | RxOverflow) : status;
+ acked &= ~tp->napi_event;
+
+ RTL_W16(IntrStatus, acked);
+
/* Handle all of the error cases first. These will reset
* the chip, so just exit the loop.
*/
@@ -3574,7 +3592,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
/* Work around for rx fifo overflow */
if (unlikely(status & RxFIFOOver) &&
- (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+ (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
netif_stop_queue(dev);
rtl8169_tx_timeout(dev);
break;
@@ -3588,31 +3606,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
if (status & LinkChg)
rtl8169_check_link_status(dev, tp, ioaddr);
- /* We need to see the lastest version of tp->intr_mask to
- * avoid ignoring an MSI interrupt and having to wait for
- * another event which may never come.
- */
- smp_rmb();
- if (status & tp->intr_mask & tp->napi_event) {
- RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
- tp->intr_mask = ~tp->napi_event;
-
- if (likely(napi_schedule_prep(&tp->napi)))
- __napi_schedule(&tp->napi);
- else if (netif_msg_intr(tp)) {
- printk(KERN_INFO "%s: interrupt %04x in poll\n",
- dev->name, status);
- }
- }
+ rtl_napi_cond_schedule(tp, status);
- /* We only get a new MSI interrupt when all active irq
- * sources on the chip have been acknowledged. So, ack
- * everything we've seen and check if new sources have become
- * active to avoid blocking all interrupts from the chip.
- */
- RTL_W16(IntrStatus,
- (status & RxFIFOOver) ? (status | RxOverflow) : status);
- status = RTL_R16(IntrStatus);
+ break;
}
return IRQ_RETVAL(handled);
@@ -3625,22 +3621,19 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
void __iomem *ioaddr = tp->mmio_addr;
int work_done;
+
+ RTL_W16(IntrStatus, tp->napi_event);
+
work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
rtl8169_tx_interrupt(dev, tp, ioaddr);
if (work_done < budget) {
napi_complete(napi);
- /* We need for force the visibility of tp->intr_mask
- * for other CPUs, as we can loose an MSI interrupt
- * and potentially wait for a retransmit timeout if we don't.
- * The posted write to IntrMask is safe, as it will
- * eventually make it to the chip and we won't loose anything
- * until it does.
- */
- tp->intr_mask = 0xffff;
- smp_wmb();
RTL_W16(IntrMask, tp->intr_event);
+ mmiowb();
+
+ rtl_napi_cond_schedule(tp, RTL_R16(IntrStatus));
}
return work_done;
--
Ueimor
^ permalink raw reply related
* Re: dropped packets with bonding and 8021q
From: Jesse Brandeburg @ 2009-08-27 22:22 UTC (permalink / raw)
To: Michael Walle, NetDEV list; +Cc: linux-kernel
In-Reply-To: <9e8b01b1556687e0b78ca63dfb5ca8dc.squirrel@ssl.serverraum.org>
Forwarding to the networking mailing list
On Wed, Aug 19, 2009 at 3:29 AM, Michael Walle<michael@walle.cc> wrote:
>
> Hi,
>
> i have some strange bonding and vlan configuration. The bonding interface
> is in active-standby mode and i want to send and receive raw ethernet
> frames on _both_ enslaved interfaces. Additionally the frames are tagged
> with a vlan id. So one config could be:
>
> # modprobe bonding mode=1
> # modprobe 8021q
> # ifenslave bond0 eth1
> # ifenslave bond0 eth2
> # vconfig add eth1 10
> # vconfig add eth2 20
> # vconfig add bond0 1000
>
> # [activate bonding active slave etc..]
>
> I use raw/dgram sockets (AF_PACKET) with eth1.10 and eth2.20 (or dump the
> frames with tcpdump).
>
> As long as i don't use the bonding module everything works as expected.
> But if the physical interfaces are enslaved, frames received on the
> standby device will be dropped.
>
> The network driver is e1000. So the hardware acceleration for tagged VLAN
> frames gets used and the frame gets through __vlan_hwaccel_rx() in the
> receiving path. And there it seems to get dropped by
> skb_bond_should_drop().
>
> On the "normal" receive path there was a patch by Joe Eykholt that allows
> to receive frames on the physical interface even if it is enslaved and not
> active (git commit 0d7a3681232f545).
>
> Shouldn't __vlan_hwaccel_rx() (in net/8021q/vlan_core.c) be patched in the
> same way to allow reception on inactive enslaved interfaces?
>
> Thanks,
> Michael
>
> PS. could you please cc me, as i'm not subscribed to the ml.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply
* [net-next PATCH 3/3] qlge: Move TX completions from workqueue to NAPI.
From: Ron Mercer @ 2009-08-27 21:02 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1251406931-15107-1-git-send-email-ron.mercer@qlogic.com>
TX completions were running in a workqueue queued by the ISR. This
patch moves the processing of TX completions to an existing RSS NAPI
context.
Now each irq vector runs NAPI for one RSS ring and one or more TX
completion rings.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 7 +-
drivers/net/qlge/qlge_main.c | 266 +++++++++++++++++++++---------------------
2 files changed, 137 insertions(+), 136 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index ed5dbca..a9845a2 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1292,7 +1292,6 @@ struct rx_ring {
u32 cpu; /* Which CPU this should run on. */
char name[IFNAMSIZ + 5];
struct napi_struct napi;
- struct delayed_work rx_work;
u8 reserved;
struct ql_adapter *qdev;
};
@@ -1366,6 +1365,7 @@ struct nic_stats {
struct intr_context {
struct ql_adapter *qdev;
u32 intr;
+ u32 irq_mask; /* Mask of which rings the vector services. */
u32 hooked;
u32 intr_en_mask; /* value/mask used to enable this intr */
u32 intr_dis_mask; /* value/mask used to disable this intr */
@@ -1486,11 +1486,11 @@ struct ql_adapter {
struct intr_context intr_context[MAX_RX_RINGS];
int tx_ring_count; /* One per online CPU. */
- u32 rss_ring_count; /* One per online CPU. */
+ u32 rss_ring_count; /* One per irq vector. */
/*
* rx_ring_count =
* (CPU count * outbound completion rx_ring) +
- * (CPU count * inbound (RSS) completion rx_ring)
+ * (irq_vector_cnt * inbound (RSS) completion rx_ring)
*/
int rx_ring_count;
int ring_mem_size;
@@ -1517,7 +1517,6 @@ struct ql_adapter {
union flash_params flash;
struct net_device_stats stats;
- struct workqueue_struct *q_workqueue;
struct workqueue_struct *workqueue;
struct delayed_work asic_reset_work;
struct delayed_work mpi_reset_work;
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 0cbda4d..8dd266b 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -1859,11 +1859,41 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
{
struct rx_ring *rx_ring = container_of(napi, struct rx_ring, napi);
struct ql_adapter *qdev = rx_ring->qdev;
- int work_done = ql_clean_inbound_rx_ring(rx_ring, budget);
+ struct rx_ring *trx_ring;
+ int i, work_done = 0;
+ struct intr_context *ctx = &qdev->intr_context[rx_ring->cq_id];
QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n",
rx_ring->cq_id);
+ /* Service the TX rings first. They start
+ * right after the RSS rings. */
+ for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) {
+ trx_ring = &qdev->rx_ring[i];
+ /* If this TX completion ring belongs to this vector and
+ * it's not empty then service it.
+ */
+ if ((ctx->irq_mask & (1 << trx_ring->cq_id)) &&
+ (ql_read_sh_reg(trx_ring->prod_idx_sh_reg) !=
+ trx_ring->cnsmr_idx)) {
+ QPRINTK(qdev, INTR, DEBUG,
+ "%s: Servicing TX completion ring %d.\n",
+ __func__, trx_ring->cq_id);
+ ql_clean_outbound_rx_ring(trx_ring);
+ }
+ }
+
+ /*
+ * Now service the RSS ring if it's active.
+ */
+ if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
+ rx_ring->cnsmr_idx) {
+ QPRINTK(qdev, INTR, DEBUG,
+ "%s: Servicing RX completion ring %d.\n",
+ __func__, rx_ring->cq_id);
+ work_done = ql_clean_inbound_rx_ring(rx_ring, budget);
+ }
+
if (work_done < budget) {
napi_complete(napi);
ql_enable_completion_interrupt(qdev, rx_ring->irq);
@@ -1925,38 +1955,6 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
}
-/* Worker thread to process a given rx_ring that is dedicated
- * to outbound completions.
- */
-static void ql_tx_clean(struct work_struct *work)
-{
- struct rx_ring *rx_ring =
- container_of(work, struct rx_ring, rx_work.work);
- ql_clean_outbound_rx_ring(rx_ring);
- ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq);
-
-}
-
-/* Worker thread to process a given rx_ring that is dedicated
- * to inbound completions.
- */
-static void ql_rx_clean(struct work_struct *work)
-{
- struct rx_ring *rx_ring =
- container_of(work, struct rx_ring, rx_work.work);
- ql_clean_inbound_rx_ring(rx_ring, 64);
- ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq);
-}
-
-/* MSI-X Multiple Vector Interrupt Handler for outbound completions. */
-static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id)
-{
- struct rx_ring *rx_ring = dev_id;
- queue_delayed_work_on(rx_ring->cpu, rx_ring->qdev->q_workqueue,
- &rx_ring->rx_work, 0);
- return IRQ_HANDLED;
-}
-
/* MSI-X Multiple Vector Interrupt Handler for inbound completions. */
static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
{
@@ -1976,7 +1974,6 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
struct ql_adapter *qdev = rx_ring->qdev;
struct intr_context *intr_context = &qdev->intr_context[0];
u32 var;
- int i;
int work_done = 0;
spin_lock(&qdev->hw_lock);
@@ -2017,41 +2014,18 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
}
/*
- * Check the default queue and wake handler if active.
+ * Get the bit-mask that shows the active queues for this
+ * pass. Compare it to the queues that this irq services
+ * and call napi if there's a match.
*/
- rx_ring = &qdev->rx_ring[0];
- if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
- QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n");
- ql_disable_completion_interrupt(qdev, intr_context->intr);
- queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue,
- &rx_ring->rx_work, 0);
- work_done++;
- }
-
- if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
- /*
- * Start the DPC for each active queue.
- */
- for (i = 1; i < qdev->rx_ring_count; i++) {
- rx_ring = &qdev->rx_ring[i];
- if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
- rx_ring->cnsmr_idx) {
+ var = ql_read32(qdev, ISR1);
+ if (var & intr_context->irq_mask) {
QPRINTK(qdev, INTR, INFO,
- "Waking handler for rx_ring[%d].\n", i);
- ql_disable_completion_interrupt(qdev,
- intr_context->
- intr);
- if (i >= qdev->rss_ring_count)
- queue_delayed_work_on(rx_ring->cpu,
- qdev->q_workqueue,
- &rx_ring->rx_work,
- 0);
- else
+ "Waking handler for rx_ring[0].\n");
+ ql_disable_completion_interrupt(qdev, intr_context->intr);
napi_schedule(&rx_ring->napi);
work_done++;
}
- }
- }
ql_enable_completion_interrupt(qdev, intr_context->intr);
return work_done ? IRQ_HANDLED : IRQ_NONE;
}
@@ -2703,35 +2677,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
switch (rx_ring->type) {
case TX_Q:
- /* If there's only one interrupt, then we use
- * worker threads to process the outbound
- * completion handling rx_rings. We do this so
- * they can be run on multiple CPUs. There is
- * room to play with this more where we would only
- * run in a worker if there are more than x number
- * of outbound completions on the queue and more
- * than one queue active. Some threshold that
- * would indicate a benefit in spite of the cost
- * of a context switch.
- * If there's more than one interrupt, then the
- * outbound completions are processed in the ISR.
- */
- if (!test_bit(QL_MSIX_ENABLED, &qdev->flags))
- INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean);
- else {
- /* With all debug warnings on we see a WARN_ON message
- * when we free the skb in the interrupt context.
- */
- INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean);
- }
cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames);
break;
- case DEFAULT_Q:
- INIT_DELAYED_WORK(&rx_ring->rx_work, ql_rx_clean);
- cqicb->irq_delay = 0;
- cqicb->pkt_delay = 0;
- break;
case RX_Q:
/* Inbound completion handling rx_rings run in
* separate NAPI contexts.
@@ -2878,6 +2826,71 @@ msi:
QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n");
}
+/* Each vector services 1 RSS ring and and 1 or more
+ * TX completion rings. This function loops through
+ * the TX completion rings and assigns the vector that
+ * will service it. An example would be if there are
+ * 2 vectors (so 2 RSS rings) and 8 TX completion rings.
+ * This would mean that vector 0 would service RSS ring 0
+ * and TX competion rings 0,1,2 and 3. Vector 1 would
+ * service RSS ring 1 and TX completion rings 4,5,6 and 7.
+ */
+static void ql_set_tx_vect(struct ql_adapter *qdev)
+{
+ int i, j, vect;
+ u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count;
+
+ if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) {
+ /* Assign irq vectors to TX rx_rings.*/
+ for (vect = 0, j = 0, i = qdev->rss_ring_count;
+ i < qdev->rx_ring_count; i++) {
+ if (j == tx_rings_per_vector) {
+ vect++;
+ j = 0;
+ }
+ qdev->rx_ring[i].irq = vect;
+ j++;
+ }
+ } else {
+ /* For single vector all rings have an irq
+ * of zero.
+ */
+ for (i = 0; i < qdev->rx_ring_count; i++)
+ qdev->rx_ring[i].irq = 0;
+ }
+}
+
+/* Set the interrupt mask for this vector. Each vector
+ * will service 1 RSS ring and 1 or more TX completion
+ * rings. This function sets up a bit mask per vector
+ * that indicates which rings it services.
+ */
+static void ql_set_irq_mask(struct ql_adapter *qdev, struct intr_context *ctx)
+{
+ int j, vect = ctx->intr;
+ u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count;
+
+ if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) {
+ /* Add the RSS ring serviced by this vector
+ * to the mask.
+ */
+ ctx->irq_mask = (1 << qdev->rx_ring[vect].cq_id);
+ /* Add the TX ring(s) serviced by this vector
+ * to the mask. */
+ for (j = 0; j < tx_rings_per_vector; j++) {
+ ctx->irq_mask |=
+ (1 << qdev->rx_ring[qdev->rss_ring_count +
+ (vect * tx_rings_per_vector) + j].cq_id);
+ }
+ } else {
+ /* For single vector we just shift each queue's
+ * ID into the mask.
+ */
+ for (j = 0; j < qdev->rx_ring_count; j++)
+ ctx->irq_mask |= (1 << qdev->rx_ring[j].cq_id);
+ }
+}
+
/*
* Here we build the intr_context structures based on
* our rx_ring count and intr vector count.
@@ -2893,12 +2906,15 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
/* Each rx_ring has it's
* own intr_context since we have separate
* vectors for each queue.
- * This only true when MSI-X is enabled.
*/
for (i = 0; i < qdev->intr_count; i++, intr_context++) {
qdev->rx_ring[i].irq = i;
intr_context->intr = i;
intr_context->qdev = qdev;
+ /* Set up this vector's bit-mask that indicates
+ * which queues it services.
+ */
+ ql_set_irq_mask(qdev, intr_context);
/*
* We set up each vectors enable/disable/read bits so
* there's no bit/mask calculations in the critical path.
@@ -2915,20 +2931,21 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK |
INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD |
i;
-
- if (i < qdev->rss_ring_count) {
- /*
- * Inbound queues handle unicast frames only.
+ if (i == 0) {
+ /* The first vector/queue handles
+ * broadcast/multicast, fatal errors,
+ * and firmware events. This in addition
+ * to normal inbound NAPI processing.
*/
- intr_context->handler = qlge_msix_rx_isr;
+ intr_context->handler = qlge_isr;
sprintf(intr_context->name, "%s-rx-%d",
qdev->ndev->name, i);
} else {
/*
- * Outbound queue is for outbound completions only.
+ * Inbound queues handle unicast frames only.
*/
- intr_context->handler = qlge_msix_tx_isr;
- sprintf(intr_context->name, "%s-tx-%d",
+ intr_context->handler = qlge_msix_rx_isr;
+ sprintf(intr_context->name, "%s-rx-%d",
qdev->ndev->name, i);
}
}
@@ -2955,9 +2972,17 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
*/
intr_context->handler = qlge_isr;
sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name);
- for (i = 0; i < qdev->rx_ring_count; i++)
- qdev->rx_ring[i].irq = 0;
+ /* Set up this vector's bit-mask that indicates
+ * which queues it services. In this case there is
+ * a single vector so it will service all RSS and
+ * TX completion rings.
+ */
+ ql_set_irq_mask(qdev, intr_context);
}
+ /* Tell the TX completion rings which MSIx vector
+ * they will be using.
+ */
+ ql_set_tx_vect(qdev);
}
static void ql_free_irq(struct ql_adapter *qdev)
@@ -3326,7 +3351,6 @@ static void ql_display_dev_info(struct net_device *ndev)
static int ql_adapter_down(struct ql_adapter *qdev)
{
int i, status = 0;
- struct rx_ring *rx_ring;
ql_link_off(qdev);
@@ -3340,27 +3364,8 @@ static int ql_adapter_down(struct ql_adapter *qdev)
cancel_delayed_work_sync(&qdev->mpi_idc_work);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
- /* The default queue at index 0 is always processed in
- * a workqueue.
- */
- cancel_delayed_work_sync(&qdev->rx_ring[0].rx_work);
-
- /* The rest of the rx_rings are processed in
- * a workqueue only if it's a single interrupt
- * environment (MSI/Legacy).
- */
- for (i = 1; i < qdev->rx_ring_count; i++) {
- rx_ring = &qdev->rx_ring[i];
- /* Only the RSS rings use NAPI on multi irq
- * environment. Outbound completion processing
- * is done in interrupt context.
- */
- if (i <= qdev->rss_ring_count) {
- napi_disable(&rx_ring->napi);
- } else {
- cancel_delayed_work_sync(&rx_ring->rx_work);
- }
- }
+ for (i = 0; i < qdev->rss_ring_count; i++)
+ napi_disable(&qdev->rx_ring[i].napi);
clear_bit(QL_ADAPTER_UP, &qdev->flags);
@@ -3476,9 +3481,9 @@ static int ql_configure_rings(struct ql_adapter *qdev)
/*
* The completion queue ID for the tx rings start
- * immediately after the default Q ID, which is zero.
+ * immediately after the rss rings.
*/
- tx_ring->cq_id = i + qdev->rss_ring_count;
+ tx_ring->cq_id = qdev->rss_ring_count + i;
}
for (i = 0; i < qdev->rx_ring_count; i++) {
@@ -3488,7 +3493,9 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->cq_id = i;
rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */
if (i < qdev->rss_ring_count) {
- /* Inbound completions (RSS) queues */
+ /*
+ * Inbound (RSS) queues.
+ */
rx_ring->cq_len = qdev->rx_ring_size;
rx_ring->cq_size =
rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
@@ -3804,10 +3811,7 @@ static void ql_release_all(struct pci_dev *pdev)
destroy_workqueue(qdev->workqueue);
qdev->workqueue = NULL;
}
- if (qdev->q_workqueue) {
- destroy_workqueue(qdev->q_workqueue);
- qdev->q_workqueue = NULL;
- }
+
if (qdev->reg_base)
iounmap(qdev->reg_base);
if (qdev->doorbell_area)
@@ -3920,8 +3924,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
* Set up the operating parameters.
*/
qdev->rx_csum = 1;
-
- qdev->q_workqueue = create_workqueue(ndev->name);
qdev->workqueue = create_singlethread_workqueue(ndev->name);
INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work);
INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work);
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 2/3] qlge: Allow running MSIx with fewer vectors.
From: Ron Mercer @ 2009-08-27 21:02 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1251406931-15107-1-git-send-email-ron.mercer@qlogic.com>
Currently we downshift to MSI/Legacy if we don't get enough vectors for
cpu_count RSS rings plus cpu_count TX completion rings. This patch
allows running MSIX with the vector count that the platform provides.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 85 +++++++++++++++++++-----------------------
1 files changed, 38 insertions(+), 47 deletions(-)
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 89ea9c7..0cbda4d 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -2815,17 +2815,20 @@ static void ql_disable_msix(struct ql_adapter *qdev)
}
}
+/* We start by trying to get the number of vectors
+ * stored in qdev->intr_count. If we don't get that
+ * many then we reduce the count and try again.
+ */
static void ql_enable_msix(struct ql_adapter *qdev)
{
- int i;
+ int i, err;
- qdev->intr_count = 1;
/* Get the MSIX vectors. */
if (irq_type == MSIX_IRQ) {
/* Try to alloc space for the msix struct,
* if it fails then go to MSI/legacy.
*/
- qdev->msi_x_entry = kcalloc(qdev->rx_ring_count,
+ qdev->msi_x_entry = kcalloc(qdev->intr_count,
sizeof(struct msix_entry),
GFP_KERNEL);
if (!qdev->msi_x_entry) {
@@ -2833,26 +2836,36 @@ static void ql_enable_msix(struct ql_adapter *qdev)
goto msi;
}
- for (i = 0; i < qdev->rx_ring_count; i++)
+ for (i = 0; i < qdev->intr_count; i++)
qdev->msi_x_entry[i].entry = i;
- if (!pci_enable_msix
- (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) {
- set_bit(QL_MSIX_ENABLED, &qdev->flags);
- qdev->intr_count = qdev->rx_ring_count;
- QPRINTK(qdev, IFUP, DEBUG,
- "MSI-X Enabled, got %d vectors.\n",
- qdev->intr_count);
- return;
- } else {
+ /* Loop to get our vectors. We start with
+ * what we want and settle for what we get.
+ */
+ do {
+ err = pci_enable_msix(qdev->pdev,
+ qdev->msi_x_entry, qdev->intr_count);
+ if (err > 0)
+ qdev->intr_count = err;
+ } while (err > 0);
+
+ if (err < 0) {
kfree(qdev->msi_x_entry);
qdev->msi_x_entry = NULL;
QPRINTK(qdev, IFUP, WARNING,
"MSI-X Enable failed, trying MSI.\n");
+ qdev->intr_count = 1;
irq_type = MSI_IRQ;
+ } else if (err == 0) {
+ set_bit(QL_MSIX_ENABLED, &qdev->flags);
+ QPRINTK(qdev, IFUP, INFO,
+ "MSI-X Enabled, got %d vectors.\n",
+ qdev->intr_count);
+ return;
}
}
msi:
+ qdev->intr_count = 1;
if (irq_type == MSI_IRQ) {
if (!pci_enable_msi(qdev->pdev)) {
set_bit(QL_MSI_ENABLED, &qdev->flags);
@@ -2876,8 +2889,6 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
int i = 0;
struct intr_context *intr_context = &qdev->intr_context[0];
- ql_enable_msix(qdev);
-
if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) {
/* Each rx_ring has it's
* own intr_context since we have separate
@@ -3438,40 +3449,20 @@ static int ql_configure_rings(struct ql_adapter *qdev)
int i;
struct rx_ring *rx_ring;
struct tx_ring *tx_ring;
- int cpu_cnt = num_online_cpus();
-
- /*
- * For each processor present we allocate one
- * rx_ring for outbound completions, and one
- * rx_ring for inbound completions. Plus there is
- * always the one default queue. For the CPU
- * counts we end up with the following rx_rings:
- * rx_ring count =
- * one default queue +
- * (CPU count * outbound completion rx_ring) +
- * (CPU count * inbound (RSS) completion rx_ring)
- * To keep it simple we limit the total number of
- * queues to < 32, so we truncate CPU to 8.
- * This limitation can be removed when requested.
+ int cpu_cnt = min(MAX_CPUS, (int)num_online_cpus());
+
+ /* In a perfect world we have one RSS ring for each CPU
+ * and each has it's own vector. To do that we ask for
+ * cpu_cnt vectors. ql_enable_msix() will adjust the
+ * vector count to what we actually get. We then
+ * allocate an RSS ring for each.
+ * Essentially, we are doing min(cpu_count, msix_vector_count).
*/
-
- if (cpu_cnt > MAX_CPUS)
- cpu_cnt = MAX_CPUS;
-
- /*
- * rx_ring[0] is always the default queue.
- */
- /* Allocate outbound completion ring for each CPU. */
+ qdev->intr_count = cpu_cnt;
+ ql_enable_msix(qdev);
+ /* Adjust the RSS ring count to the actual vector count. */
+ qdev->rss_ring_count = qdev->intr_count;
qdev->tx_ring_count = cpu_cnt;
- /* Allocate inbound completion (RSS) ring for each CPU. */
- qdev->rss_ring_count = cpu_cnt;
- /*
- * qdev->rx_ring_count:
- * Total number of rx_rings. This includes the one
- * default queue, a number of outbound completion
- * handler rx_rings, and the number of inbound
- * completion handler rx_rings.
- */
qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count;
for (i = 0; i < qdev->tx_ring_count; i++) {
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 1/3] qlge: Get rid of 'default' rx_ring type.
From: Ron Mercer @ 2009-08-27 21:02 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1251406931-15107-1-git-send-email-ron.mercer@qlogic.com>
Currently we have three types of RX rings.
1) Default ring - services rx_ring for broadcast/multicast, handles
firmware events, and errors.
2) TX completion ring - handles only outbound completions.
3) RSS ring - handles only inbound completions.
This patch gets rid of the default ring type and moves it's functionality
into the first RSS ring. This makes better use of MSIX vectors since
they are a limited resource on some platforms.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 4 +--
drivers/net/qlge/qlge_dbg.c | 2 -
drivers/net/qlge/qlge_ethtool.c | 16 ++++----
drivers/net/qlge/qlge_main.c | 70 ++++++++++----------------------------
4 files changed, 28 insertions(+), 64 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 6ed5317..ed5dbca 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1287,7 +1287,7 @@ struct rx_ring {
u32 sbq_free_cnt; /* free buffer desc cnt */
/* Misc. handler elements. */
- u32 type; /* Type of queue, tx, rx, or default. */
+ u32 type; /* Type of queue, tx, rx. */
u32 irq; /* Which vector this ring is assigned. */
u32 cpu; /* Which CPU this should run on. */
char name[IFNAMSIZ + 5];
@@ -1486,11 +1486,9 @@ struct ql_adapter {
struct intr_context intr_context[MAX_RX_RINGS];
int tx_ring_count; /* One per online CPU. */
- u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */
u32 rss_ring_count; /* One per online CPU. */
/*
* rx_ring_count =
- * one default queue +
* (CPU count * outbound completion rx_ring) +
* (CPU count * inbound (RSS) completion rx_ring)
*/
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 40a70c3..aa88cb3 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -418,8 +418,6 @@ void ql_dump_qdev(struct ql_adapter *qdev)
printk(KERN_ERR PFX "qdev->intr_count = %d.\n", qdev->intr_count);
printk(KERN_ERR PFX "qdev->tx_ring = %p.\n",
qdev->tx_ring);
- printk(KERN_ERR PFX "qdev->rss_ring_first_cq_id = %d.\n",
- qdev->rss_ring_first_cq_id);
printk(KERN_ERR PFX "qdev->rss_ring_count = %d.\n",
qdev->rss_ring_count);
printk(KERN_ERR PFX "qdev->rx_ring = %p.\n", qdev->rx_ring);
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index eb6a9ee..68f9bd2 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -49,10 +49,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
/* Skip the default queue, and update the outbound handler
* queues if they changed.
*/
- cqicb = (struct cqicb *)&qdev->rx_ring[1];
+ cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_count];
if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs ||
- le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) {
- for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) {
+ le16_to_cpu(cqicb->pkt_delay) !=
+ qdev->tx_max_coalesced_frames) {
+ for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) {
rx_ring = &qdev->rx_ring[i];
cqicb = (struct cqicb *)rx_ring;
cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
@@ -70,12 +71,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
}
/* Update the inbound (RSS) handler queues if they changed. */
- cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_first_cq_id];
+ cqicb = (struct cqicb *)&qdev->rx_ring[0];
if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs ||
- le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) {
- for (i = qdev->rss_ring_first_cq_id;
- i <= qdev->rss_ring_first_cq_id + qdev->rss_ring_count;
- i++) {
+ le16_to_cpu(cqicb->pkt_delay) !=
+ qdev->rx_max_coalesced_frames) {
+ for (i = 0; i < qdev->rss_ring_count; i++, rx_ring++) {
rx_ring = &qdev->rx_ring[i];
cqicb = (struct cqicb *)rx_ring;
cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs);
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 3a271af..89ea9c7 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -370,9 +370,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
cam_output = (CAM_OUT_ROUTE_NIC |
(qdev->
func << CAM_OUT_FUNC_SHIFT) |
- (qdev->
- rss_ring_first_cq_id <<
- CAM_OUT_CQ_ID_SHIFT));
+ (0 << CAM_OUT_CQ_ID_SHIFT));
if (qdev->vlgrp)
cam_output |= CAM_OUT_RV;
/* route to NIC core */
@@ -1649,8 +1647,7 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
qdev->stats.rx_packets++;
qdev->stats.rx_bytes += skb->len;
- skb_record_rx_queue(skb,
- rx_ring->cq_id - qdev->rss_ring_first_cq_id);
+ skb_record_rx_queue(skb, rx_ring->cq_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
if (qdev->vlgrp &&
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
@@ -2044,7 +2041,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
ql_disable_completion_interrupt(qdev,
intr_context->
intr);
- if (i < qdev->rss_ring_first_cq_id)
+ if (i >= qdev->rss_ring_count)
queue_delayed_work_on(rx_ring->cpu,
qdev->q_workqueue,
&rx_ring->rx_work,
@@ -2908,28 +2905,20 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD |
i;
- if (i == 0) {
+ if (i < qdev->rss_ring_count) {
/*
- * Default queue handles bcast/mcast plus
- * async events. Needs buffers.
+ * Inbound queues handle unicast frames only.
*/
- intr_context->handler = qlge_isr;
- sprintf(intr_context->name, "%s-default-queue",
- qdev->ndev->name);
- } else if (i < qdev->rss_ring_first_cq_id) {
+ intr_context->handler = qlge_msix_rx_isr;
+ sprintf(intr_context->name, "%s-rx-%d",
+ qdev->ndev->name, i);
+ } else {
/*
* Outbound queue is for outbound completions only.
*/
intr_context->handler = qlge_msix_tx_isr;
sprintf(intr_context->name, "%s-tx-%d",
qdev->ndev->name, i);
- } else {
- /*
- * Inbound queues handle unicast frames only.
- */
- intr_context->handler = qlge_msix_rx_isr;
- sprintf(intr_context->name, "%s-rx-%d",
- qdev->ndev->name, i);
}
}
} else {
@@ -3062,7 +3051,7 @@ static int ql_start_rss(struct ql_adapter *qdev)
memset((void *)ricb, 0, sizeof(*ricb));
- ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K;
+ ricb->base_cq = RSS_L4K;
ricb->flags =
(RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 |
RSS_RT6);
@@ -3264,7 +3253,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
}
/* Start NAPI for the RSS queues. */
- for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) {
+ for (i = 0; i < qdev->rss_ring_count; i++) {
QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n",
i);
napi_enable(&qdev->rx_ring[i].napi);
@@ -3355,7 +3344,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
* environment. Outbound completion processing
* is done in interrupt context.
*/
- if (i >= qdev->rss_ring_first_cq_id) {
+ if (i <= qdev->rss_ring_count) {
napi_disable(&rx_ring->napi);
} else {
cancel_delayed_work_sync(&rx_ring->rx_work);
@@ -3370,7 +3359,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
/* Call netif_napi_del() from common point.
*/
- for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++)
+ for (i = 0; i < qdev->rss_ring_count; i++)
netif_napi_del(&qdev->rx_ring[i].napi);
ql_free_rx_buffers(qdev);
@@ -3476,8 +3465,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
qdev->tx_ring_count = cpu_cnt;
/* Allocate inbound completion (RSS) ring for each CPU. */
qdev->rss_ring_count = cpu_cnt;
- /* cq_id for the first inbound ring handler. */
- qdev->rss_ring_first_cq_id = cpu_cnt + 1;
/*
* qdev->rx_ring_count:
* Total number of rx_rings. This includes the one
@@ -3485,7 +3472,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
* handler rx_rings, and the number of inbound
* completion handler rx_rings.
*/
- qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
+ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count;
for (i = 0; i < qdev->tx_ring_count; i++) {
tx_ring = &qdev->tx_ring[i];
@@ -3500,7 +3487,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
* The completion queue ID for the tx rings start
* immediately after the default Q ID, which is zero.
*/
- tx_ring->cq_id = i + 1;
+ tx_ring->cq_id = i + qdev->rss_ring_count;
}
for (i = 0; i < qdev->rx_ring_count; i++) {
@@ -3509,11 +3496,8 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->qdev = qdev;
rx_ring->cq_id = i;
rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */
- if (i == 0) { /* Default queue at index 0. */
- /*
- * Default queue handles bcast/mcast plus
- * async events. Needs buffers.
- */
+ if (i < qdev->rss_ring_count) {
+ /* Inbound completions (RSS) queues */
rx_ring->cq_len = qdev->rx_ring_size;
rx_ring->cq_size =
rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
@@ -3525,8 +3509,8 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->sbq_size =
rx_ring->sbq_len * sizeof(__le64);
rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
- rx_ring->type = DEFAULT_Q;
- } else if (i < qdev->rss_ring_first_cq_id) {
+ rx_ring->type = RX_Q;
+ } else {
/*
* Outbound queue handles outbound completions only.
*/
@@ -3541,22 +3525,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->sbq_size = 0;
rx_ring->sbq_buf_size = 0;
rx_ring->type = TX_Q;
- } else { /* Inbound completions (RSS) queues */
- /*
- * Inbound queues handle unicast frames only.
- */
- rx_ring->cq_len = qdev->rx_ring_size;
- rx_ring->cq_size =
- rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
- rx_ring->lbq_len = NUM_LARGE_BUFFERS;
- rx_ring->lbq_size =
- rx_ring->lbq_len * sizeof(__le64);
- rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
- rx_ring->sbq_len = NUM_SMALL_BUFFERS;
- rx_ring->sbq_size =
- rx_ring->sbq_len * sizeof(__le64);
- rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
- rx_ring->type = RX_Q;
}
}
return 0;
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 0/3] qlge: Allow running MSIx with fewer vectors.
From: Ron Mercer @ 2009-08-27 21:02 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Hello Dave and All,
The purpose of this patch series is to allow MSIx usage on
platforms where vector availability is limited. The change is to
move broadcast/multicast/firmware event processing from a dedicated
'default' ring into the first RSS ring, and move TX completion
processing into NAPI context.
These patches change the rx_ring to MSIx vector mapping as follows:
FROM-
- 1 x default rx_ring (broadcast/multicast/firmware events)
- cpu_count x RSS rx_rings
- cpu_count x TX completion rx_rings.
We then attempt to allocate a vector for each rx_ring. If it fails then
we drop down to MSI/Legacy single interrupt. This is not efficient.
TO-
1) Get rid of dedicated default rx_ring and add it's extra functionality
to the first RSS ring.
2) Allocate one RSS ring for each MSIX vector.
3) Allocate one TX completion ring for each CPU.
4) Move TX completion ring processing to NAPI context.
Each interrupt will start NAPI to process it's RSS ring and
and one or more TX completion rx_rings.
Regards,
Ron Mercer
^ permalink raw reply
* Re: UDP multicast packet loss not reported if TX ring overrun?
From: Christoph Lameter @ 2009-08-27 20:23 UTC (permalink / raw)
To: Sridhar Samudrala
Cc: David Stevens, David S. Miller, Eric Dumazet, netdev, niv
In-Reply-To: <alpine.DEB.1.10.0908271139450.14277@gentwo.org>
ip_local_out returns NET_XMIT_DROP but the qdisc increment does not
trigger...
[ 219.098552] ip_local_out failed with 1
[ 219.098798] ip_local_out failed with 1
[ 219.099091] ip_local_out failed with 1
[ 219.099158] ip_local_out failed with 1
[ 219.099399] ip_local_out failed with 1
[ 219.099466] ip_local_out failed with 1
[ 219.099530] ip_local_out failed with 1
[ 219.099688] ip_local_out failed with 1
[ 219.099751] ip_local_out failed with 1
[ 219.099818] ip_local_out failed with 1
---
net/core/dev.c | 2 ++
net/ipv4/ip_output.c | 2 ++
2 files changed, 4 insertions(+)
Index: linux-2.6.31-rc7/net/core/dev.c
===================================================================
--- linux-2.6.31-rc7.orig/net/core/dev.c 2009-08-27 19:46:44.000000000 +0000
+++ linux-2.6.31-rc7/net/core/dev.c 2009-08-27 19:51:54.000000000 +0000
@@ -1865,6 +1865,8 @@ gso:
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
rc = qdisc_drop(skb, q);
+ if (net_ratelimit())
+ printk(KERN_CRIT "Qdisc not active. NIC overrun\n");
} else {
rc = qdisc_enqueue_root(skb, q);
qdisc_run(q);
Index: linux-2.6.31-rc7/net/ipv4/ip_output.c
===================================================================
--- linux-2.6.31-rc7.orig/net/ipv4/ip_output.c 2009-08-27 19:48:17.000000000 +0000
+++ linux-2.6.31-rc7/net/ipv4/ip_output.c 2009-08-27 19:51:30.000000000 +0000
@@ -1301,6 +1301,8 @@ int ip_push_pending_frames(struct sock *
/* Netfilter gets whole the not fragmented skb. */
err = ip_local_out(skb);
if (err) {
+ if (net_ratelimit())
+ printk(KERN_CRIT "ip_local_out failed with %d\n", err);
if (err > 0)
err = net_xmit_errno(err);
if (err)
^ permalink raw reply
* Re: regression: Apparently missing err assignment in ipv6 bind
From: David Miller @ 2009-08-27 20:12 UTC (permalink / raw)
To: maze; +Cc: netdev
In-Reply-To: <6897af6d0908270816w5ee81dd5j98bd11fe1d49479d@mail.gmail.com>
From: Maciej Żenczykowski <maze@google.com>
Date: Thu, 27 Aug 2009 08:16:40 -0700
> AFAICT, 2.6.30.5 and 2.6.31-rc7 both include a change in net/ipv6/af_inet6.c
>
> http://lxr.linux.no/linux+v2.6.30.5/net/ipv6/af_inet6.c#L298
>
> which results in a possible error return path with no err assignment.
> I believe the error should be EADDRNOTAVAIL.
There is a fix for this already in Linus's tree.
And I'm going to submit it for -stable too.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox