* Re: CPU: 0 Not tainted (3.1.9+ #1) when ifconfig rose0 down
From: Bernard Pidoux @ 2012-07-31 15:27 UTC (permalink / raw)
To: linux-hams, Linux Netdev List
In-Reply-To: <5017E786.5000102@free.fr>
Here is a complementary observation.
Trying to remove rose module with rmmod rose did not create any kernel
panic.
However, there is an endless message from the kernel saying :
Message from syslogd@raspberrypi at Jul 31 17:22:40 ...
kernel:[ 831.579007] unregister_netdevice: waiting for rose0 to
become free. Usage count = 23
Message from syslogd@raspberrypi at Jul 31 17:22:50 ...
kernel:[ 841.739390] unregister_netdevice: waiting for rose0 to
become free. Usage count = 23
Message from syslogd@raspberrypi at Jul 31 17:23:00 ...
kernel:[ 851.899758] unregister_netdevice: waiting for rose0 to
become free. Usage count = 23
.....
As observed at many occasions, count number seems to be random ! and
the same message keeps going without any change of count number.
At the same time, there is no possibility to recover the command line on
any console.
However I could loggin via ssh and I noticed that rose0 device is
actually no more in the ifconfig list.
If I try to remove rose with rmmod rose I get :
root@raspberrypi:/home/pi# rmmod rose
libkmod: ERROR ../libkmod/libkmod-module.c:753
kmod_module_remove_module: could not remove 'rose': Device or resource busy
Error: could not remove module rose: Device or resource busy
Does this help ?
On 31/07/2012 16:11, Bernard Pidoux wrote:
> Hi,
>
> I observe systematically a kernel panic when I try to shutdown rose0
> device using ifconfig rose0 down
>
> This is happening on two very different ROSE implementation, one is on a
> machine with x86-64 kernel 4.6.3 on an Intel core 2 duo CPU
> the other is on a RaspBerry Pi with Raspbian and 3.1.9+ wheezy kernel
> recompiled with AX.25 modules (ax25, rose, netrom, 6pack, kiss) enabled.
>
> Here is an image of the screen dump :
>
> http://f6bvp.org/photos/rose_device_event.JPG
>
> It can be noticed that PC is at rose_device_event and
> LR is at sock_def_wakeup
>
> One thing to be noticed is that when I close before all ROSE and AX.25
> applications, there are still a few populated sockets, probably for one
> of the program did not close the sockets properly.
>
> I that case, does rose module should accept to shutdown rose0 device ?
> However, I guess that it should not create a kernel panic due to a
> kernel NULL pointer.
>
> I don't know what to do in order to debug that issue.
>
> Bernard
>
^ permalink raw reply
* [PATCH] ipv4: percpu nh_rth_output cache
From: Eric Dumazet @ 2012-07-31 15:22 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Alexander Duyck
From: Eric Dumazet <edumazet@google.com>
Input path is mostly run under RCU and doesnt touch dst refcnt
But output path on forwarding or UDP workloads hits
badly dst refcount, and we have lot of false sharing, for example
in ipv4_mtu() when reading rt->rt_pmtu
Using a percpu cache for nh_rth_output gives a nice performance
increase at a small cost.
24 udpflood test on my 24 cpu machine (dummy0 output device)
(each process sends 1.000.000 udp frames, 24 processes are started)
before : 5.24 s
after : 2.06 s
For reference, time on linux-3.5 : 6.60 s
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
On top on previous "ipv4: Restore old dst_free() behavior" patch
We probably can remove all paddings in struct dst_entry
include/net/ip_fib.h | 3 ++-
net/ipv4/fib_semantics.c | 19 ++++++++++++++++++-
net/ipv4/route.c | 20 +++++++++++++++-----
3 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index e521a03..a0f003d 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -21,6 +21,7 @@
#include <linux/rcupdate.h>
#include <net/fib_rules.h>
#include <net/inetpeer.h>
+#include <linux/percpu.h>
struct fib_config {
u8 fc_dst_len;
@@ -81,7 +82,7 @@ struct fib_nh {
__be32 nh_gw;
__be32 nh_saddr;
int nh_saddr_genid;
- struct rtable __rcu *nh_rth_output;
+ struct rtable * __percpu *nh_pcpu_rth_output;
struct rtable __rcu *nh_rth_input;
struct fnhe_hash_bucket *nh_exceptions;
};
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 625cf18..c8bf86e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -176,6 +176,22 @@ static void rt_nexthop_free(struct rtable __rcu **rtp)
dst_free(&rt->dst);
}
+static void rt_nexthop_free_cpus(struct rtable * __percpu *rtp)
+{
+ int cpu;
+
+ if (!rtp)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ struct rtable *rt = *per_cpu_ptr(rtp, cpu);
+
+ if (rt)
+ dst_free(&rt->dst);
+ }
+ free_percpu(rtp);
+}
+
/* Release a nexthop info record */
static void free_fib_info_rcu(struct rcu_head *head)
{
@@ -186,7 +202,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
dev_put(nexthop_nh->nh_dev);
if (nexthop_nh->nh_exceptions)
free_nh_exceptions(nexthop_nh);
- rt_nexthop_free(&nexthop_nh->nh_rth_output);
+ rt_nexthop_free_cpus(nexthop_nh->nh_pcpu_rth_output);
rt_nexthop_free(&nexthop_nh->nh_rth_input);
} endfor_nexthops(fi);
@@ -817,6 +833,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
fi->fib_nhs = nhs;
change_nexthops(fi) {
nexthop_nh->nh_parent = fi;
+ nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable *);
} endfor_nexthops(fi)
if (cfg->fc_mx) {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 2bd1074..d5efcfe 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1206,11 +1206,16 @@ static inline void rt_free(struct rtable *rt)
static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
{
- struct rtable *orig, *prev, **p = (struct rtable **)&nh->nh_rth_output;
+ struct rtable *orig, *prev, **p;
- if (rt_is_input_route(rt))
+ if (rt_is_input_route(rt)) {
p = (struct rtable **)&nh->nh_rth_input;
-
+ } else {
+ if (!nh->nh_pcpu_rth_output)
+ goto nocache;
+ p = per_cpu_ptr(nh->nh_pcpu_rth_output,
+ raw_smp_processor_id());
+ }
orig = *p;
prev = cmpxchg(p, orig, rt);
@@ -1223,6 +1228,7 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
* unsuccessful at storing this route into the cache
* we really need to set it.
*/
+nocache:
rt->dst.flags |= DST_NOCACHE;
}
}
@@ -1749,8 +1755,12 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
fnhe = NULL;
if (fi) {
fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
- if (!fnhe) {
- rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_output);
+ if (!fnhe && FIB_RES_NH(*res).nh_pcpu_rth_output) {
+ struct rtable **prth;
+
+ prth = per_cpu_ptr(FIB_RES_NH(*res).nh_pcpu_rth_output,
+ raw_smp_processor_id());
+ rth = rcu_dereference(*(__force __rcu struct rtable **)prth);
if (rt_cache_valid(rth)) {
dst_hold(&rth->dst);
return rth;
^ permalink raw reply related
* [PATCH iproute2 2/2] em_canid: Ematch used to classify CAN frames according to their identifiers
From: Rostislav Lisovy @ 2012-07-31 14:46 UTC (permalink / raw)
To: netdev; +Cc: linux-can, pisa, sojkam1, Rostislav Lisovy
In-Reply-To: <1343745981-14248-1-git-send-email-lisovy@gmail.com>
This ematch enables effective filtering of CAN frames (AF_CAN) based
on CAN identifiers with masking of compared bits. Implementation
utilizes bitmap based classification for standard frame format (SFF)
which is optimized for minimal overhead.
Signed-off-by: Rostislav Lisovy <lisovy@gmail.com>
---
etc/iproute2/ematch_map | 1 +
include/linux/pkt_cls.h | 6 +-
tc/Makefile | 1 +
tc/em_canid.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 197 insertions(+), 2 deletions(-)
create mode 100644 tc/em_canid.c
diff --git a/etc/iproute2/ematch_map b/etc/iproute2/ematch_map
index 7c6a281..8d08613 100644
--- a/etc/iproute2/ematch_map
+++ b/etc/iproute2/ematch_map
@@ -3,3 +3,4 @@
2 nbyte
3 u32
4 meta
+7 canid
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index defbde2..082eafa 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -451,8 +451,10 @@ enum {
#define TCF_EM_U32 3
#define TCF_EM_META 4
#define TCF_EM_TEXT 5
-#define TCF_EM_VLAN 6
-#define TCF_EM_MAX 6
+#define TCF_EM_VLAN 6
+#define TCF_EM_CANID 7
+#define TCF_EM_IPSET 8
+#define TCF_EM_MAX 8
enum {
TCF_EM_PROG_TC
diff --git a/tc/Makefile b/tc/Makefile
index 64d93ad..bfdcf9f 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -45,6 +45,7 @@ TCMODULES += p_udp.o
TCMODULES += em_nbyte.o
TCMODULES += em_cmp.o
TCMODULES += em_u32.o
+TCMODULES += em_canid.o
TCMODULES += em_meta.o
TCMODULES += q_mqprio.o
TCMODULES += q_codel.o
diff --git a/tc/em_canid.c b/tc/em_canid.c
new file mode 100644
index 0000000..16f6ed5
--- /dev/null
+++ b/tc/em_canid.c
@@ -0,0 +1,191 @@
+/*
+ * em_canid.c Ematch rule to match CAN frames according to their CAN identifiers
+ *
+ * This program is free software; you can distribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Idea: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Copyright: (c) 2011 Czech Technical University in Prague
+ * (c) 2011 Volkswagen Group Research
+ * Authors: Michal Sojka <sojkam1@fel.cvut.cz>
+ * Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Rostislav Lisovy <lisovy@gmail.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * Documentation: http://rtime.felk.cvut.cz/can/socketcan-qdisc-final.pdf
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/can.h>
+#include <inttypes.h>
+#include "m_ematch.h"
+
+#define EM_CANID_RULES_MAX 400 /* Main reason for this number is Nelink
+ message size limit equal to Single memory page size. When dump()
+ is invoked, there are even some ematch related headers sent from
+ kernel to userspace together with em_canid configuration --
+ 400*sizeof(struct can_filter) should fit without any problems */
+
+extern struct ematch_util canid_ematch_util;
+struct rules {
+ struct can_filter *rules_raw;
+ int rules_capacity; /* Size of array allocated for rules_raw */
+ int rules_cnt; /* Actual number of rules stored in rules_raw */
+};
+
+static void canid_print_usage(FILE *fd)
+{
+ fprintf(fd,
+ "Usage: canid(IDLIST)\n" \
+ "where: IDLIST := IDSPEC [ IDLIST ]\n" \
+ " IDSPEC := { ’sff’ CANID | ’eff’ CANID }\n" \
+ " CANID := ID[:MASK]\n" \
+ " ID, MASK := hexadecimal number (i.e. 0x123)\n" \
+ "Example: canid(sff 0x123 sff 0x124 sff 0x125:0xf)\n");
+}
+
+static int canid_parse_rule(struct rules *rules, struct bstr *a, int iseff)
+{
+ unsigned int can_id = 0;
+ unsigned int can_mask = 0;
+
+ if (sscanf(a->data, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
+ if (sscanf(a->data, "%"SCNx32, &can_id) != 1) {
+ return -1;
+ } else {
+ can_mask = (iseff) ? CAN_EFF_MASK : CAN_SFF_MASK;
+ }
+ }
+
+ /* Stretch rules array up to EM_CANID_RULES_MAX if necessary */
+ if (rules->rules_cnt == rules->rules_capacity) {
+ if (rules->rules_capacity <= EM_CANID_RULES_MAX/2) {
+ rules->rules_capacity *= 2;
+ rules->rules_raw = realloc(rules->rules_raw,
+ sizeof(struct can_filter) * rules->rules_capacity);
+ } else {
+ return -2;
+ }
+ }
+
+ rules->rules_raw[rules->rules_cnt].can_id =
+ can_id | ((iseff) ? CAN_EFF_FLAG : 0);
+ rules->rules_raw[rules->rules_cnt].can_mask =
+ can_mask | CAN_EFF_FLAG;
+
+ rules->rules_cnt++;
+
+ return 0;
+}
+
+static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
+ struct bstr *args)
+{
+ int iseff = 0;
+ int ret = 0;
+ struct rules rules = {
+ .rules_capacity = 25, /* Denominator of EM_CANID_RULES_MAX
+ Will be multiplied by 2 to calculate the size for realloc() */
+ .rules_cnt = 0
+ };
+
+#define PARSE_ERR(CARG, FMT, ARGS...) \
+ em_parse_error(EINVAL, args, CARG, &canid_ematch_util, FMT, ##ARGS)
+
+ if (args == NULL)
+ return PARSE_ERR(args, "canid: missing arguments");
+
+ rules.rules_raw = malloc(sizeof(struct can_filter) * rules.rules_capacity);
+ memset(rules.rules_raw, 0, sizeof(struct can_filter) * rules.rules_capacity);
+
+ do {
+ if (!bstrcmp(args, "sff")) {
+ iseff = 0;
+ } else if (!bstrcmp(args, "eff")) {
+ iseff = 1;
+ } else {
+ ret = PARSE_ERR(args, "canid: invalid key");
+ goto exit;
+ }
+
+ args = bstr_next(args);
+ if (args == NULL) {
+ ret = PARSE_ERR(args, "canid: missing argument");
+ goto exit;
+ }
+
+ ret = canid_parse_rule(&rules, args, iseff);
+ if (ret == -1) {
+ ret = PARSE_ERR(args, "canid: Improperly formed CAN ID & mask\n");
+ goto exit;
+ } else if (ret == -2) {
+ ret = PARSE_ERR(args, "canid: Too many arguments on input\n");
+ goto exit;
+ }
+ } while ((args = bstr_next(args)) != NULL);
+
+ addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
+ addraw_l(n, MAX_MSG, rules.rules_raw,
+ sizeof(struct can_filter) * rules.rules_cnt);
+
+#undef PARSE_ERR
+exit:
+ free(rules.rules_raw);
+ return ret;
+}
+
+static int canid_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
+ int data_len)
+{
+ struct can_filter *conf = data; /* Array with rules */
+ int rules_count;
+ int i;
+
+ rules_count = data_len / sizeof(struct can_filter);
+
+ for (i = 0; i < rules_count; i++) {
+ struct can_filter *pcfltr = &conf[i];
+
+ if (pcfltr->can_id & CAN_EFF_FLAG) {
+ if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_EFF_MASK))
+ fprintf(fd, "eff 0x%"PRIX32,
+ pcfltr->can_id & CAN_EFF_MASK);
+ else
+ fprintf(fd, "eff 0x%"PRIX32":0x%"PRIX32,
+ pcfltr->can_id & CAN_EFF_MASK,
+ pcfltr->can_mask & CAN_EFF_MASK);
+ } else {
+ if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_SFF_MASK))
+ fprintf(fd, "sff 0x%"PRIX32,
+ pcfltr->can_id & CAN_SFF_MASK);
+ else
+ fprintf(fd, "sff 0x%"PRIX32":0x%"PRIX32,
+ pcfltr->can_id & CAN_SFF_MASK,
+ pcfltr->can_mask & CAN_SFF_MASK);
+ }
+
+ if ((i + 1) < rules_count)
+ fprintf(fd, " ");
+ }
+
+ return 0;
+}
+
+struct ematch_util canid_ematch_util = {
+ .kind = "canid",
+ .kind_num = TCF_EM_CANID,
+ .parse_eopt = canid_parse_eopt,
+ .print_eopt = canid_print_eopt,
+ .print_usage = canid_print_usage
+};
--
1.7.10.4
^ permalink raw reply related
* [PATCH iproute2 1/2] Add missing can.h
From: Rostislav Lisovy @ 2012-07-31 14:46 UTC (permalink / raw)
To: netdev; +Cc: linux-can, pisa, sojkam1, Rostislav Lisovy
Header file used when working with AF_CAN frames -- generated from
linux kernel 3.5+
Signed-off-by: Rostislav Lisovy <lisovy@gmail.com>
---
include/linux/can.h | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 include/linux/can.h
diff --git a/include/linux/can.h b/include/linux/can.h
new file mode 100644
index 0000000..018055e
--- /dev/null
+++ b/include/linux/can.h
@@ -0,0 +1,161 @@
+/*
+ * linux/can.h
+ *
+ * Definitions for CAN network layer (socket addr / CAN frame / CAN filter)
+ *
+ * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Urs Thuermann <urs.thuermann@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ */
+
+#ifndef CAN_H
+#define CAN_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* controller area network (CAN) kernel definitions */
+
+/* special address description flags for the CAN_ID */
+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define CAN_ERR_FLAG 0x20000000U /* error message frame */
+
+/* valid bits in CAN ID for frame formats */
+#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
+#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
+#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
+
+/*
+ * Controller Area Network Identifier structure
+ *
+ * bit 0-28 : CAN identifier (11/29 bit)
+ * bit 29 : error message frame flag (0 = data frame, 1 = error message)
+ * bit 30 : remote transmission request flag (1 = rtr frame)
+ * bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef __u32 canid_t;
+
+#define CAN_SFF_ID_BITS 11
+#define CAN_EFF_ID_BITS 29
+
+/*
+ * Controller Area Network Error Message Frame Mask structure
+ *
+ * bit 0-28 : error class mask (see include/linux/can/error.h)
+ * bit 29-31 : set to zero
+ */
+typedef __u32 can_err_mask_t;
+
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
+#define CANFD_MAX_DLC 15
+#define CANFD_MAX_DLEN 64
+
+/**
+ * struct can_frame - basic CAN frame structure
+ * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
+ * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
+ * mapping of the 'data length code' to the real payload length
+ * @data: CAN frame payload (up to 8 byte)
+ */
+struct can_frame {
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ __u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
+ __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/*
+ * defined bits for canfd_frame.flags
+ *
+ * As the default for CAN FD should be to support the high data rate in the
+ * payload section of the frame (HDR) and to support up to 64 byte in the
+ * data section (EDL) the bits are only set in the non-default case.
+ * Btw. as long as there's no real implementation for CAN FD network driver
+ * these bits are only preliminary.
+ *
+ * RX: NOHDR/NOEDL - info about received CAN FD frame
+ * ESI - bit from originating CAN controller
+ * TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller
+ * ESI - bit is set by local CAN controller
+ */
+#define CANFD_NOHDR 0x01 /* frame without high data rate */
+#define CANFD_NOEDL 0x02 /* frame without extended data length */
+#define CANFD_ESI 0x04 /* error state indicator */
+
+/**
+ * struct canfd_frame - CAN flexible data rate frame structure
+ * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN)
+ * @flags: additional flags for CAN FD
+ * @__res0: reserved / padding
+ * @__res1: reserved / padding
+ * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte)
+ */
+struct canfd_frame {
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ __u8 len; /* frame payload length in byte */
+ __u8 flags; /* additional flags for CAN FD */
+ __u8 __res0; /* reserved / padding */
+ __u8 __res1; /* reserved / padding */
+ __u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+#define CAN_MTU (sizeof(struct can_frame))
+#define CANFD_MTU (sizeof(struct canfd_frame))
+
+/* particular protocols of the protocol family PF_CAN */
+#define CAN_RAW 1 /* RAW sockets */
+#define CAN_BCM 2 /* Broadcast Manager */
+#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */
+#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */
+#define CAN_MCNET 5 /* Bosch MCNet */
+#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */
+#define CAN_NPROTO 7
+
+#define SOL_CAN_BASE 100
+
+/**
+ * struct sockaddr_can - the sockaddr structure for CAN sockets
+ * @can_family: address family number AF_CAN.
+ * @can_ifindex: CAN network interface index.
+ * @can_addr: protocol specific address information
+ */
+struct sockaddr_can {
+ __kernel_sa_family_t can_family;
+ int can_ifindex;
+ union {
+ /* transport protocol class address information (e.g. ISOTP) */
+ struct { canid_t rx_id, tx_id; } tp;
+
+ /* reserved for future CAN protocols address information */
+ } can_addr;
+};
+
+/**
+ * struct can_filter - CAN ID based filter in can_register().
+ * @can_id: relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ * <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
+ */
+struct can_filter {
+ canid_t can_id;
+ canid_t can_mask;
+};
+
+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+
+#endif /* CAN_H */
--
1.7.10.4
^ permalink raw reply related
* CPU: 0 Not tainted (3.1.9+ #1) when ifconfig rose0 down
From: Bernard Pidoux @ 2012-07-31 14:11 UTC (permalink / raw)
To: linux-hams, Linux Netdev List
Hi,
I observe systematically a kernel panic when I try to shutdown rose0
device using ifconfig rose0 down
This is happening on two very different ROSE implementation, one is on a
machine with x86-64 kernel 4.6.3 on an Intel core 2 duo CPU
the other is on a RaspBerry Pi with Raspbian and 3.1.9+ wheezy kernel
recompiled with AX.25 modules (ax25, rose, netrom, 6pack, kiss) enabled.
Here is an image of the screen dump :
http://f6bvp.org/photos/rose_device_event.JPG
It can be noticed that PC is at rose_device_event and
LR is at sock_def_wakeup
One thing to be noticed is that when I close before all ROSE and AX.25
applications, there are still a few populated sockets, probably for one
of the program did not close the sockets properly.
I that case, does rose module should accept to shutdown rose0 device ?
However, I guess that it should not create a kernel panic due to a
kernel NULL pointer.
I don't know what to do in order to debug that issue.
Bernard
^ permalink raw reply
* Re: TCP stalls with 802.3ad + bridge + kvm guest
From: Peter Samuelson @ 2012-07-31 14:07 UTC (permalink / raw)
To: Jay Vosburgh, netdev; +Cc: jgoerzen
In-Reply-To: <26496.1343419205@death.nxdomain>
> > ixgbe [10 Gbit port] -- bonding [802.3ad] -- bridge -- KVM guest
> >
> >(There's also a VLAN layer, but I can reproduce this problem without
> >it.) It all works, except that with some flows in the KVM guest - I
> >can reproduce using smbclient - transfers keep stalling, such that I'm
> >averaging well under 1 MB/s. Should be more like 100 MB/s.
> >
> >Oddly, this only occurs when both the 802.3ad and KVM are used:
> >
> > Server Agg Client TCP stalls
> > --------------------------------------------------
> > external none KVM guest no
> > external 802.3ad KVM host no
> > KVM host 802.3ad KVM guest no
> > external 802.3ad KVM guest yes
[Jay Vosburgh]
> Does the "none" for Agg (the first line) mean no bonding at all?
Correct. 'None' is without the bonding driver, putting the eth
interface directly on the bridge. (With or without a VLAN layer.)
> Does the problem happen if the bond is a different mode
> (balance-xor, for example)?
This is taking me longer to test, as I have to also update the switch
port config, which required coordination with coworkers. I'll get that
info as soon as I can.
> Do the various stats on the host and guest show any drops?
> E.g., from "netstat -i" and "tc -s qdisc"
Yes, 'netstat -i' on the KVM host shows a few dropped RX packets on
bond0 - looks like it increments by 2 each time I do a test download of
my 20MB file. 'tc -s qdisc' on the KVM host shows nothing, and I see
no drops on the KVM guest side.
I'll get the switch reconfigured not to do LACP so I can test other
bonding modes, as you suggest. Thanks for the quick response! Sorry
my own followup was delayed....
Peter
^ permalink raw reply
* Re: [RFC v2 1/2] PCI-Express Non-Transparent Bridge Support
From: Bjorn Helgaas @ 2012-07-31 13:45 UTC (permalink / raw)
To: Jon Mason; +Cc: linux-kernel, netdev, linux-pci, Dave Jiang
In-Reply-To: <20120730181542.GA987@jonmason-lab>
On Mon, Jul 30, 2012 at 12:15 PM, Jon Mason <jon.mason@intel.com> wrote:
> On Mon, Jul 30, 2012 at 10:50:13AM -0600, Bjorn Helgaas wrote:
>> On Sun, Jul 29, 2012 at 6:26 PM, Jon Mason <jon.mason@intel.com> wrote:
>> > A PCI-Express non-transparent bridge (NTB) is a point-to-point PCIe bus
>> > connecting 2 systems, providing electrical isolation between the two subsystems.
>> > A non-transparent bridge is functionally similar to a transparent bridge except
>> > that both sides of the bridge have their own independent address domains. The
>> > host on one side of the bridge will not have the visibility of the complete
>> > memory or I/O space on the other side of the bridge. To communicate across the
>> > non-transparent bridge, each NTB endpoint has one (or more) apertures exposed to
>> > the local system. Writes to these apertures are mirrored to memory on the
>> > remote system. Communications can also occur through the use of doorbell
>> > registers that initiate interrupts to the alternate domain, and scratch-pad
>> > registers accessible from both sides.
>> >
>> > The NTB device driver is needed to configure these memory windows, doorbell, and
>> > scratch-pad registers as well as use them in such a way as they can be turned
>> > into a viable communication channel to the remote system. ntb_hw.[ch]
>> > determines the usage model (NTB to NTB or NTB to Root Port) and abstracts away
>> > the underlying hardware to provide access and a common interface to the doorbell
>> > registers, scratch pads, and memory windows. These hardware interfaces are
>> > exported so that other, non-mainlined kernel drivers can access these.
>> > ntb_transport.[ch] also uses the exported interfaces in ntb_hw.[ch] to setup a
>> > communication channel(s) and provide a reliable way of transferring data from
>> > one side to the other, which it then exports so that "client" drivers can access
>> > them. These client drivers are used to provide a standard kernel interface
>> > (i.e., Ethernet device) to NTB, such that Linux can transfer data from one
>> > system to the other in a standard way.
>> >
>> > Signed-off-by: Jon Mason <jon.mason@intel.com>
>> > ---
>> > MAINTAINERS | 6 +
>> > drivers/Kconfig | 2 +
>> > drivers/Makefile | 1 +
>> > drivers/ntb/Kconfig | 13 +
>> > drivers/ntb/Makefile | 3 +
>> > drivers/ntb/ntb_hw.c | 1178 ++++++++++++++++++++++++++++++++++++
>> > drivers/ntb/ntb_hw.h | 206 +++++++
>> > drivers/ntb/ntb_regs.h | 150 +++++
>> > drivers/ntb/ntb_transport.c | 1387 +++++++++++++++++++++++++++++++++++++++++++
>> > include/linux/ntb.h | 92 +++
>>
>> Where will drivers for non-Intel NTBs fit in this hierarchy? It seems
>> a bit presumptuous to claim the generic "ntb" names just for Intel
>> devices.
>
> I've tried to make it all generic enough that non-Intel NTBs should plug in with
> minimal changes to ntb_hw.c. If their design is too divergent, then a slight
> redesign of ntb_hw.c might be necessary. But from what I've seen of other
> designs on the internet, they appear to be extremely similar. The transport and
> client drivers were written with the hardware abstracted away as much as
> possible to prevent the need to modify it for different hardware. If there is
> anything which is Intel hardware specific, I'd be happy to change it to make it
> more generic.
That makes sense from a technical point of view, but I think it's
going to cause maintenance issues. For example, assume PLX NTB
support is added. Will PLX be happy about having to convince you to
accept changes? Will Intel be happy about having to release a new
driver for their hardware just to incorporate a PLX bug fix? Will
users of PLX hardware accept a new driver release that only benefits
Intel users?
^ permalink raw reply
* Re: [PATCH] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Wolfgang Grandegger @ 2012-07-31 13:43 UTC (permalink / raw)
To: Olivier Sobrie; +Cc: Marc Kleine-Budde, linux-can, netdev
In-Reply-To: <20120731130650.GA23541@hposo>
On 07/31/2012 03:06 PM, Olivier Sobrie wrote:
> On Tue, Jul 31, 2012 at 11:56:22AM +0200, Marc Kleine-Budde wrote:
...
>> Please test Bus-Off behaviour:
>> - setup working CAN network
>> - short circuit CAN-H and CAN-L wires
>> - start "candump any,0:0,#FFFFFFFF" on one shell
>> - send one can frame on the other
>>
>> then
>>
>> - remove the short circuit
>> - see if the can frame is transmitted to the other side
>> - it should show up as an echo'ed CAN frame on the sender side
>>
>> Repeat the same test with disconnecting CAN-H and CAN-L from the other
>> CAN station instead of short circuit.
>>
>> Please send the output from candump.
>
> 1) With the short circuit:
>
> I perform the test you described. It showed that the Kvaser passes from
> ERROR-WARNING to ERROR-PASSIVE and then BUS-OFF. But after going to the
> state BUS-OFF it comes back to ERROR-WARNING.
You can use the option "-e" to get a human readable output.
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
A state change (0x10 here) should only be reported once.
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> ...
> can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME <-- bus off
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> ...
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 123 [2] 11 22 <-- short circuit removed
>
> I see the echo and on the other end I see the frame coming in.
> By the way I see that the txerr and rxerr fields of the structure
> kvaser_msg_error_event stay at 0.
If possible, they should be set for any CAN error message.
>
> 2) With CAN-H and CAN-L disconnected:
>
> I never see the bus going in OFF state. It stays in PASSIVE mode.
That is the correct behavior. You should get ACK slot (and not ACK
delimiter), IIRC.
I'm offline for the rest of the week. I will have a closer look next
week (to your next version(s)).
Wolfgang.
^ permalink raw reply
* Re: [PATCH 1/2] net: Allow to create links with given ifindex
From: Pavel Emelyanov @ 2012-07-31 13:30 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Linux Netdev List, David Miller
In-Reply-To: <878ve0dtw3.fsf@xmission.com>
>> First, let's imagine that on host A the loopback device got registered as
>> first device, but on host B for some reason some other device got registered
>> first. In that case after migration from A to B the lo on B will have index
>> equals 2. And there's no any strict requirement that lo's per net operations
>> are registered first. Please, correct me if I'm wrong.
>
> Actually there is a hard requirement that the loopback device be the
> last device in a network namespace to be unregistered. We meet that
> requirement by registering the loopback device first
> "net/core/dev.c:net_dev_init()".
Hm... Indeed, and this is good news!
>> Next. In fact, lo is not the only problem. Look at the e.g. sit versus ipgre
>> fallback devices. Both gets created on netns creation and obtain whatever
>> ifindices are generated for them. Even if we make ifidex per netns chances
>> that sit gets registered _strictly_ before ipgre equal zero, since they are
>> both modules.
>
> True. However those fallback devices should no longer be needed,
> and even if they are I think you can delete and recreate them.
Good idea! I will look at that direction.
> Making lo the particularly interesting case.
Yup, provided we can manually recreate those auto-created devices this solves
the issue.
>> Just an idea -- is it worth moving the possibility to have ifindidces intersect
>> under CONFIG_<SOMETHING> (EXPERT/CHECKPOINT_RESTORE) to let wider audience check
>> the code in real-life?
>
> I think the best testing we are going to get diversity wise is to create
> a per netns counter into dev_new_index when net-next opens up.
>
> Having an ifindex that we can only set at netdevice creation time seems
> reasonable.
OK, thank you, Eric.
> Eric
> .
>
Thanks,
Pavel
^ permalink raw reply
* Re: [PATCH] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Marc Kleine-Budde @ 2012-07-31 13:27 UTC (permalink / raw)
To: Olivier Sobrie; +Cc: Wolfgang Grandegger, linux-can, netdev
In-Reply-To: <20120731130650.GA23541@hposo>
[-- Attachment #1: Type: text/plain, Size: 10413 bytes --]
On 07/31/2012 03:06 PM, Olivier Sobrie wrote:
[...]
>>>> Please check if your driver survives hot-unplugging while sending and
>>>> receiving CAN frames at maximum laod.
>>>
>>> I tested this with two Kvaser sending frames with "cangen can0 -g 0 -i"
>>> never saw a crash.
>>
>> Please test send sending and receiving at the same time.
>
> Yes that's what I did; "cangen can0 -g 0 -i" on both sides.
Fine.
[...]
>>>>> --- /dev/null
>>>>> +++ b/drivers/net/can/usb/kvaser_usb.c
>>>>> @@ -0,0 +1,1062 @@
>>>>> +/*
>>>>
>>>> Please add a license statement and probably your copyright:
>>>>
>>>> * This program is free software; you can redistribute it and/or
>>>> * modify it under the terms of the GNU General Public License as
>>>> * published by the Free Software Foundation version 2.
>>>>
>>>> You also should copy the copyright from the drivers you used:
>>>>
>>>>> + * Parts of this driver are based on the following:
>>>>> + * - Kvaser linux leaf driver (version 4.78)
>>>>
>>>> I just downloaded their driver and noticed that it's quite sparse on
>>>> stating the license the code is released under.
>>>> "doc/HTMLhelp/copyright.htx" is quite restrictive, the word GPL occurs 3
>>>> times, all in MODULE_LICENSE("GPL"). Running modinfo on the usbcan.ko
>>>> shows "license: GPL"
>>>
>>> I'll add the license statement.
>>> In fact it's the leaf.ko which is used for this device and it is under
>>> GPL as modinfo said.
>>
>> I just talked to my boss and we're the same opinion, that
>> MODULE_LICENSE("GPL") is a technical term and not relevant if the
>> included license doesn't say a word about GPL. If the kvaser tarball
>> violates the GPL, however is written on different sheet of paper (as we
>> say in Germany).
>>
>> So I cannot put my S-o-b under this driver as long as we haven't talked
>> to kvaser.
>
> Ok I thought it was sufficient enough to have MODULE_LICENSE("GPL") in
> the code to indicate it is a GPL driver. I'll ask Kvaser before sending
> any new version of the patch.
We can continue the review process, this problem has to be sorted out
before I can apply this patch to linux-can-next tree.
[...]
>>>>> +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>>>>> + const struct kvaser_msg *msg)
>>>>> +{
>>>>> + struct can_frame *cf;
>>>>> + struct sk_buff *skb;
>>>>> + struct net_device_stats *stats;
>>>>> + struct kvaser_usb_net_priv *priv;
>>>>> + u8 channel, status, txerr, rxerr;
>>>>> +
>>>>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
>>>>> + channel = msg->u.error_event.channel;
>>>>> + status = msg->u.error_event.status;
>>>>> + txerr = msg->u.error_event.tx_errors_count;
>>>>> + rxerr = msg->u.error_event.rx_errors_count;
>>>>> + } else {
>>>>> + channel = msg->u.chip_state_event.channel;
>>>>> + status = msg->u.chip_state_event.status;
>>>>> + txerr = msg->u.chip_state_event.tx_errors_count;
>>>>> + rxerr = msg->u.chip_state_event.rx_errors_count;
>>>>> + }
>>>>> +
>>>>> + if (channel >= dev->nchannels) {
>>>>> + dev_err(dev->udev->dev.parent,
>>>>> + "Invalid channel number (%d)\n", channel);
>>>>> + return;
>>>>> + }
>>>>> +
>>>>> + priv = dev->nets[channel];
>>>>> + stats = &priv->netdev->stats;
>>>>> +
>>>>> + skb = alloc_can_err_skb(priv->netdev, &cf);
>>>>> + if (!skb) {
>>>>> + stats->rx_dropped++;
>>>>> + return;
>>>>> + }
>>>>> +
>>>>> + if ((status & M16C_STATE_BUS_OFF) ||
>>>>> + (status & M16C_STATE_BUS_RESET)) {
>>>>> + priv->can.state = CAN_STATE_BUS_OFF;
>>>>> + cf->can_id |= CAN_ERR_BUSOFF;
>>>>> + can_bus_off(priv->netdev);
>>
>> you should increment priv->can.can_stats.bus_off
>> What does the firmware do in this state? Does it automatically try to
>> recover and try to send the outstanding frames?
>
> Yes that's what I observed.
It's behaves like the at91_can.
>> If so, you should turn of the CAN interface, it possible. See:
>> http://lxr.free-electrons.com/source/drivers/net/can/at91_can.c#L986
>
> Ok I'll have a look at this.
>
>>
>> Please test Bus-Off behaviour:
>> - setup working CAN network
>> - short circuit CAN-H and CAN-L wires
>> - start "candump any,0:0,#FFFFFFFF" on one shell
>> - send one can frame on the other
>>
>> then
>>
>> - remove the short circuit
>> - see if the can frame is transmitted to the other side
>> - it should show up as an echo'ed CAN frame on the sender side
>>
>> Repeat the same test with disconnecting CAN-H and CAN-L from the other
>> CAN station instead of short circuit.
>>
>> Please send the output from candump.
>
> 1) With the short circuit:
>
> I perform the test you described. It showed that the Kvaser passes from
> ERROR-WARNING to ERROR-PASSIVE and then BUS-OFF. But after going to the
> state BUS-OFF it comes back to ERROR-WARNING.
>
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
Why don't we have any rx/tx numbers in the error frame?
> ...
> can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME <-- bus off
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> ...
> can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> can1 123 [2] 11 22 <-- short circuit removed
>
> I see the echo and on the other end I see the frame coming in.
> By the way I see that the txerr and rxerr fields of the structure
> kvaser_msg_error_event stay at 0.
>
> 2) With CAN-H and CAN-L disconnected:
>
> I never see the bus going in OFF state. It stays in PASSIVE mode.
>
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> ...
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
> can1 123 [2] 11 22 <-- other end connected
From the hardware point of view the short circuit and open end tests
look good. Please adjust the driver to turn off the CAN interface in
case of a bus off if restart_ms is 0.
>>>>> + } else if (status & M16C_STATE_BUS_ERROR) {
>>>>> + priv->can.state = CAN_STATE_ERROR_WARNING;
>>>>> + priv->can.can_stats.error_warning++;
>>>>> + } else if (status & M16C_STATE_BUS_PASSIVE) {
>>>>> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
>>>>> + priv->can.can_stats.error_passive++;
>>>>> + } else {
>>>>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
>>>>> + cf->can_id |= CAN_ERR_PROT;
>>>>> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
>>>>> + }
>>>>> +
>>>>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
>>>>> + u8 error_factor = msg->u.error_event.error_factor;
>>>>> +
>>>>> + priv->can.can_stats.bus_error++;
>>>>> + stats->rx_errors++;
>>>>> +
>>>>> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
>>>>> +
>>>>> + if ((priv->can.state == CAN_STATE_ERROR_WARNING) ||
>>>>> + (priv->can.state == CAN_STATE_ERROR_PASSIVE)) {
>>>>> + cf->data[1] = (txerr > rxerr) ?
>>>>> + CAN_ERR_CRTL_TX_PASSIVE
>>>>> + : CAN_ERR_CRTL_RX_PASSIVE;
Please use CAN_ERR_CRTL_RX_WARNING, CAN_ERR_CRTL_TX_WARNING where
appropriate.
>>>>> + }
>>>>> +
>>>>> + if (error_factor & M16C_EF_ACKE)
>>>>> + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
>>>>> + CAN_ERR_PROT_LOC_ACK_DEL);
>>>>> + if (error_factor & M16C_EF_CRCE)
>>>>> + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
>>>>> + CAN_ERR_PROT_LOC_CRC_DEL);
>>>>> + if (error_factor & M16C_EF_FORME)
>>>>> + cf->data[2] |= CAN_ERR_PROT_FORM;
>>>>> + if (error_factor & M16C_EF_STFE)
>>>>> + cf->data[2] |= CAN_ERR_PROT_STUFF;
>>>>> + if (error_factor & M16C_EF_BITE0)
>>>>> + cf->data[2] |= CAN_ERR_PROT_BIT0;
>>>>> + if (error_factor & M16C_EF_BITE1)
>>>>> + cf->data[2] |= CAN_ERR_PROT_BIT1;
>>>>> + if (error_factor & M16C_EF_TRE)
>>>>> + cf->data[2] |= CAN_ERR_PROT_TX;
>>>>> + }
>>>>> +
>>>>> + cf->data[6] = txerr;
>>>>> + cf->data[7] = rxerr;
>>>>> +
>>>>> + netif_rx(skb);
>>>>> +
>>>>> + priv->bec.txerr = txerr;
>>>>> + priv->bec.rxerr = rxerr;
>>>>> +
>>>>> + stats->rx_packets++;
>>>>> + stats->rx_bytes += cf->can_dlc;
>>>>> +}
>>>>> +
[...]
>>>>> +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
>>>>> + struct can_berr_counter *bec)
>>>>> +{
>>>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>>>> +
>>>>> + bec->txerr = priv->bec.txerr;
>>>>> + bec->rxerr = priv->bec.rxerr;
I think you can copy the struct like this:
*bec = priv->bec;
>>>>> +
>>>>> + return 0;
>>>>> +}
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: [PATCH] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Olivier Sobrie @ 2012-07-31 13:06 UTC (permalink / raw)
To: Marc Kleine-Budde; +Cc: Wolfgang Grandegger, linux-can, netdev
In-Reply-To: <5017ABC6.7030307@pengutronix.de>
On Tue, Jul 31, 2012 at 11:56:22AM +0200, Marc Kleine-Budde wrote:
> On 07/30/2012 03:33 PM, Olivier Sobrie wrote:
> > Hi Marc,
> >
> > On Mon, Jul 30, 2012 at 01:11:46PM +0200, Marc Kleine-Budde wrote:
> >> On 07/30/2012 07:32 AM, Olivier Sobrie wrote:
> >>> This driver provides support for several Kvaser CAN/USB devices.
> >>> Such kind of devices supports up to three can network interfaces.
> >>>
> >>> It has been tested with a Kvaser USB Leaf Light (one network interface)
> >>> connected to a pch_can interface.
> >>> The firmware version of the Kvaser device was 2.5.205.
> >>
> >> Please add linux-usb@vger.kernel.org to Cc for review of the USB part.
> >
> > Ok I'll do it when I send the new version of the patch.
> > But it might be a good idea to add an entry in the MAINTAINERS file so
> > that when someone sends a patch they are aware of this when the
> > get_maintainer script is invoked.
>
> Interesting Idea. We should discuss this here, however we should not
> bother the USB List when sending USB unrelated patches.
>
> >> Please combine .h and .c file. Please make use of netdev_LEVEL() for
> >> error printing, not dev_LEVEL().
> >
> > I'll combine the .c and .h.
> > I used the netdev_LEVEL() everywhere it was possible. It requires to
> > have access to a pointer to netdev which is not always possible;
> > that's the reason why I used dev_LEVEL().
>
> I see, you used it when channel is invalid. So you have obviously no netdev.
Indeed.
>
> >> Please review if all members of the struct kvaser_msg are properly
> >> aligned. You never access the struct kvaser_msg_* members directly, as
> >> they are unaligned. Please check for le16 and le32 access. You missed to
> >> convert the bitrate.
> >
> > Indeed. Thanks. I'll check if I didn't missed another one.
>
> Tnx
>
> >> Please check if your driver survives hot-unplugging while sending and
> >> receiving CAN frames at maximum laod.
> >
> > I tested this with two Kvaser sending frames with "cangen can0 -g 0 -i"
> > never saw a crash.
>
> Please test send sending and receiving at the same time.
Yes that's what I did; "cangen can0 -g 0 -i" on both sides.
>
> >> More comments inline,
> >> regards, Marc
> >>
> >>> List of Kvaser devices supported by the driver:
> >>> - Kvaser Leaf prototype (P010v2 and v3)
> >>> - Kvaser Leaf Light (P010v3)
> >>> - Kvaser Leaf Professional HS
> >>> - Kvaser Leaf SemiPro HS
> >>> - Kvaser Leaf Professional LS
> >>> - Kvaser Leaf Professional SWC
> >>> - Kvaser Leaf Professional LIN
> >>> - Kvaser Leaf SemiPro LS
> >>> - Kvaser Leaf SemiPro SWC
> >>> - Kvaser Memorator II, Prototype
> >>> - Kvaser Memorator II HS/HS
> >>> - Kvaser USBcan Professional HS/HS
> >>> - Kvaser Leaf Light GI
> >>> - Kvaser Leaf Professional HS (OBD-II connector)
> >>> - Kvaser Memorator Professional HS/LS
> >>> - Kvaser Leaf Light "China"
> >>> - Kvaser BlackBird SemiPro
> >>> - Kvaser OEM Mercury
> >>> - Kvaser OEM Leaf
> >>> - Kvaser USBcan R
> >>>
> >>> Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
> >>> ---
> >>> drivers/net/can/usb/Kconfig | 33 ++
> >>> drivers/net/can/usb/Makefile | 1 +
> >>> drivers/net/can/usb/kvaser_usb.c | 1062 ++++++++++++++++++++++++++++++++++++++
> >>> drivers/net/can/usb/kvaser_usb.h | 237 +++++++++
> >>> 4 files changed, 1333 insertions(+)
> >>> create mode 100644 drivers/net/can/usb/kvaser_usb.c
> >>> create mode 100644 drivers/net/can/usb/kvaser_usb.h
> >>>
> >>> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> >>> index 0a68768..578955f 100644
> >>> --- a/drivers/net/can/usb/Kconfig
> >>> +++ b/drivers/net/can/usb/Kconfig
> >>> @@ -13,6 +13,39 @@ config CAN_ESD_USB2
> >>> This driver supports the CAN-USB/2 interface
> >>> from esd electronic system design gmbh (http://www.esd.eu).
> >>>
> >>> +config CAN_KVASER_USB
> >>> + tristate "Kvaser CAN/USB interface"
> >>> + ---help---
> >>> + This driver adds support for Kvaser CAN/USB devices like Kvaser
> >>> + Leaf Light.
> >>> +
> >>> + The driver gives support for the following devices:
> >>> + - Kvaser Leaf prototype (P010v2 and v3)
> >>> + - Kvaser Leaf Light (P010v3)
> >>> + - Kvaser Leaf Professional HS
> >>> + - Kvaser Leaf SemiPro HS
> >>> + - Kvaser Leaf Professional LS
> >>> + - Kvaser Leaf Professional SWC
> >>> + - Kvaser Leaf Professional LIN
> >>> + - Kvaser Leaf SemiPro LS
> >>> + - Kvaser Leaf SemiPro SWC
> >>> + - Kvaser Memorator II, Prototype
> >>> + - Kvaser Memorator II HS/HS
> >>> + - Kvaser USBcan Professional HS/HS
> >>> + - Kvaser Leaf Light GI
> >>> + - Kvaser Leaf Professional HS (OBD-II connector)
> >>> + - Kvaser Memorator Professional HS/LS
> >>> + - Kvaser Leaf Light "China"
> >>> + - Kvaser BlackBird SemiPro
> >>> + - Kvaser OEM Mercury
> >>> + - Kvaser OEM Leaf
> >>> + - Kvaser USBcan R
> >>> +
> >>> + If unsure, say N.
> >>> +
> >>> + To compile this driver as a module, choose M here: the
> >>> + module will be called kvaser_usb.
> >>> +
> >>> config CAN_PEAK_USB
> >>> tristate "PEAK PCAN-USB/USB Pro interfaces"
> >>> ---help---
> >>> diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
> >>> index da6d1d3..80a2ee4 100644
> >>> --- a/drivers/net/can/usb/Makefile
> >>> +++ b/drivers/net/can/usb/Makefile
> >>> @@ -4,6 +4,7 @@
> >>>
> >>> obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
> >>> obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
> >>> +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
> >>> obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
> >>>
> >>> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> >>> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> >>> new file mode 100644
> >>> index 0000000..4965480
> >>> --- /dev/null
> >>> +++ b/drivers/net/can/usb/kvaser_usb.c
> >>> @@ -0,0 +1,1062 @@
> >>> +/*
> >>
> >> Please add a license statement and probably your copyright:
> >>
> >> * This program is free software; you can redistribute it and/or
> >> * modify it under the terms of the GNU General Public License as
> >> * published by the Free Software Foundation version 2.
> >>
> >> You also should copy the copyright from the drivers you used:
> >>
> >>> + * Parts of this driver are based on the following:
> >>> + * - Kvaser linux leaf driver (version 4.78)
> >>
> >> I just downloaded their driver and noticed that it's quite sparse on
> >> stating the license the code is released under.
> >> "doc/HTMLhelp/copyright.htx" is quite restrictive, the word GPL occurs 3
> >> times, all in MODULE_LICENSE("GPL"). Running modinfo on the usbcan.ko
> >> shows "license: GPL"
> >
> > I'll add the license statement.
> > In fact it's the leaf.ko which is used for this device and it is under
> > GPL as modinfo said.
>
> I just talked to my boss and we're the same opinion, that
> MODULE_LICENSE("GPL") is a technical term and not relevant if the
> included license doesn't say a word about GPL. If the kvaser tarball
> violates the GPL, however is written on different sheet of paper (as we
> say in Germany).
>
> So I cannot put my S-o-b under this driver as long as we haven't talked
> to kvaser.
Ok I thought it was sufficient enough to have MODULE_LICENSE("GPL") in
the code to indicate it is a GPL driver. I'll ask Kvaser before sending
any new version of the patch.
>
> >>> + * - CAN driver for esd CAN-USB/2
> >>> + */
> >>> +
> >>> +#include <linux/init.h>
> >>> +#include <linux/completion.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/netdevice.h>
> >>> +#include <linux/usb.h>
> >>> +
> >>> +#include <linux/can.h>
> >>> +#include <linux/can/dev.h>
> >>> +#include <linux/can/error.h>
> >>> +
> >>> +#include "kvaser_usb.h"
> >>> +
> >>> +struct kvaser_usb_tx_urb_context {
> >>> + struct kvaser_usb_net_priv *priv;
> >>
> >> Huh - how does this work without forward declaration?
> >
> > It works.
>
> Yes, obviously :)
>
> > "In C and C++ it is possible to declare pointers to structs before
> > declaring their struct layout, provided the pointers are not
> > dereferenced--this is known as forward declaration."
> >
> > See http://www.linuxtopia.org/online_books/an_introduction_to_gcc/gccintro_94.html
>
> Thanks for the link.
> >>
> >>> + u32 echo_index;
> >>> + int dlc;
> >>> +};
> >>> +
> >>> +struct kvaser_usb {
> >>> + struct usb_device *udev;
> >>> + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
> >>> +
> >>> + struct usb_anchor rx_submitted;
> >>> +
> >>> + u32 fw_version;
> >>> + unsigned int nchannels;
> >>> +
> >>> + bool rxinitdone;
> >>> +};
> >>> +
> >>> +struct kvaser_usb_net_priv {
> >>> + struct can_priv can;
> >>> +
> >>> + atomic_t active_tx_urbs;
> >>> + struct usb_anchor tx_submitted;
> >>> + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
> >>> +
> >>> + int open_time;
> >>
> >> please remove open_time
> >
> > Ok.
> >
> >>
> >>> + struct completion start_stop_comp;
> >>> +
> >>> + struct kvaser_usb *dev;
> >>> + struct net_device *netdev;
> >>> + int channel;
> >>> + struct can_berr_counter bec;
> >>> +};
> >>> +
> >>> +static struct usb_device_id kvaser_usb_table[] = {
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
> >>> + .driver_info = KVASER_HAS_SILENT_MODE },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID) },
> >>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID) },
> >>> + { }
> >>> +};
> >>> +MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
> >>> +
> >>> +static int kvaser_usb_send_msg(const struct kvaser_usb *dev,
> >>> + struct kvaser_msg *msg)
> >> inline?
> >
> > Ok.
> >
> >>> +{
> >>> + int actual_len;
> >>> +
> >>> + return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 1),
> >> ^
> >> Can you please introduce a #define for this.
> >
> > Ok. No problem.
> >
> >>
> >>> + msg, msg->len, &actual_len, USB_SEND_TIMEOUT);
> >>> +}
> >>> +
> >>> +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
> >>> + struct kvaser_msg *msg)
> >>> +{
> >>> + struct kvaser_msg *tmp;
> >>> + void *buf;
> >>> + int actual_len;
> >>> + int err;
> >>> + int pos = 0;
> >>> +
> >>> + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
> >>> + if (!buf)
> >>> + return -ENOMEM;
> >>> +
> >>> + err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 129),
> >> ^^^
> >> dito
> >
> > Ok too.
> >
> >>
> >>> + buf, RX_BUFFER_SIZE, &actual_len,
> >>> + USB_RECEIVE_TIMEOUT);
> >>> + if (err < 0) {
> >>> + kfree(buf);
> >>> + return err;
> >>> + }
> >>> +
> >>> + while (pos < actual_len) {
> >>
> >> Please check that pos + sizeof(*msg) is < actual_len, as you fill access
> >> it later.
> >
> > I'll instead perform a check on 'pos + tmp->len < actual_len' and copy
> > only tmp->len instead of sizeof(*msg).
> > Thanks.
>
> Even better, saves some bytes to be copied. Take care not to deref tmp,
> unless you checked that tmp is in valid memory.
Ok. I changed the loop by 'while (pos <= actual_len - MSG_HEADER_LEN)'
and then perform the check on 'pos + tmp->len < actual_len'.
>
> >>
> >>> + tmp = buf + pos;
> >>> +
> >>> + if (!tmp->len)
> >>> + break;
> >>> +
> >>> + if (tmp->id == id) {
> >>> + memcpy(msg, tmp, sizeof(*msg));
> >>> + kfree(buf);
> >>> + return 0;
> >>> + }
> >>> +
> >>> + pos += tmp->len;
> >>> + }
> >>> +
> >>> + kfree(buf);
> >>> +
> >>> + return -EINVAL;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
> >>> + u8 msg_id, int channel)
> >>> +{
> >>> + struct kvaser_msg msg;
> >>> + int err;
> >>> +
> >>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
> >>> + msg.id = msg_id;
> >>> + msg.u.simple.channel = channel;
> >>> + msg.u.simple.tid = 0xff;
> >>
> >> Please use C99 struct initializer.
> >>
> >> struct kvaser_msg msg = {
> >> .len = ,
> >> .id =,
> >> };
> >
> > Ok.
> >
> >>
> >>
> >>> +
> >>> + err = kvaser_usb_send_msg(dev, &msg);
> >>
> >> just:
> >> return err;
> >
> > Ok.
> >
> >>
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
> >>> +{
> >>> + struct kvaser_msg msg;
> >>> + int err;
> >>> +
> >>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
> >>> +{
> >>> + struct kvaser_msg msg;
> >>> + int err;
> >>> +
> >>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + dev->nchannels = msg.u.cardinfo.nchannels;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
> >>> + const struct kvaser_msg *msg)
> >>> +{
> >>> + struct net_device_stats *stats;
> >>> + struct kvaser_usb_tx_urb_context *context;
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + u8 channel = msg->u.tx_acknowledge.channel;
> >>> + u8 tid = msg->u.tx_acknowledge.tid;
> >>> +
> >>> + if (channel >= dev->nchannels) {
> >>> + dev_err(dev->udev->dev.parent,
> >>> + "Invalid channel number (%d)\n", channel);
> >>> + return;
> >>> + }
> >>
> >> can you do a check for (channel >= dev->nchannels), in a central place?
> >> e.g. kvaser_usb_handle_message()?
> >
> > The problem is that channel is not always at the same place in the
> > messages I get from the hardware. 'tid' and 'channel' are inverted for
> > tx and rx frames.
> > e.g.
>
> Grr...who's written that firmware :D
>
> >
> > struct kvaser_msg_tx_can {
> > u8 channel;
> > u8 tid;
> > u8 msg[14];
> > u8 padding;
> > u8 flags;
> > } __packed;
> >
> > struct kvaser_msg_busparams {
> > u8 tid;
> > u8 channel;
> > __le32 bitrate;
> > u8 tseg1;
> > u8 tseg2;
> > u8 sjw;
> > u8 no_samp;
> > } __packed;
> >
> >>
> >>> +
> >>> + priv = dev->nets[channel];
> >>> +
> >>> + if (!netif_device_present(priv->netdev))
> >>> + return;
> >>> +
> >>> + stats = &priv->netdev->stats;
> >>> +
> >>> + context = &priv->tx_contexts[tid % MAX_TX_URBS];
> >>> +
> >>> + /*
> >>> + * It looks like the firmware never sets the flags field of the
> >>> + * tx_acknowledge frame and never reports a transmit failure.
> >>> + * If the can message can't be transmited (e.g. incompatible
> >>> + * bitrates), a frame CMD_CAN_ERROR_EVENT is sent (with a null
> >>> + * tid) and the firmware tries to transmit again the packet until
> >>> + * it succeeds. Once the packet is successfully transmitted, then
> >>> + * the tx_acknowledge frame is sent.
> >>> + */
> >>> +
> >>> + stats->tx_packets++;
> >>> + stats->tx_bytes += context->dlc;
> >>> + can_get_echo_skb(priv->netdev, context->echo_index);
> >>> +
> >>> + context->echo_index = MAX_TX_URBS;
> >>> + atomic_dec(&priv->active_tx_urbs);
> >>> +
> >>> + netif_wake_queue(priv->netdev);
> >>> +}
> >>> +
> >>> +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >>> + const struct kvaser_msg *msg)
> >>> +{
> >>> + struct can_frame *cf;
> >>> + struct sk_buff *skb;
> >>> + struct net_device_stats *stats;
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + u8 channel, status, txerr, rxerr;
> >>> +
> >>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
> >>> + channel = msg->u.error_event.channel;
> >>> + status = msg->u.error_event.status;
> >>> + txerr = msg->u.error_event.tx_errors_count;
> >>> + rxerr = msg->u.error_event.rx_errors_count;
> >>> + } else {
> >>> + channel = msg->u.chip_state_event.channel;
> >>> + status = msg->u.chip_state_event.status;
> >>> + txerr = msg->u.chip_state_event.tx_errors_count;
> >>> + rxerr = msg->u.chip_state_event.rx_errors_count;
> >>> + }
> >>> +
> >>> + if (channel >= dev->nchannels) {
> >>> + dev_err(dev->udev->dev.parent,
> >>> + "Invalid channel number (%d)\n", channel);
> >>> + return;
> >>> + }
> >>> +
> >>> + priv = dev->nets[channel];
> >>> + stats = &priv->netdev->stats;
> >>> +
> >>> + skb = alloc_can_err_skb(priv->netdev, &cf);
> >>> + if (!skb) {
> >>> + stats->rx_dropped++;
> >>> + return;
> >>> + }
> >>> +
> >>> + if ((status & M16C_STATE_BUS_OFF) ||
> >>> + (status & M16C_STATE_BUS_RESET)) {
> >>> + priv->can.state = CAN_STATE_BUS_OFF;
> >>> + cf->can_id |= CAN_ERR_BUSOFF;
> >>> + can_bus_off(priv->netdev);
>
> you should increment priv->can.can_stats.bus_off
> What does the firmware do in this state? Does it automatically try to
> recover and try to send the outstanding frames?
Yes that's what I observed.
>
> If so, you should turn of the CAN interface, it possible. See:
> http://lxr.free-electrons.com/source/drivers/net/can/at91_can.c#L986
Ok I'll have a look at this.
>
> Please test Bus-Off behaviour:
> - setup working CAN network
> - short circuit CAN-H and CAN-L wires
> - start "candump any,0:0,#FFFFFFFF" on one shell
> - send one can frame on the other
>
> then
>
> - remove the short circuit
> - see if the can frame is transmitted to the other side
> - it should show up as an echo'ed CAN frame on the sender side
>
> Repeat the same test with disconnecting CAN-H and CAN-L from the other
> CAN station instead of short circuit.
>
> Please send the output from candump.
1) With the short circuit:
I perform the test you described. It showed that the Kvaser passes from
ERROR-WARNING to ERROR-PASSIVE and then BUS-OFF. But after going to the
state BUS-OFF it comes back to ERROR-WARNING.
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
...
can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME <-- bus off
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
...
can1 20000088 [8] 00 10 90 00 00 00 00 00 ERRORFRAME
can1 123 [2] 11 22 <-- short circuit removed
I see the echo and on the other end I see the frame coming in.
By the way I see that the txerr and rxerr fields of the structure
kvaser_msg_error_event stay at 0.
2) With CAN-H and CAN-L disconnected:
I never see the bus going in OFF state. It stays in PASSIVE mode.
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
...
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 20000088 [8] 00 10 80 1B 00 00 00 00 ERRORFRAME
can1 123 [2] 11 22 <-- other end connected
>
> >>> + } else if (status & M16C_STATE_BUS_ERROR) {
> >>> + priv->can.state = CAN_STATE_ERROR_WARNING;
> >>> + priv->can.can_stats.error_warning++;
> >>> + } else if (status & M16C_STATE_BUS_PASSIVE) {
> >>> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> >>> + priv->can.can_stats.error_passive++;
> >>> + } else {
> >>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> >>> + cf->can_id |= CAN_ERR_PROT;
> >>> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
> >>> + }
> >>> +
> >>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
> >>> + u8 error_factor = msg->u.error_event.error_factor;
> >>> +
> >>> + priv->can.can_stats.bus_error++;
> >>> + stats->rx_errors++;
> >>> +
> >>> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> >>> +
> >>> + if ((priv->can.state == CAN_STATE_ERROR_WARNING) ||
> >>> + (priv->can.state == CAN_STATE_ERROR_PASSIVE)) {
> >>> + cf->data[1] = (txerr > rxerr) ?
> >>> + CAN_ERR_CRTL_TX_PASSIVE
> >>> + : CAN_ERR_CRTL_RX_PASSIVE;
> >>> + }
> >>> +
> >>> + if (error_factor & M16C_EF_ACKE)
> >>> + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
> >>> + CAN_ERR_PROT_LOC_ACK_DEL);
> >>> + if (error_factor & M16C_EF_CRCE)
> >>> + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> >>> + CAN_ERR_PROT_LOC_CRC_DEL);
> >>> + if (error_factor & M16C_EF_FORME)
> >>> + cf->data[2] |= CAN_ERR_PROT_FORM;
> >>> + if (error_factor & M16C_EF_STFE)
> >>> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> >>> + if (error_factor & M16C_EF_BITE0)
> >>> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> >>> + if (error_factor & M16C_EF_BITE1)
> >>> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> >>> + if (error_factor & M16C_EF_TRE)
> >>> + cf->data[2] |= CAN_ERR_PROT_TX;
> >>> + }
> >>> +
> >>> + cf->data[6] = txerr;
> >>> + cf->data[7] = rxerr;
> >>> +
> >>> + netif_rx(skb);
> >>> +
> >>> + priv->bec.txerr = txerr;
> >>> + priv->bec.rxerr = rxerr;
> >>> +
> >>> + stats->rx_packets++;
> >>> + stats->rx_bytes += cf->can_dlc;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> >>> + const struct kvaser_msg *msg)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + struct can_frame *cf;
> >>> + struct sk_buff *skb;
> >>> + struct net_device_stats *stats;
> >>> + u8 channel = msg->u.rx_can.channel;
> >>> +
> >>> + if (channel >= dev->nchannels) {
> >>> + dev_err(dev->udev->dev.parent,
> >>> + "Invalid channel number (%d)\n", channel);
> >>> + return;
> >>> + }
> >>> +
> >>> + priv = dev->nets[channel];
> >>> + stats = &priv->netdev->stats;
> >>> +
> >>> + skb = alloc_can_skb(priv->netdev, &cf);
> >>> + if (skb == NULL) {
> >>> + stats->tx_dropped++;
> >>> + return;
> >>> + }
> >>> +
> >>> + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
> >>> + (msg->u.rx_can.msg[1] & 0x3f);
> >>> + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
> >>> +
> >>> + if (msg->id == CMD_RX_EXT_MESSAGE) {
> >>> + cf->can_id <<= 18;
> >>> + cf->can_id += ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
> >> |=
> >>
> >> is more appropriate here
> >
> > Ok.
> >
> >>
> >>> + ((msg->u.rx_can.msg[3] & 0xff) << 6) |
> >>> + (msg->u.rx_can.msg[4] & 0x3f);
> >>> + cf->can_id |= CAN_EFF_FLAG;
> >>> + }
> >>> +
> >>> + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) {
> >>> + cf->can_id |= CAN_RTR_FLAG;
> >>> + } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
> >>> + MSG_FLAG_NERR)) {
> >>> + cf->can_id |= CAN_ERR_FLAG;
> >>> + cf->can_dlc = CAN_ERR_DLC;
> >>
> >> What kind of error is this? Can you set cf->data? What about the
> >> original cd->can_id? What about the stats->rx_*error* stats?
> >
> > Good question I've to take a look to this.
> >
> >>
> >>> + } else if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
> >>> + cf->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
> >>> + cf->can_dlc = CAN_ERR_DLC;
> >>> + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> >>> +
> >>> + stats->rx_over_errors++;
> >>> + stats->rx_errors++;
> >>> + } else if (!msg->u.rx_can.flag) {
> >>> + memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
> >>> + } else {
> >>> + kfree_skb(skb);
> >>> + return;
> >>> + }
> >>> +
> >>> + netif_rx(skb);
> >>> +
> >>> + stats->rx_packets++;
> >>> + stats->rx_bytes += cf->can_dlc;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_start_stop_chip_reply(const struct kvaser_usb *dev,
> >>> + const struct kvaser_msg *msg)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + u8 channel = msg->u.simple.channel;
> >>> +
> >>> + if (channel >= dev->nchannels) {
> >>> + dev_err(dev->udev->dev.parent,
> >>> + "Invalid channel number (%d)\n", channel);
> >>> + return;
> >>> + }
> >>> +
> >>> + priv = dev->nets[channel];
> >>> +
> >>> + complete(&priv->start_stop_comp);
> >>> +}
> >>> +
> >>> +static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
> >>> + const struct kvaser_msg *msg)
> >>> +{
> >>> + switch (msg->id) {
> >>> + case CMD_START_CHIP_REPLY:
> >>> + case CMD_STOP_CHIP_REPLY:
> >>> + kvaser_usb_start_stop_chip_reply(dev, msg);
> >>> + break;
> >>> +
> >>> + case CMD_RX_STD_MESSAGE:
> >>> + case CMD_RX_EXT_MESSAGE:
> >>> + kvaser_usb_rx_can_msg(dev, msg);
> >>> + break;
> >>> +
> >>> + case CMD_CHIP_STATE_EVENT:
> >>> + case CMD_CAN_ERROR_EVENT:
> >>> + kvaser_usb_rx_error(dev, msg);
> >>> + break;
> >>> +
> >>> + case CMD_TX_ACKNOWLEDGE:
> >>> + kvaser_usb_tx_acknowledge(dev, msg);
> >>> + break;
> >>> +
> >>> + default:
> >>> + dev_warn(dev->udev->dev.parent,
> >>> + "Unhandled message (%d)\n", msg->id);
> >>> + break;
> >>> + }
> >>> +}
> >>> +
> >>> +static void kvaser_usb_read_bulk_callback(struct urb *urb)
> >>> +{
> >>> + struct kvaser_usb *dev = urb->context;
> >>> + struct kvaser_msg *msg;
> >>> + int pos = 0;
> >>> + int err, i;
> >>> +
> >>> + switch (urb->status) {
> >>> + case 0:
> >>> + break;
> >>> + case -ENOENT:
> >>> + case -ESHUTDOWN:
> >>> + return;
> >>> + default:
> >>> + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
> >>> + urb->status);
> >>> + goto resubmit_urb;
> >>> + }
> >>> +
> >>> + while (pos < urb->actual_length) {
> >>
> >> please check here for pos + sizeof(*msg), too
> >
> > Same as above.
> >
> >>
> >>> + msg = urb->transfer_buffer + pos;
> >>> +
> >>> + if (!msg->len)
> >>> + break;
> >>> +
> >>> + kvaser_usb_handle_message(dev, msg);
> >>> +
> >>> + if (pos > urb->actual_length) {
> >>> + dev_err(dev->udev->dev.parent, "Format error\n");
> >>> + break;
> >>> + }
> >>> +
> >>> + pos += msg->len;
> >>> + }
> >>> +
> >>> +resubmit_urb:
> >>> + usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 129),
> >> ^^^
> >>
> >> use #define
> >
> > Ok.
> >
> >>
> >>> + urb->transfer_buffer, RX_BUFFER_SIZE,
> >>> + kvaser_usb_read_bulk_callback, dev);
> >>> +
> >>> + err = usb_submit_urb(urb, GFP_ATOMIC);
> >>> + if (err == -ENODEV) {
> >>> + for (i = 0; i < dev->nchannels; i++) {
> >>> + if (!dev->nets[i])
> >>> + continue;
> >>> +
> >>> + netif_device_detach(dev->nets[i]->netdev);
> >>> + }
> >>> + } else if (err) {
> >>> + dev_err(dev->udev->dev.parent,
> >>> + "Failed resubmitting read bulk urb: %d\n", err);
> >>> + }
> >>> +
> >>> + return;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
> >>> +{
> >>> + int i, err = 0;
> >>> +
> >>> + if (dev->rxinitdone)
> >>> + return 0;
> >>> +
> >>> + for (i = 0; i < MAX_RX_URBS; i++) {
> >>> + struct urb *urb = NULL;
> >>> + u8 *buf = NULL;
> >>> +
> >>> + urb = usb_alloc_urb(0, GFP_KERNEL);
> >>> + if (!urb) {
> >>> + dev_warn(dev->udev->dev.parent,
> >>> + "No memory left for URBs\n");
> >>> + err = -ENOMEM;
> >>> + break;
> >>> + }
> >>> +
> >>> + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
> >>> + GFP_KERNEL, &urb->transfer_dma);
> >>> + if (!buf) {
> >>> + dev_warn(dev->udev->dev.parent,
> >>> + "No memory left for USB buffer\n");
> >>> + usb_free_urb(urb);
> >>> + err = -ENOMEM;
> >>> + break;
> >>> + }
> >>> +
> >>> + usb_fill_bulk_urb(urb, dev->udev,
> >>> + usb_rcvbulkpipe(dev->udev, 129),
> >>
> >> use #define
> >
> > Ok.
> >
> >>
> >>> + buf, RX_BUFFER_SIZE,
> >>> + kvaser_usb_read_bulk_callback, dev);
> >>> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> >>> + usb_anchor_urb(urb, &dev->rx_submitted);
> >>> +
> >>> + err = usb_submit_urb(urb, GFP_KERNEL);
> >>> + if (err) {
> >>> + usb_unanchor_urb(urb);
> >>> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
> >>> + urb->transfer_dma);
> >>> + break;
> >>> + }
> >>> +
> >>> + usb_free_urb(urb);
> >>> + }
> >>> +
> >>> + if (i == 0) {
> >>> + dev_warn(dev->udev->dev.parent,
> >>> + "Cannot setup read URBs, error %d\n", err);
> >>> + return err;
> >>> + } else if (i < MAX_RX_URBS) {
> >>> + dev_warn(dev->udev->dev.parent,
> >>> + "RX performances may be slow\n");
> >>> + }
> >>> +
> >>> + dev->rxinitdone = true;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
> >>> +{
> >>> + struct kvaser_msg msg;
> >>> +
> >>> + memset(&msg, 0x00, sizeof(msg));
> >>> + msg.id = CMD_SET_CTRL_MODE;
> >>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_ctrl_mode);
> >>> + msg.u.ctrl_mode.tid = 0xff;
> >>> + msg.u.ctrl_mode.channel = priv->channel;
> >>
> >> please use C99 struct initializers
> >
> > Ok.
> >
> >>
> >>> +
> >>> + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> >>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
> >>> + else
> >>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
> >>> +
> >>> + return kvaser_usb_send_msg(priv->dev, &msg);
> >>> +}
> >>> +
> >>> +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
> >>> +{
> >>> + int err;
> >>> +
> >>> + init_completion(&priv->start_stop_comp);
> >>> +
> >>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
> >>> + priv->channel);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + if (!wait_for_completion_timeout(&priv->start_stop_comp,
> >>> + msecs_to_jiffies(START_TIMEOUT)))
> >>> + return -ETIMEDOUT;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_open(struct net_device *netdev)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> + struct kvaser_usb *dev = priv->dev;
> >>> + int err;
> >>> +
> >>> + err = open_candev(netdev);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + err = kvaser_usb_setup_rx_urbs(dev);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + err = kvaser_usb_set_opt_mode(priv);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + err = kvaser_usb_start_chip(priv);
> >>> + if (err) {
> >>> + netdev_warn(netdev, "Cannot start device, error %d\n", err);
> >>> + close_candev(netdev);
> >>> + return err;
> >>> + }
> >>> +
> >>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> >>> + priv->open_time = jiffies;
> >>> + netif_start_queue(netdev);
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> >>> +{
> >>> + int i;
> >>> +
> >>> + usb_kill_anchored_urbs(&priv->tx_submitted);
> >>> + atomic_set(&priv->active_tx_urbs, 0);
> >>> +
> >>> + for (i = 0; i < MAX_TX_URBS; i++)
> >> ARRAY_SIZE(priv->tx_contexts) instead of MAX_TX_URBS
> >
> > Ok.
> >
> >>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
> >>> +{
> >>> + int i;
> >>> +
> >>> + usb_kill_anchored_urbs(&dev->rx_submitted);
> >>> +
> >>> + for (i = 0; i < MAX_NET_DEVICES; i++) {
> >> ARRAY_SIZE()
> >>> + struct kvaser_usb_net_priv *priv = dev->nets[i];
> >>> +
> >>> + if (priv)
> >>> + kvaser_usb_unlink_tx_urbs(priv);
> >>> + }
> >>> +}
> >>> +
> >>> +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
> >>> +{
> >>> + int err;
> >>> +
> >>> + init_completion(&priv->start_stop_comp);
> >>> +
> >>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
> >>> + priv->channel);
> >>> + if (err)
> >>> + return err;
> >>> +
> >>> + if (!wait_for_completion_timeout(&priv->start_stop_comp,
> >>> + msecs_to_jiffies(STOP_TIMEOUT)))
> >>> + return -ETIMEDOUT;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
> >>> +{
> >>> + struct kvaser_msg msg;
> >>> +
> >>> + memset(&msg, 0x00, sizeof(msg));
> >>> + msg.id = CMD_FLUSH_QUEUE;
> >>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_flush_queue);
> >>> + msg.u.flush_queue.channel = priv->channel;
> >> C99 initialziers, please
> >
> > Ok.
> >
> >>> +
> >>> + return kvaser_usb_send_msg(priv->dev, &msg);
> >>> +}
> >>> +
> >>> +static int kvaser_usb_close(struct net_device *netdev)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> + int err;
> >>> +
> >>> + netif_stop_queue(netdev);
> >>> +
> >>> + err = kvaser_usb_flush_queue(priv);
> >>> + if (err)
> >>> + netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
> >>> +
> >>> + err = kvaser_usb_stop_chip(priv);
> >>> + if (err) {
> >>> + netdev_warn(netdev, "Cannot stop device, error %d\n", err);
> >>> + return err;
> >>> + }
> >>> +
> >>> + kvaser_usb_unlink_tx_urbs(priv);
> >>> +
> >>> + priv->can.state = CAN_STATE_STOPPED;
> >>> + close_candev(priv->netdev);
> >>> + priv->open_time = 0;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_write_bulk_callback(struct urb *urb)
> >>> +{
> >>> + struct kvaser_usb_tx_urb_context *context = urb->context;
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + struct net_device *netdev;
> >>> +
> >>> + if (WARN_ON(!context))
> >>> + return;
> >>> +
> >>> + priv = context->priv;
> >>> + netdev = priv->netdev;
> >>> +
> >>> + usb_free_coherent(urb->dev, urb->transfer_buffer_length,
> >>> + urb->transfer_buffer, urb->transfer_dma);
> >>> +
> >>> + if (!netif_device_present(netdev))
> >>> + return;
> >>> +
> >>> + if (urb->status)
> >>> + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
> >>> +
> >>> + netdev->trans_start = jiffies;
> >>
> >> Is trans_start needed? at least for non-usb devices it works without.
> >
> > I don't know, I'll try to figure this out.
> > I see it's used in the two others CAN/USB drivers, 'ems_usb.c' and
> > 'esd_usb2.c'
> >
> >>
> >>> +}
> >>> +
> >>> +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> >>> + struct net_device *netdev)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> + struct kvaser_usb *dev = priv->dev;
> >>> + struct net_device_stats *stats = &netdev->stats;
> >>> + struct can_frame *cf = (struct can_frame *)skb->data;
> >>> + struct kvaser_usb_tx_urb_context *context = NULL;
> >>> + struct urb *urb;
> >>> + void *buf;
> >>> + struct kvaser_msg *msg;
> >>> + int i, err;
> >>> + int ret = NETDEV_TX_OK;
> >>> +
> >>> + if (can_dropped_invalid_skb(netdev, skb))
> >>> + return NETDEV_TX_OK;
> >>> +
> >>> + urb = usb_alloc_urb(0, GFP_ATOMIC);
> >>> + if (!urb) {
> >>> + netdev_err(netdev, "No memory left for URBs\n");
> >>> + stats->tx_dropped++;
> >>> + dev_kfree_skb(skb);
> >>> + goto nourbmem;
> >>> + }
> >>> +
> >>> + buf = usb_alloc_coherent(dev->udev, sizeof(struct kvaser_msg),
> >>> + GFP_ATOMIC, &urb->transfer_dma);
> >>> + if (!buf) {
> >>> + netdev_err(netdev, "No memory left for USB buffer\n");
> >>> + stats->tx_dropped++;
> >>> + dev_kfree_skb(skb);
> >>> + goto nobufmem;
> >>> + }
> >>> +
> >>> + msg = (struct kvaser_msg *)buf;
> >>> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
> >>> + msg->u.tx_can.flags = 0;
> >>> + msg->u.tx_can.channel = priv->channel;
> >>> +
> >>> + if (cf->can_id & CAN_EFF_FLAG) {
> >>> + msg->id = CMD_TX_EXT_MESSAGE;
> >>> + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
> >>> + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
> >>> + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
> >>> + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
> >>> + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
> >>> + } else {
> >>> + msg->id = CMD_TX_STD_MESSAGE;
> >>> + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
> >>> + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
> >>> + }
> >>> +
> >>> + msg->u.tx_can.msg[5] = cf->can_dlc;
> >>> + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
> >>> +
> >>> + if (cf->can_id & CAN_RTR_FLAG)
> >>> + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
> >>> +
> >>> + for (i = 0; i < MAX_TX_URBS; i++) {
> >> ARRAY_SIZE
> >
> > Ok.
> >
> >>> + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> >>> + context = &priv->tx_contexts[i];
> >>> + break;
> >>> + }
> >>> + }
> >>> +
> >>> + if (!context) {
> >>> + netdev_warn(netdev, "cannot find free context\n");
> >>> + ret = NETDEV_TX_BUSY;
> >>> + goto releasebuf;
> >>> + }
> >>> +
> >>> + context->priv = priv;
> >>> + context->echo_index = i;
> >>> + context->dlc = cf->can_dlc;
> >>> +
> >>> + msg->u.tx_can.tid = context->echo_index;
> >>> +
> >>> + usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
> >>> + buf, msg->len,
> >>> + kvaser_usb_write_bulk_callback, context);
> >>> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> >>> + usb_anchor_urb(urb, &priv->tx_submitted);
> >>> +
> >>> + can_put_echo_skb(skb, netdev, context->echo_index);
> >>> +
> >>> + atomic_inc(&priv->active_tx_urbs);
> >>> +
> >>> + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
> >>> + netif_stop_queue(netdev);
> >>> +
> >>> + err = usb_submit_urb(urb, GFP_ATOMIC);
> >>> + if (unlikely(err)) {
> >>> + can_free_echo_skb(netdev, context->echo_index);
> >>> +
> >>> + atomic_dec(&priv->active_tx_urbs);
> >>> + usb_unanchor_urb(urb);
> >>> +
> >>> + stats->tx_dropped++;
> >>> +
> >>> + if (err == -ENODEV)
> >>> + netif_device_detach(netdev);
> >>> + else
> >>> + netdev_warn(netdev, "Failed tx_urb %d\n", err);
> >>> +
> >>> + goto releasebuf;
> >>> + }
> >>> +
> >>> + netdev->trans_start = jiffies;
> >>> +
> >>> + usb_free_urb(urb);
> >>> +
> >>> + return NETDEV_TX_OK;
> >>> +
> >>> +releasebuf:
> >>> + usb_free_coherent(dev->udev, sizeof(struct kvaser_msg),
> >>> + buf, urb->transfer_dma);
> >>> +nobufmem:
> >>> + usb_free_urb(urb);
> >>> +nourbmem:
> >>> + return ret;
> >>> +}
> >>> +
> >>> +static const struct net_device_ops kvaser_usb_netdev_ops = {
> >>> + .ndo_open = kvaser_usb_open,
> >>> + .ndo_stop = kvaser_usb_close,
> >>> + .ndo_start_xmit = kvaser_usb_start_xmit,
> >>> +};
> >>> +
> >>> +static struct can_bittiming_const kvaser_usb_bittiming_const = {
> >>> + .name = "kvaser_usb",
> >>> + .tseg1_min = KVASER_USB_TSEG1_MIN,
> >>> + .tseg1_max = KVASER_USB_TSEG1_MAX,
> >>> + .tseg2_min = KVASER_USB_TSEG2_MIN,
> >>> + .tseg2_max = KVASER_USB_TSEG2_MAX,
> >>> + .sjw_max = KVASER_USB_SJW_MAX,
> >>> + .brp_min = KVASER_USB_BRP_MIN,
> >>> + .brp_max = KVASER_USB_BRP_MAX,
> >>> + .brp_inc = KVASER_USB_BRP_INC,
> >>> +};
> >>> +
> >>> +static int kvaser_usb_set_bittiming(struct net_device *netdev)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> + struct can_bittiming *bt = &priv->can.bittiming;
> >>> + struct kvaser_usb *dev = priv->dev;
> >>> + struct kvaser_msg msg;
> >>> +
> >>> + msg.id = CMD_SET_BUS_PARAMS;
> >>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_busparams);
> >>> + msg.u.busparams.channel = priv->channel;
> >>> + msg.u.busparams.tid = 0xff;
> >>> + msg.u.busparams.bitrate = bt->bitrate;
> >>
> >> bitrate is le32
> >
> > Indeed ! I'll fix this.
> >
> >>
> >>> + msg.u.busparams.sjw = bt->sjw;
> >>> + msg.u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
> >>> + msg.u.busparams.tseg2 = bt->phase_seg2;
> >>
> >> C99 initializers, please
> >>
> >>> +
> >>> + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> >>> + msg.u.busparams.no_samp = 3;
> >>> + else
> >>> + msg.u.busparams.no_samp = 1;
> >>> +
> >>> + return kvaser_usb_send_msg(dev, &msg);
> >>> +}
> >>> +
> >>> +static int kvaser_usb_set_mode(struct net_device *netdev,
> >>> + enum can_mode mode)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> +
> >>> + if (!priv->open_time)
> >>> + return -EINVAL;
> >>> +
> >>> + switch (mode) {
> >>> + case CAN_MODE_START:
> >>> + if (netif_queue_stopped(netdev))
> >>> + netif_wake_queue(netdev);
> >>
> >> No need to restart your USB device?
> >
> > No. I don't think so.
> > The module continuously tries to transmit the frame and isn't stopped.
> > So there is no need to restart it if it has been explicitely stopped.
> >
> > When it cannot transmit, the module try again and sends continuously
> > CMD_CAN_ERROR_EVENT frames until it succeeds to transmit the frame.
> > If the device is stopped with the command CMD_STOP_CHIP then it stops
> > sending these CMD_CAN_ERROR_EVENT.
> > Should I handle this in another manner?
>
> If the firmware automatically recovers from busoff (like the at91 does),
> you should stop the chip it priv->can.restart_ms == 0 and let the chip
> continue working otherwise.
>
> >
> >>
> >>> + break;
> >>> + default:
> >>> + return -EOPNOTSUPP;
> >>> + }
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
> >>> + struct can_berr_counter *bec)
> >>> +{
> >>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> >>> +
> >>> + bec->txerr = priv->bec.txerr;
> >>> + bec->rxerr = priv->bec.rxerr;
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_init_one(struct usb_interface *intf,
> >>> + const struct usb_device_id *id, int channel)
> >>> +{
> >>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> >>> + struct net_device *netdev;
> >>> + struct kvaser_usb_net_priv *priv;
> >>> + int i, err;
> >>> +
> >>> + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
> >>> + if (!netdev) {
> >>> + dev_err(&intf->dev, "Cannot alloc candev\n");
> >>> + return -ENOMEM;
> >>> + }
> >>> +
> >>> + priv = netdev_priv(netdev);
> >>> +
> >>> + init_usb_anchor(&priv->tx_submitted);
> >>> + atomic_set(&priv->active_tx_urbs, 0);
> >>> +
> >>> + for (i = 0; i < MAX_TX_URBS; i++)
> >>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> >>> +
> >>> + priv->dev = dev;
> >>> + priv->netdev = netdev;
> >>> + priv->channel = channel;
> >>> +
> >>> + priv->can.state = CAN_STATE_STOPPED;
> >>> + priv->can.clock.freq = CAN_USB_CLOCK;
> >>> + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
> >>> + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
> >>> + priv->can.do_set_mode = kvaser_usb_set_mode;
> >>> + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
> >>> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
> >>> + if (id->driver_info & KVASER_HAS_SILENT_MODE)
> >>> + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
> >>> +
> >>> + netdev->flags |= IFF_ECHO;
> >>> +
> >>> + netdev->netdev_ops = &kvaser_usb_netdev_ops;
> >>> +
> >>> + SET_NETDEV_DEV(netdev, &intf->dev);
> >>> +
> >>> + err = register_candev(netdev);
> >>> + if (err) {
> >>> + dev_err(&intf->dev, "Failed to register can device\n");
> >>> + free_candev(netdev);
> >>> + return err;
> >>> + }
> >>> +
> >>> + dev->nets[channel] = priv;
> >>> + netdev_info(netdev, "device %s registered\n", netdev->name);
> >>
> >> netdev_info should take care of printing the device's name.
> >
> > Ok.
> >
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int kvaser_usb_probe(struct usb_interface *intf,
> >>> + const struct usb_device_id *id)
> >>> +{
> >>> + struct kvaser_usb *dev;
> >>> + int err = -ENOMEM;
> >>> + int i;
> >>> +
> >>> + dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> >>
> >> Who will free dev on driver unload? Please make use of devm_kzalloc().
> >
> > Ok. kfree is missing is disconnect().
> > I'll replace it by devm_kzalloc() and devm_free().
>
> The beauty of devm_kzalloc is you don't have to call *_free, its
> automatically called if probe fails or when remove function has been called.
Cool :-)
>
> >
> >>
> >>> + if (!dev)
> >>> + return -ENOMEM;
> >>> +
> >>> + dev->udev = interface_to_usbdev(intf);
> >>> +
> >>> + init_usb_anchor(&dev->rx_submitted);
> >>> +
> >>> + usb_set_intfdata(intf, dev);
> >>> +
> >>> + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, 0)) {
> >>> + dev_err(&intf->dev, "Cannot reset kvaser\n");
> >>> + goto error;
> >>> + }
> >>> +
> >>> + if (kvaser_usb_get_software_info(dev)) {
> >>> + dev_err(&intf->dev, "Cannot get software infos\n");
> >>> + goto error;
> >>> + }
> >>> +
> >>> + if (kvaser_usb_get_card_info(dev)) {
> >>> + dev_err(&intf->dev, "Cannot get card infos\n");
> >>> + goto error;
> >>> + }
> >>> +
> >>> + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
> >>> + ((dev->fw_version >> 24) & 0xff),
> >>> + ((dev->fw_version >> 16) & 0xff),
> >>> + (dev->fw_version & 0xffff));
> >>> +
> >>> + for (i = 0; i < dev->nchannels; i++)
> >>> + kvaser_usb_init_one(intf, id, i);
> >>> +
> >>> + return 0;
> >>> +
> >>> +error:
> >>> + kfree(dev);
> >>> + return err;
> >>> +}
> >>> +
> >>> +static void kvaser_usb_disconnect(struct usb_interface *intf)
> >>> +{
> >>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> >>> + int i;
> >>> +
> >>> + usb_set_intfdata(intf, NULL);
> >>> +
> >>> + if (!dev)
> >>> + return;
> >>> +
> >>> + for (i = 0; i < dev->nchannels; i++) {
> >>> + if (!dev->nets[i])
> >>> + continue;
> >>> +
> >>> + unregister_netdev(dev->nets[i]->netdev);
> >>> + free_candev(dev->nets[i]->netdev);
> >>> + }
> >>> +
> >>> + kvaser_usb_unlink_all_urbs(dev);
> >>> +}
> >>> +
> >>> +static struct usb_driver kvaser_usb_driver = {
> >>> + .name = "kvaser_usb",
> >>> + .probe = kvaser_usb_probe,
> >>> + .disconnect = kvaser_usb_disconnect,
> >>> + .id_table = kvaser_usb_table
> >>> +};
> >>> +
> >>> +module_usb_driver(kvaser_usb_driver);
> >>> +
> >>> +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
> >>> +MODULE_DESCRIPTION("Can driver for Kvaser CAN/USB devices");
> >>> +MODULE_LICENSE("GPL v2");
> >>> diff --git a/drivers/net/can/usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb.h
> >>> new file mode 100644
> >>> index 0000000..8e0b6ab
> >>> --- /dev/null
> >>> +++ b/drivers/net/can/usb/kvaser_usb.h
> >>> @@ -0,0 +1,237 @@
> >>> +#ifndef _KVASER_USB_H_
> >>> +#define _KVASER_USB_H_
> >>> +
> >>> +#define MAX_TX_URBS 16
> >> Please no tab between define and macro name
> >
> > Ok I didn't know it was not allowed... checkpatch didn't complain.
>
> It's allowed, but not used without tab it's more common, at least among
> CAN drivers.
>
> >
> >>> +#define MAX_RX_URBS 4
> >>> +#define START_TIMEOUT 1000
> >>> +#define STOP_TIMEOUT 1000
> >>> +#define USB_SEND_TIMEOUT 1000
> >>> +#define USB_RECEIVE_TIMEOUT 1000
> >>> +#define RX_BUFFER_SIZE 3072
> >>> +#define CAN_USB_CLOCK 8000000
> >>> +#define MAX_NET_DEVICES 3
> >>> +
> >>> +/* Kvaser USB devices */
> >>> +#define KVASER_VENDOR_ID 0x0bfd
> >>> +#define USB_LEAF_DEVEL_PRODUCT_ID 10
> >>> +#define USB_LEAF_LITE_PRODUCT_ID 11
> >>> +#define USB_LEAF_PRO_PRODUCT_ID 12
> >>> +#define USB_LEAF_SPRO_PRODUCT_ID 14
> >>> +#define USB_LEAF_PRO_LS_PRODUCT_ID 15
> >>> +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
> >>> +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
> >>> +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
> >>> +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
> >>> +#define USB_MEMO2_DEVEL_PRODUCT_ID 22
> >>> +#define USB_MEMO2_HSHS_PRODUCT_ID 23
> >>> +#define USB_UPRO_HSHS_PRODUCT_ID 24
> >>> +#define USB_LEAF_LITE_GI_PRODUCT_ID 25
> >>> +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
> >>> +#define USB_MEMO2_HSLS_PRODUCT_ID 27
> >>> +#define USB_LEAF_LITE_CH_PRODUCT_ID 28
> >>> +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
> >>> +#define USB_OEM_MERCURY_PRODUCT_ID 34
> >>> +#define USB_OEM_LEAF_PRODUCT_ID 35
> >>> +#define USB_CAN_R_PRODUCT_ID 39
> >>> +
> >>> +/* USB devices features */
> >>> +#define KVASER_HAS_SILENT_MODE (1 << 0)
> >> pleae use BIT(0)
> >>> +
> >>> +/* Message header size */
> >>> +#define MSG_HEADER_LEN 2
> >>> +
> >>> +/* Can message flags */
> >>> +#define MSG_FLAG_ERROR_FRAME (1 << 0)
> >>> +#define MSG_FLAG_OVERRUN (1 << 1)
> >>> +#define MSG_FLAG_NERR (1 << 2)
> >>> +#define MSG_FLAG_WAKEUP (1 << 3)
> >>> +#define MSG_FLAG_REMOTE_FRAME (1 << 4)
> >>> +#define MSG_FLAG_RESERVED (1 << 5)
> >>> +#define MSG_FLAG_TX_ACK (1 << 6)
> >>> +#define MSG_FLAG_TX_REQUEST (1 << 7)
> >>> +
> >>> +/* Can states */
> >>> +#define M16C_STATE_BUS_RESET (1 << 0)
> >>> +#define M16C_STATE_BUS_ERROR (1 << 4)
> >>> +#define M16C_STATE_BUS_PASSIVE (1 << 5)
> >>> +#define M16C_STATE_BUS_OFF (1 << 6)
> >>> +
> >>> +/* Can msg ids */
> >>> +#define CMD_RX_STD_MESSAGE 12
> >>> +#define CMD_TX_STD_MESSAGE 13
> >>> +#define CMD_RX_EXT_MESSAGE 14
> >>> +#define CMD_TX_EXT_MESSAGE 15
> >>> +#define CMD_SET_BUS_PARAMS 16
> >>> +#define CMD_GET_BUS_PARAMS 17
> >>> +#define CMD_GET_BUS_PARAMS_REPLY 18
> >>> +#define CMD_GET_CHIP_STATE 19
> >>> +#define CMD_CHIP_STATE_EVENT 20
> >>> +#define CMD_SET_CTRL_MODE 21
> >>> +#define CMD_GET_CTRL_MODE 22
> >>> +#define CMD_GET_CTRL_MODE_REPLY 23
> >>> +#define CMD_RESET_CHIP 24
> >>> +#define CMD_RESET_CHIP_REPLY 25
> >>> +#define CMD_START_CHIP 26
> >>> +#define CMD_START_CHIP_REPLY 27
> >>> +#define CMD_STOP_CHIP 28
> >>> +#define CMD_STOP_CHIP_REPLY 29
> >>> +#define CMD_GET_CARD_INFO2 32
> >>> +#define CMD_GET_CARD_INFO 34
> >>> +#define CMD_GET_CARD_INFO_REPLY 35
> >>> +#define CMD_GET_SOFTWARE_INFO 38
> >>> +#define CMD_GET_SOFTWARE_INFO_REPLY 39
> >>> +#define CMD_ERROR_EVENT 45
> >>> +#define CMD_FLUSH_QUEUE 48
> >>> +#define CMD_TX_ACKNOWLEDGE 50
> >>> +#define CMD_CAN_ERROR_EVENT 51
> >>> +#define CMD_USB_THROTTLE 77
> >>> +
> >>> +/* error factors */
> >>> +#define M16C_EF_ACKE (1 << 0)
> >>> +#define M16C_EF_CRCE (1 << 1)
> >>> +#define M16C_EF_FORME (1 << 2)
> >>> +#define M16C_EF_STFE (1 << 3)
> >>> +#define M16C_EF_BITE0 (1 << 4)
> >>> +#define M16C_EF_BITE1 (1 << 5)
> >>> +#define M16C_EF_RCVE (1 << 6)
> >>> +#define M16C_EF_TRE (1 << 7)
> >>> +
> >>> +/* bittiming parameters */
> >>> +#define KVASER_USB_TSEG1_MIN 1
> >>> +#define KVASER_USB_TSEG1_MAX 16
> >>> +#define KVASER_USB_TSEG2_MIN 1
> >>> +#define KVASER_USB_TSEG2_MAX 8
> >>> +#define KVASER_USB_SJW_MAX 4
> >>> +#define KVASER_USB_BRP_MIN 1
> >>> +#define KVASER_USB_BRP_MAX 64
> >>> +#define KVASER_USB_BRP_INC 1
> >>> +
> >>> +/* ctrl modes */
> >>> +#define KVASER_CTRL_MODE_NORMAL 1
> >>> +#define KVASER_CTRL_MODE_SILENT 2
> >>> +#define KVASER_CTRL_MODE_SELFRECEPTION 3
> >>> +#define KVASER_CTRL_MODE_OFF 4
> >>> +
> >>> +struct kvaser_msg_simple {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_cardinfo {
> >>> + u8 tid;
> >>> + u8 nchannels;
> >>> + __le32 serial_number;
> >>> + __le32 padding;
> >>> + __le32 clock_resolution;
> >>> + __le32 mfgdate;
> >>> + u8 ean[8];
> >>> + u8 hw_revision;
> >>> + u8 usb_hs_mode;
> >>> + __le16 padding2;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_cardinfo2 {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + u8 pcb_id[24];
> >>> + __le32 oem_unlock_code;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_softinfo {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + __le32 sw_options;
> >>> + __le32 fw_version;
> >>> + __le16 max_outstanding_tx;
> >>> + __le16 padding[9];
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_busparams {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + __le32 bitrate;
> >>> + u8 tseg1;
> >>> + u8 tseg2;
> >>> + u8 sjw;
> >>> + u8 no_samp;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_tx_can {
> >>> + u8 channel;
> >>> + u8 tid;
> >>> + u8 msg[14];
> >>> + u8 padding;
> >>> + u8 flags;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_rx_can {
> >>> + u8 channel;
> >>> + u8 flag;
> >>> + __le16 time[3];
> >>> + u8 msg[14];
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_chip_state_event {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + __le16 time[3];
> >>> + u8 tx_errors_count;
> >>> + u8 rx_errors_count;
> >>> + u8 status;
> >>> + u8 padding[3];
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_tx_acknowledge {
> >>> + u8 channel;
> >>> + u8 tid;
> >>> + __le16 time[3];
> >>> + u8 flags;
> >>> + u8 time_offset;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_error_event {
> >>> + u8 tid;
> >>> + u8 flags;
> >>> + __le16 time[3];
> >>> + u8 channel;
> >>> + u8 padding;
> >>> + u8 tx_errors_count;
> >>> + u8 rx_errors_count;
> >>> + u8 status;
> >>> + u8 error_factor;
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_ctrl_mode {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + u8 ctrl_mode;
> >>> + u8 padding[3];
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg_flush_queue {
> >>> + u8 tid;
> >>> + u8 channel;
> >>> + u8 flags;
> >>> + u8 padding[3];
> >>> +} __packed;
> >>> +
> >>> +struct kvaser_msg {
> >>> + u8 len;
> >>> + u8 id;
> >>> + union {
> >>> + struct kvaser_msg_simple simple;
> >>> + struct kvaser_msg_cardinfo cardinfo;
> >>> + struct kvaser_msg_cardinfo2 cardinfo2;
> >>> + struct kvaser_msg_softinfo softinfo;
> >>> + struct kvaser_msg_busparams busparams;
> >>> + struct kvaser_msg_tx_can tx_can;
> >>> + struct kvaser_msg_rx_can rx_can;
> >>> + struct kvaser_msg_chip_state_event chip_state_event;
> >>> + struct kvaser_msg_tx_acknowledge tx_acknowledge;
> >>> + struct kvaser_msg_error_event error_event;
> >>> + struct kvaser_msg_ctrl_mode ctrl_mode;
> >>> + struct kvaser_msg_ctrl_mode flush_queue;
> >>> + } u;
> >>> +} __packed;
> >>> +
> >>> +#endif
> >>>
> >>
> >>
> >> --
> >> Pengutronix e.K. | Marc Kleine-Budde |
> >> Industrial Linux Solutions | Phone: +49-231-2826-924 |
> >> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
> >> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
> >>
> >
> > Thanks for the review.
> np,
>
> regards, Marc
>
> --
> Pengutronix e.K. | Marc Kleine-Budde |
> Industrial Linux Solutions | Phone: +49-231-2826-924 |
> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
>
Thanks,
--
Olivier
^ permalink raw reply
* Re: [PATCH 1/2] net: Allow to create links with given ifindex
From: Eric W. Biederman @ 2012-07-31 11:58 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: Linux Netdev List, David Miller
In-Reply-To: <50179F66.1000604@parallels.com>
Pavel Emelyanov <xemul@parallels.com> writes:
> On 07/30/2012 02:56 PM, Eric W. Biederman wrote:
>> ebiederm@xmission.com (Eric W. Biederman) writes:
>>
>>> Pavel Emelyanov <xemul@parallels.com> writes:
>>>
>>>> Currently the RTM_NEWLINK results in -EOPNOTSUPP if the ifinfomsg->ifi_index
>>>> is not zero. I propose to allow requesting ifindices on link creation. This
>>>> is required by the checkpoint-restore to correctly restore a net namespace
>>>> (i.e. -- a container). The question what to do with pre-created devices such
>>>> as lo or sit fbdev is open, but for manually created devices this can be
>>>> solved by this patch.
>>>
>>> Have you walked through and found the locations where we still rely on
>>> ifindex being globally unique?
>>>
>>> Last time I was working in this area there were serveral places where
>>> things were indexed by just the interface index.
>>
>> If it is really safe to make ifindex per network namespace at this
>> point you can make dev_new_ifindex have a per network namespace base
>> counter, and that will fix your problems with the loopback device.
>
> Not it's not so unfortunately :(
>
> First, let's imagine that on host A the loopback device got registered as
> first device, but on host B for some reason some other device got registered
> first. In that case after migration from A to B the lo on B will have index
> equals 2. And there's no any strict requirement that lo's per net operations
> are registered first. Please, correct me if I'm wrong.
Actually there is a hard requirement that the loopback device be the
last device in a network namespace to be unregistered. We meet that
requirement by registering the loopback device first
"net/core/dev.c:net_dev_init()".
> Next. In fact, lo is not the only problem. Look at the e.g. sit versus ipgre
> fallback devices. Both gets created on netns creation and obtain whatever
> ifindices are generated for them. Even if we make ifidex per netns chances
> that sit gets registered _strictly_ before ipgre equal zero, since they are
> both modules.
True. However those fallback devices should no longer be needed,
and even if they are I think you can delete and recreate them.
Making lo the particularly interesting case.
>> Unless you have done the work to root out the last of dependencies on
>> ifindex being globally unique I think you will run into some operational
>> problems.
>
> I totally agree with that. Before doing this patch I revisited the ancient
> attempt to make ifindices per netns and checked the issues Dave and you
> discussed then -- I have looked through how the ifindices are used in the
> networking code and found no places where the system-wide uniqueness is still
> required. That's why I proposed this patch for inclusion. If you know the
> places I've missed, please let me know, I will work on it.
I took a quick look and I did not see anything. I saw places under
net/sched/ that looked a bit suspicious, and of course there are places
where we use oif and iff in some of the routing code that make we wonder
a bit. But if you have looked and if I have looked I think we are ok.
> Just an idea -- is it worth moving the possibility to have ifindidces intersect
> under CONFIG_<SOMETHING> (EXPERT/CHECKPOINT_RESTORE) to let wider audience check
> the code in real-life?
I think the best testing we are going to get diversity wise is to create
a per netns counter into dev_new_index when net-next opens up.
Having an ifindex that we can only set at netdevice creation time seems
reasonable.
Eric
^ permalink raw reply
* [ANNOUNCE] iptables 1.4.15 release
From: Pablo Neira Ayuso @ 2012-07-31 11:25 UTC (permalink / raw)
To: netfilter-devel; +Cc: netdev, netfilter, netfilter-announce, lwn
[-- Attachment #1: Type: text/plain, Size: 407 bytes --]
Hi!
The Netfilter project proudly presents:
iptables 1.4.15
This release includes support for new features now present in the
Linux kernel 3.5 and one major bugfix (that shows up with gcc-4.7).
See ChangeLog that comes attached to this email for more details.
You can download it from:
http://www.netfilter.org/projects/iptables/downloads.html
ftp://ftp.netfilter.org/pub/iptables/
Have fun!
[-- Attachment #2: changes-iptables-1.4.15.txt --]
[-- Type: text/plain, Size: 805 bytes --]
Denys Fedoryshchenko (1):
libxt_recent: add --mask netmask
Eldad Zack (1):
libxt_recent: remove unused variable
Florian Westphal (2):
libxt_devgroup: add man page snippet
libxt_hashlimit: add support for byte-based operation
Hans Schillstrom (3):
extensions: add HMARK target
libxt_HMARK: fix output of iptables -L
libxt_HMARK: correct a number of errors introduced by Pablo's rework
Pablo Neira Ayuso (6):
libxtables: add xtables_ip[6]mask_to_cidr
libxt_HMARK: fix ct case example
iptables-restore: move code to add_param_to_argv, cleanup (fix gcc-4.7)
Revert "iptables-restore: move code to add_param_to_argv, cleanup (fix gcc-4.7)"
iptables-restore: fix parameter parsing (shows up with gcc-4.7)
bump version to 1.4.15
^ permalink raw reply
* [ANNOUNCE] conntrack-tools 1.2.2 release
From: Pablo Neira Ayuso @ 2012-07-31 11:22 UTC (permalink / raw)
To: netfilter-devel; +Cc: netdev, netfilter, netfilter-announce, lwn
[-- Attachment #1: Type: text/plain, Size: 337 bytes --]
Hi!
The Netfilter project proudly presents:
conntrack-tools 1.2.2
This release contains accumulated bugfixes.
See ChangeLog that comes attached to this email for more details.
You can download it from:
http://www.netfilter.org/projects/conntrack-tools/downloads.html
ftp://ftp.netfilter.org/pub/conntrack-tools/
Have fun!
[-- Attachment #2: changes-conntrack-tools-1.2.2.txt --]
[-- Type: text/plain, Size: 485 bytes --]
Jan Engelhardt (1):
update .gitignore
Pablo Neira Ayuso (7):
conntrackd: simplify TCP connection handling logic
conntrackd: fix compilation in src/parse.c
doc: fix documentation on ExpectationSync and H.323 helper
conntrackd: add bugtrap notice in case of flush while commit in progress
conntrackd: fix commit operation, needs to be synchronous
conntrackd: implement selective flushing for `-t' and `-F' commands
bump version to 1.2.2
^ permalink raw reply
* [PATCH v2] ipv4: Restore old dst_free() behavior.
From: Eric Dumazet @ 2012-07-31 11:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20120730.223827.74792864437911339.davem@davemloft.net>
From: Eric Dumazet <edumazet@google.com>
On Mon, 2012-07-30 at 22:38 -0700, David Miller wrote:
> Eric, this is what I'd like to propose.
>
> It seems the problem you were likely running into was simply
> the fact that we were not inserting an RCU grace period for
> the dst_free() that we do when purging a FIB nexthop.
>
> So this reverts your change, and instead adds the necessary
> call_rcu_bh() wrapper around the dst_free() done in fib_semantics.c
>
> That makes it so that we don't need all of that inc_not_zero stuff for
> sockets, and the special dst flag. If we set the pointer to NULL,
> then do the dst_free() via RCU, we can test that refcount safely in
> dst_free() since it can only decrease at that point.
>
> What do you think? Does it pass your tests?
It doesnt.
But I believe I found why, thats the good news ;)
In the past, we used RCU only for input routes, thats why using
call_rcu_bh() was OK.
But now we alse cache output routes, we must use call_rcu(), because
on output path we use rcu_read_lock() 'only', in process context,
not from softirq handler.
If you dont mind, I would like to keep inet_sk_rx_dst_set() helper
because I believe its cleaner and I'll probably add IPv6 stuff on it
(the cookie thing)
Also I added __rcu attributes to nh_rth_output and nh_rth_input to
better document what is going on in this code.
Thanks
[PATCH v2] ipv4: Restore old dst_free() behavior
commit 404e0a8b6a55 (net: ipv4: fix RCU races on dst refcounts) tried
to solve a race but added a problem at device/fib dismantle time :
We really want to call dst_free() as soon as possible, even if sockets
still have dst in their cache.
dst_release() calls in free_fib_info_rcu() are not welcomed.
Root of the problem was that now we also cache output routes (in
nh_rth_output), we must use call_rcu() instead of call_rcu_bh() in
rt_free(), because output route lookups are done in process context.
Based on feedback and initial patch from David Miller (adding another
call_rcu_bh() call in fib, but it appears it was not the right fix)
I left the inet_sk_rx_dst_set() helper and added __rcu attributes
to nh_rth_output and nh_rth_input to better document what is going on in
this code.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/dst.h | 7 ++++++-
include/net/inet_sock.h | 10 +++-------
include/net/ip_fib.h | 4 ++--
net/core/dst.c | 26 +++++---------------------
net/decnet/dn_route.c | 6 ------
net/ipv4/fib_semantics.c | 21 +++++++++++++++++----
net/ipv4/route.c | 26 +++++++++++++++++---------
7 files changed, 50 insertions(+), 50 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 31a9fd3..baf5978 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -61,7 +61,6 @@ struct dst_entry {
#define DST_NOPEER 0x0040
#define DST_FAKE_RTABLE 0x0080
#define DST_XFRM_TUNNEL 0x0100
-#define DST_RCU_FREE 0x0200
unsigned short pending_confirm;
@@ -383,6 +382,12 @@ static inline void dst_free(struct dst_entry *dst)
__dst_free(dst);
}
+static inline void dst_rcu_free(struct rcu_head *head)
+{
+ struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head);
+ dst_free(dst);
+}
+
static inline void dst_confirm(struct dst_entry *dst)
{
dst->pending_confirm = 1;
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index e3fd34c..83b567f 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -253,13 +253,9 @@ static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb
{
struct dst_entry *dst = skb_dst(skb);
- if (atomic_inc_not_zero(&dst->__refcnt)) {
- if (!(dst->flags & DST_RCU_FREE))
- dst->flags |= DST_RCU_FREE;
-
- sk->sk_rx_dst = dst;
- inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
- }
+ dst_hold(dst);
+ sk->sk_rx_dst = dst;
+ inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
}
#endif /* _INET_SOCK_H */
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index e69c3a4..e521a03 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -81,8 +81,8 @@ struct fib_nh {
__be32 nh_gw;
__be32 nh_saddr;
int nh_saddr_genid;
- struct rtable *nh_rth_output;
- struct rtable *nh_rth_input;
+ struct rtable __rcu *nh_rth_output;
+ struct rtable __rcu *nh_rth_input;
struct fnhe_hash_bucket *nh_exceptions;
};
diff --git a/net/core/dst.c b/net/core/dst.c
index d9e33eb..069d51d 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -258,15 +258,6 @@ again:
}
EXPORT_SYMBOL(dst_destroy);
-static void dst_rcu_destroy(struct rcu_head *head)
-{
- struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head);
-
- dst = dst_destroy(dst);
- if (dst)
- __dst_free(dst);
-}
-
void dst_release(struct dst_entry *dst)
{
if (dst) {
@@ -274,14 +265,10 @@ void dst_release(struct dst_entry *dst)
newrefcnt = atomic_dec_return(&dst->__refcnt);
WARN_ON(newrefcnt < 0);
- if (unlikely(dst->flags & (DST_NOCACHE | DST_RCU_FREE)) && !newrefcnt) {
- if (dst->flags & DST_RCU_FREE) {
- call_rcu_bh(&dst->rcu_head, dst_rcu_destroy);
- } else {
- dst = dst_destroy(dst);
- if (dst)
- __dst_free(dst);
- }
+ if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt) {
+ dst = dst_destroy(dst);
+ if (dst)
+ __dst_free(dst);
}
}
}
@@ -333,14 +320,11 @@ EXPORT_SYMBOL(__dst_destroy_metrics_generic);
*/
void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
- bool hold;
-
WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
/* If dst not in cache, we must take a reference, because
* dst_release() will destroy dst as soon as its refcount becomes zero
*/
- hold = (dst->flags & (DST_NOCACHE | DST_RCU_FREE)) == DST_NOCACHE;
- if (unlikely(hold)) {
+ if (unlikely(dst->flags & DST_NOCACHE)) {
dst_hold(dst);
skb_dst_set(skb, dst);
} else {
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 2671977..85a3604 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -184,12 +184,6 @@ static __inline__ unsigned int dn_hash(__le16 src, __le16 dst)
return dn_rt_hash_mask & (unsigned int)tmp;
}
-static inline void dst_rcu_free(struct rcu_head *head)
-{
- struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head);
- dst_free(dst);
-}
-
static inline void dnrt_free(struct dn_route *rt)
{
call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e55171f..625cf18 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -161,6 +161,21 @@ static void free_nh_exceptions(struct fib_nh *nh)
kfree(hash);
}
+static void rt_nexthop_free(struct rtable __rcu **rtp)
+{
+ struct rtable *rt = rcu_dereference_protected(*rtp, 1);
+
+ if (!rt)
+ return;
+
+ /* Not even needed : RCU_INIT_POINTER(*rtp, NULL);
+ * because we waited an RCU grace period before calling
+ * free_fib_info_rcu()
+ */
+
+ dst_free(&rt->dst);
+}
+
/* Release a nexthop info record */
static void free_fib_info_rcu(struct rcu_head *head)
{
@@ -171,10 +186,8 @@ static void free_fib_info_rcu(struct rcu_head *head)
dev_put(nexthop_nh->nh_dev);
if (nexthop_nh->nh_exceptions)
free_nh_exceptions(nexthop_nh);
- if (nexthop_nh->nh_rth_output)
- dst_release(&nexthop_nh->nh_rth_output->dst);
- if (nexthop_nh->nh_rth_input)
- dst_release(&nexthop_nh->nh_rth_input->dst);
+ rt_nexthop_free(&nexthop_nh->nh_rth_output);
+ rt_nexthop_free(&nexthop_nh->nh_rth_input);
} endfor_nexthops(fi);
release_net(fi->fib_net);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index d6eabcf..2bd1074 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1199,23 +1199,31 @@ restart:
fnhe->fnhe_stamp = jiffies;
}
+static inline void rt_free(struct rtable *rt)
+{
+ call_rcu(&rt->dst.rcu_head, dst_rcu_free);
+}
+
static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
{
- struct rtable *orig, *prev, **p = &nh->nh_rth_output;
+ struct rtable *orig, *prev, **p = (struct rtable **)&nh->nh_rth_output;
if (rt_is_input_route(rt))
- p = &nh->nh_rth_input;
+ p = (struct rtable **)&nh->nh_rth_input;
orig = *p;
- rt->dst.flags |= DST_RCU_FREE;
- dst_hold(&rt->dst);
prev = cmpxchg(p, orig, rt);
if (prev == orig) {
if (orig)
- dst_release(&orig->dst);
+ rt_free(orig);
} else {
- dst_release(&rt->dst);
+ /* Routes we intend to cache in the FIB nexthop have
+ * the DST_NOCACHE bit clear. However, if we are
+ * unsuccessful at storing this route into the cache
+ * we really need to set it.
+ */
+ rt->dst.flags |= DST_NOCACHE;
}
}
@@ -1412,7 +1420,7 @@ static int __mkroute_input(struct sk_buff *skb,
do_cache = false;
if (res->fi) {
if (!itag) {
- rth = FIB_RES_NH(*res).nh_rth_input;
+ rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
if (rt_cache_valid(rth)) {
skb_dst_set_noref(skb, &rth->dst);
goto out;
@@ -1574,7 +1582,7 @@ local_input:
do_cache = false;
if (res.fi) {
if (!itag) {
- rth = FIB_RES_NH(res).nh_rth_input;
+ rth = rcu_dereference(FIB_RES_NH(res).nh_rth_input);
if (rt_cache_valid(rth)) {
skb_dst_set_noref(skb, &rth->dst);
err = 0;
@@ -1742,7 +1750,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
if (fi) {
fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
if (!fnhe) {
- rth = FIB_RES_NH(*res).nh_rth_output;
+ rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_output);
if (rt_cache_valid(rth)) {
dst_hold(&rth->dst);
return rth;
^ permalink raw reply related
* RE: [PATCH 13/17] Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO
From: KY Srinivasan @ 2012-07-31 10:34 UTC (permalink / raw)
To: Ben Hutchings
Cc: Olaf Hering, gregkh@linuxfoundation.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
apw@canonical.com, devel@linuxdriverproject.org
In-Reply-To: <20120730191912.GH1894@decadent.org.uk>
> -----Original Message-----
> From: Ben Hutchings [mailto:ben@decadent.org.uk]
> Sent: Monday, July 30, 2012 3:19 PM
> To: KY Srinivasan
> Cc: Olaf Hering; gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; apw@canonical.com; netdev@vger.kernel.org
> Subject: Re: [PATCH 13/17] Tools: hv: Implement the KVP verb -
> KVP_OP_SET_IP_INFO
>
> On Mon, Jul 30, 2012 at 06:32:15PM +0000, KY Srinivasan wrote:
> >
> >
> > > -----Original Message-----
> > > From: Olaf Hering [mailto:olaf@aepfle.de]
> > > Sent: Monday, July 30, 2012 2:03 PM
> > > To: KY Srinivasan
> > > Cc: gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
> > > devel@linuxdriverproject.org; apw@canonical.com; netdev@vger.kernel.org;
> > > ben@decadent.org.uk
> > > Subject: Re: [PATCH 13/17] Tools: hv: Implement the KVP verb -
> > > KVP_OP_SET_IP_INFO
> > >
> > > On Tue, Jul 24, K. Y. Srinivasan wrote:
> > >
> > > > + /*
> > > > + * Set the configuration for the specified interface with
> > > > + * the information provided. Since there is no standard
> > > > + * way to configure an interface, we will have an external
> > > > + * script that does the job of configuring the interface and
> > > > + * flushing the configuration.
> > > > + *
> > > > + * The parameters passed to this external script are:
> > > > + * 1. A configuration file that has the specified configuration.
> > >
> > > Maybe this should be written as 'A info file that has the requested
> > > network configuration' or something like that.
> >
> > That is the idea. This configuration file simply reflects all the
> > information we have perhaps with some additional constant
> > information. The script is free to ignore what it does not need.
> [...]
>
> This does not strike me as a sensible interface. If scripts are
> 'free to ignore' information then the KVP interface becomes unreliable
> as a means for managing networking on Linux guests. I would suggest
> that at the least the script should be able to report that it did not
> recognise some parts of the configuration. This would be logged
> and/or reported back to the hypervisor.
>
> (This is separate from the issue of constant configuration lines;
> for some distributions the script might recognise but ignore them
> because they have no use on that distribution. I don't see the
> point in constant lines, but they don't seem to result in any
> unreliability.)
Ben,
I see your point. I have cleaned up the contents of the KVP produced
configuration file to not include constant information that can be
auto generated by the distro specific script if it needs to. Also, I have
tried to make the documentation of the contents of the file a little
better. I will send out these new patches soon. Still, there is a possibility that
some of the content of this file may be redundant on a specific distro and I think
that should be fine. For instance, per Olaf's suggestion, I have included a line that
specifies the interface name in the file (in addition to the mac address). Given the
current format of the name of the config file (where the interface name is embedded
in the config file name, this additional name entry may be redundant on some distros.
Once again, thank you for taking the time to review this code.
Regards,
K. Y
^ permalink raw reply
* Re: [PATCH] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Marc Kleine-Budde @ 2012-07-31 9:56 UTC (permalink / raw)
To: Olivier Sobrie; +Cc: Wolfgang Grandegger, linux-can, netdev
In-Reply-To: <20120730133323.GA13941@hposo>
[-- Attachment #1: Type: text/plain, Size: 51547 bytes --]
On 07/30/2012 03:33 PM, Olivier Sobrie wrote:
> Hi Marc,
>
> On Mon, Jul 30, 2012 at 01:11:46PM +0200, Marc Kleine-Budde wrote:
>> On 07/30/2012 07:32 AM, Olivier Sobrie wrote:
>>> This driver provides support for several Kvaser CAN/USB devices.
>>> Such kind of devices supports up to three can network interfaces.
>>>
>>> It has been tested with a Kvaser USB Leaf Light (one network interface)
>>> connected to a pch_can interface.
>>> The firmware version of the Kvaser device was 2.5.205.
>>
>> Please add linux-usb@vger.kernel.org to Cc for review of the USB part.
>
> Ok I'll do it when I send the new version of the patch.
> But it might be a good idea to add an entry in the MAINTAINERS file so
> that when someone sends a patch they are aware of this when the
> get_maintainer script is invoked.
Interesting Idea. We should discuss this here, however we should not
bother the USB List when sending USB unrelated patches.
>> Please combine .h and .c file. Please make use of netdev_LEVEL() for
>> error printing, not dev_LEVEL().
>
> I'll combine the .c and .h.
> I used the netdev_LEVEL() everywhere it was possible. It requires to
> have access to a pointer to netdev which is not always possible;
> that's the reason why I used dev_LEVEL().
I see, you used it when channel is invalid. So you have obviously no netdev.
>> Please review if all members of the struct kvaser_msg are properly
>> aligned. You never access the struct kvaser_msg_* members directly, as
>> they are unaligned. Please check for le16 and le32 access. You missed to
>> convert the bitrate.
>
> Indeed. Thanks. I'll check if I didn't missed another one.
Tnx
>> Please check if your driver survives hot-unplugging while sending and
>> receiving CAN frames at maximum laod.
>
> I tested this with two Kvaser sending frames with "cangen can0 -g 0 -i"
> never saw a crash.
Please test send sending and receiving at the same time.
>> More comments inline,
>> regards, Marc
>>
>>> List of Kvaser devices supported by the driver:
>>> - Kvaser Leaf prototype (P010v2 and v3)
>>> - Kvaser Leaf Light (P010v3)
>>> - Kvaser Leaf Professional HS
>>> - Kvaser Leaf SemiPro HS
>>> - Kvaser Leaf Professional LS
>>> - Kvaser Leaf Professional SWC
>>> - Kvaser Leaf Professional LIN
>>> - Kvaser Leaf SemiPro LS
>>> - Kvaser Leaf SemiPro SWC
>>> - Kvaser Memorator II, Prototype
>>> - Kvaser Memorator II HS/HS
>>> - Kvaser USBcan Professional HS/HS
>>> - Kvaser Leaf Light GI
>>> - Kvaser Leaf Professional HS (OBD-II connector)
>>> - Kvaser Memorator Professional HS/LS
>>> - Kvaser Leaf Light "China"
>>> - Kvaser BlackBird SemiPro
>>> - Kvaser OEM Mercury
>>> - Kvaser OEM Leaf
>>> - Kvaser USBcan R
>>>
>>> Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
>>> ---
>>> drivers/net/can/usb/Kconfig | 33 ++
>>> drivers/net/can/usb/Makefile | 1 +
>>> drivers/net/can/usb/kvaser_usb.c | 1062 ++++++++++++++++++++++++++++++++++++++
>>> drivers/net/can/usb/kvaser_usb.h | 237 +++++++++
>>> 4 files changed, 1333 insertions(+)
>>> create mode 100644 drivers/net/can/usb/kvaser_usb.c
>>> create mode 100644 drivers/net/can/usb/kvaser_usb.h
>>>
>>> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
>>> index 0a68768..578955f 100644
>>> --- a/drivers/net/can/usb/Kconfig
>>> +++ b/drivers/net/can/usb/Kconfig
>>> @@ -13,6 +13,39 @@ config CAN_ESD_USB2
>>> This driver supports the CAN-USB/2 interface
>>> from esd electronic system design gmbh (http://www.esd.eu).
>>>
>>> +config CAN_KVASER_USB
>>> + tristate "Kvaser CAN/USB interface"
>>> + ---help---
>>> + This driver adds support for Kvaser CAN/USB devices like Kvaser
>>> + Leaf Light.
>>> +
>>> + The driver gives support for the following devices:
>>> + - Kvaser Leaf prototype (P010v2 and v3)
>>> + - Kvaser Leaf Light (P010v3)
>>> + - Kvaser Leaf Professional HS
>>> + - Kvaser Leaf SemiPro HS
>>> + - Kvaser Leaf Professional LS
>>> + - Kvaser Leaf Professional SWC
>>> + - Kvaser Leaf Professional LIN
>>> + - Kvaser Leaf SemiPro LS
>>> + - Kvaser Leaf SemiPro SWC
>>> + - Kvaser Memorator II, Prototype
>>> + - Kvaser Memorator II HS/HS
>>> + - Kvaser USBcan Professional HS/HS
>>> + - Kvaser Leaf Light GI
>>> + - Kvaser Leaf Professional HS (OBD-II connector)
>>> + - Kvaser Memorator Professional HS/LS
>>> + - Kvaser Leaf Light "China"
>>> + - Kvaser BlackBird SemiPro
>>> + - Kvaser OEM Mercury
>>> + - Kvaser OEM Leaf
>>> + - Kvaser USBcan R
>>> +
>>> + If unsure, say N.
>>> +
>>> + To compile this driver as a module, choose M here: the
>>> + module will be called kvaser_usb.
>>> +
>>> config CAN_PEAK_USB
>>> tristate "PEAK PCAN-USB/USB Pro interfaces"
>>> ---help---
>>> diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
>>> index da6d1d3..80a2ee4 100644
>>> --- a/drivers/net/can/usb/Makefile
>>> +++ b/drivers/net/can/usb/Makefile
>>> @@ -4,6 +4,7 @@
>>>
>>> obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
>>> obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
>>> +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
>>> obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
>>>
>>> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
>>> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
>>> new file mode 100644
>>> index 0000000..4965480
>>> --- /dev/null
>>> +++ b/drivers/net/can/usb/kvaser_usb.c
>>> @@ -0,0 +1,1062 @@
>>> +/*
>>
>> Please add a license statement and probably your copyright:
>>
>> * This program is free software; you can redistribute it and/or
>> * modify it under the terms of the GNU General Public License as
>> * published by the Free Software Foundation version 2.
>>
>> You also should copy the copyright from the drivers you used:
>>
>>> + * Parts of this driver are based on the following:
>>> + * - Kvaser linux leaf driver (version 4.78)
>>
>> I just downloaded their driver and noticed that it's quite sparse on
>> stating the license the code is released under.
>> "doc/HTMLhelp/copyright.htx" is quite restrictive, the word GPL occurs 3
>> times, all in MODULE_LICENSE("GPL"). Running modinfo on the usbcan.ko
>> shows "license: GPL"
>
> I'll add the license statement.
> In fact it's the leaf.ko which is used for this device and it is under
> GPL as modinfo said.
I just talked to my boss and we're the same opinion, that
MODULE_LICENSE("GPL") is a technical term and not relevant if the
included license doesn't say a word about GPL. If the kvaser tarball
violates the GPL, however is written on different sheet of paper (as we
say in Germany).
So I cannot put my S-o-b under this driver as long as we haven't talked
to kvaser.
>>> + * - CAN driver for esd CAN-USB/2
>>> + */
>>> +
>>> +#include <linux/init.h>
>>> +#include <linux/completion.h>
>>> +#include <linux/module.h>
>>> +#include <linux/netdevice.h>
>>> +#include <linux/usb.h>
>>> +
>>> +#include <linux/can.h>
>>> +#include <linux/can/dev.h>
>>> +#include <linux/can/error.h>
>>> +
>>> +#include "kvaser_usb.h"
>>> +
>>> +struct kvaser_usb_tx_urb_context {
>>> + struct kvaser_usb_net_priv *priv;
>>
>> Huh - how does this work without forward declaration?
>
> It works.
Yes, obviously :)
> "In C and C++ it is possible to declare pointers to structs before
> declaring their struct layout, provided the pointers are not
> dereferenced--this is known as forward declaration."
>
> See http://www.linuxtopia.org/online_books/an_introduction_to_gcc/gccintro_94.html
Thanks for the link.
>>
>>> + u32 echo_index;
>>> + int dlc;
>>> +};
>>> +
>>> +struct kvaser_usb {
>>> + struct usb_device *udev;
>>> + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
>>> +
>>> + struct usb_anchor rx_submitted;
>>> +
>>> + u32 fw_version;
>>> + unsigned int nchannels;
>>> +
>>> + bool rxinitdone;
>>> +};
>>> +
>>> +struct kvaser_usb_net_priv {
>>> + struct can_priv can;
>>> +
>>> + atomic_t active_tx_urbs;
>>> + struct usb_anchor tx_submitted;
>>> + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
>>> +
>>> + int open_time;
>>
>> please remove open_time
>
> Ok.
>
>>
>>> + struct completion start_stop_comp;
>>> +
>>> + struct kvaser_usb *dev;
>>> + struct net_device *netdev;
>>> + int channel;
>>> + struct can_berr_counter bec;
>>> +};
>>> +
>>> +static struct usb_device_id kvaser_usb_table[] = {
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
>>> + .driver_info = KVASER_HAS_SILENT_MODE },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID) },
>>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID) },
>>> + { }
>>> +};
>>> +MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
>>> +
>>> +static int kvaser_usb_send_msg(const struct kvaser_usb *dev,
>>> + struct kvaser_msg *msg)
>> inline?
>
> Ok.
>
>>> +{
>>> + int actual_len;
>>> +
>>> + return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 1),
>> ^
>> Can you please introduce a #define for this.
>
> Ok. No problem.
>
>>
>>> + msg, msg->len, &actual_len, USB_SEND_TIMEOUT);
>>> +}
>>> +
>>> +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
>>> + struct kvaser_msg *msg)
>>> +{
>>> + struct kvaser_msg *tmp;
>>> + void *buf;
>>> + int actual_len;
>>> + int err;
>>> + int pos = 0;
>>> +
>>> + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
>>> + if (!buf)
>>> + return -ENOMEM;
>>> +
>>> + err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 129),
>> ^^^
>> dito
>
> Ok too.
>
>>
>>> + buf, RX_BUFFER_SIZE, &actual_len,
>>> + USB_RECEIVE_TIMEOUT);
>>> + if (err < 0) {
>>> + kfree(buf);
>>> + return err;
>>> + }
>>> +
>>> + while (pos < actual_len) {
>>
>> Please check that pos + sizeof(*msg) is < actual_len, as you fill access
>> it later.
>
> I'll instead perform a check on 'pos + tmp->len < actual_len' and copy
> only tmp->len instead of sizeof(*msg).
> Thanks.
Even better, saves some bytes to be copied. Take care not to deref tmp,
unless you checked that tmp is in valid memory.
>>
>>> + tmp = buf + pos;
>>> +
>>> + if (!tmp->len)
>>> + break;
>>> +
>>> + if (tmp->id == id) {
>>> + memcpy(msg, tmp, sizeof(*msg));
>>> + kfree(buf);
>>> + return 0;
>>> + }
>>> +
>>> + pos += tmp->len;
>>> + }
>>> +
>>> + kfree(buf);
>>> +
>>> + return -EINVAL;
>>> +}
>>> +
>>> +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
>>> + u8 msg_id, int channel)
>>> +{
>>> + struct kvaser_msg msg;
>>> + int err;
>>> +
>>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
>>> + msg.id = msg_id;
>>> + msg.u.simple.channel = channel;
>>> + msg.u.simple.tid = 0xff;
>>
>> Please use C99 struct initializer.
>>
>> struct kvaser_msg msg = {
>> .len = ,
>> .id =,
>> };
>
> Ok.
>
>>
>>
>>> +
>>> + err = kvaser_usb_send_msg(dev, &msg);
>>
>> just:
>> return err;
>
> Ok.
>
>>
>>> + if (err)
>>> + return err;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
>>> +{
>>> + struct kvaser_msg msg;
>>> + int err;
>>> +
>>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
>>> + if (err)
>>> + return err;
>>> +
>>> + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
>>> + if (err)
>>> + return err;
>>> +
>>> + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
>>> +{
>>> + struct kvaser_msg msg;
>>> + int err;
>>> +
>>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
>>> + if (err)
>>> + return err;
>>> +
>>> + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
>>> + if (err)
>>> + return err;
>>> +
>>> + dev->nchannels = msg.u.cardinfo.nchannels;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
>>> + const struct kvaser_msg *msg)
>>> +{
>>> + struct net_device_stats *stats;
>>> + struct kvaser_usb_tx_urb_context *context;
>>> + struct kvaser_usb_net_priv *priv;
>>> + u8 channel = msg->u.tx_acknowledge.channel;
>>> + u8 tid = msg->u.tx_acknowledge.tid;
>>> +
>>> + if (channel >= dev->nchannels) {
>>> + dev_err(dev->udev->dev.parent,
>>> + "Invalid channel number (%d)\n", channel);
>>> + return;
>>> + }
>>
>> can you do a check for (channel >= dev->nchannels), in a central place?
>> e.g. kvaser_usb_handle_message()?
>
> The problem is that channel is not always at the same place in the
> messages I get from the hardware. 'tid' and 'channel' are inverted for
> tx and rx frames.
> e.g.
Grr...who's written that firmware :D
>
> struct kvaser_msg_tx_can {
> u8 channel;
> u8 tid;
> u8 msg[14];
> u8 padding;
> u8 flags;
> } __packed;
>
> struct kvaser_msg_busparams {
> u8 tid;
> u8 channel;
> __le32 bitrate;
> u8 tseg1;
> u8 tseg2;
> u8 sjw;
> u8 no_samp;
> } __packed;
>
>>
>>> +
>>> + priv = dev->nets[channel];
>>> +
>>> + if (!netif_device_present(priv->netdev))
>>> + return;
>>> +
>>> + stats = &priv->netdev->stats;
>>> +
>>> + context = &priv->tx_contexts[tid % MAX_TX_URBS];
>>> +
>>> + /*
>>> + * It looks like the firmware never sets the flags field of the
>>> + * tx_acknowledge frame and never reports a transmit failure.
>>> + * If the can message can't be transmited (e.g. incompatible
>>> + * bitrates), a frame CMD_CAN_ERROR_EVENT is sent (with a null
>>> + * tid) and the firmware tries to transmit again the packet until
>>> + * it succeeds. Once the packet is successfully transmitted, then
>>> + * the tx_acknowledge frame is sent.
>>> + */
>>> +
>>> + stats->tx_packets++;
>>> + stats->tx_bytes += context->dlc;
>>> + can_get_echo_skb(priv->netdev, context->echo_index);
>>> +
>>> + context->echo_index = MAX_TX_URBS;
>>> + atomic_dec(&priv->active_tx_urbs);
>>> +
>>> + netif_wake_queue(priv->netdev);
>>> +}
>>> +
>>> +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>>> + const struct kvaser_msg *msg)
>>> +{
>>> + struct can_frame *cf;
>>> + struct sk_buff *skb;
>>> + struct net_device_stats *stats;
>>> + struct kvaser_usb_net_priv *priv;
>>> + u8 channel, status, txerr, rxerr;
>>> +
>>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
>>> + channel = msg->u.error_event.channel;
>>> + status = msg->u.error_event.status;
>>> + txerr = msg->u.error_event.tx_errors_count;
>>> + rxerr = msg->u.error_event.rx_errors_count;
>>> + } else {
>>> + channel = msg->u.chip_state_event.channel;
>>> + status = msg->u.chip_state_event.status;
>>> + txerr = msg->u.chip_state_event.tx_errors_count;
>>> + rxerr = msg->u.chip_state_event.rx_errors_count;
>>> + }
>>> +
>>> + if (channel >= dev->nchannels) {
>>> + dev_err(dev->udev->dev.parent,
>>> + "Invalid channel number (%d)\n", channel);
>>> + return;
>>> + }
>>> +
>>> + priv = dev->nets[channel];
>>> + stats = &priv->netdev->stats;
>>> +
>>> + skb = alloc_can_err_skb(priv->netdev, &cf);
>>> + if (!skb) {
>>> + stats->rx_dropped++;
>>> + return;
>>> + }
>>> +
>>> + if ((status & M16C_STATE_BUS_OFF) ||
>>> + (status & M16C_STATE_BUS_RESET)) {
>>> + priv->can.state = CAN_STATE_BUS_OFF;
>>> + cf->can_id |= CAN_ERR_BUSOFF;
>>> + can_bus_off(priv->netdev);
you should increment priv->can.can_stats.bus_off
What does the firmware do in this state? Does it automatically try to
recover and try to send the outstanding frames?
If so, you should turn of the CAN interface, it possible. See:
http://lxr.free-electrons.com/source/drivers/net/can/at91_can.c#L986
Please test Bus-Off behaviour:
- setup working CAN network
- short circuit CAN-H and CAN-L wires
- start "candump any,0:0,#FFFFFFFF" on one shell
- send one can frame on the other
then
- remove the short circuit
- see if the can frame is transmitted to the other side
- it should show up as an echo'ed CAN frame on the sender side
Repeat the same test with disconnecting CAN-H and CAN-L from the other
CAN station instead of short circuit.
Please send the output from candump.
>>> + } else if (status & M16C_STATE_BUS_ERROR) {
>>> + priv->can.state = CAN_STATE_ERROR_WARNING;
>>> + priv->can.can_stats.error_warning++;
>>> + } else if (status & M16C_STATE_BUS_PASSIVE) {
>>> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
>>> + priv->can.can_stats.error_passive++;
>>> + } else {
>>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
>>> + cf->can_id |= CAN_ERR_PROT;
>>> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
>>> + }
>>> +
>>> + if (msg->id == CMD_CAN_ERROR_EVENT) {
>>> + u8 error_factor = msg->u.error_event.error_factor;
>>> +
>>> + priv->can.can_stats.bus_error++;
>>> + stats->rx_errors++;
>>> +
>>> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
>>> +
>>> + if ((priv->can.state == CAN_STATE_ERROR_WARNING) ||
>>> + (priv->can.state == CAN_STATE_ERROR_PASSIVE)) {
>>> + cf->data[1] = (txerr > rxerr) ?
>>> + CAN_ERR_CRTL_TX_PASSIVE
>>> + : CAN_ERR_CRTL_RX_PASSIVE;
>>> + }
>>> +
>>> + if (error_factor & M16C_EF_ACKE)
>>> + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
>>> + CAN_ERR_PROT_LOC_ACK_DEL);
>>> + if (error_factor & M16C_EF_CRCE)
>>> + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
>>> + CAN_ERR_PROT_LOC_CRC_DEL);
>>> + if (error_factor & M16C_EF_FORME)
>>> + cf->data[2] |= CAN_ERR_PROT_FORM;
>>> + if (error_factor & M16C_EF_STFE)
>>> + cf->data[2] |= CAN_ERR_PROT_STUFF;
>>> + if (error_factor & M16C_EF_BITE0)
>>> + cf->data[2] |= CAN_ERR_PROT_BIT0;
>>> + if (error_factor & M16C_EF_BITE1)
>>> + cf->data[2] |= CAN_ERR_PROT_BIT1;
>>> + if (error_factor & M16C_EF_TRE)
>>> + cf->data[2] |= CAN_ERR_PROT_TX;
>>> + }
>>> +
>>> + cf->data[6] = txerr;
>>> + cf->data[7] = rxerr;
>>> +
>>> + netif_rx(skb);
>>> +
>>> + priv->bec.txerr = txerr;
>>> + priv->bec.rxerr = rxerr;
>>> +
>>> + stats->rx_packets++;
>>> + stats->rx_bytes += cf->can_dlc;
>>> +}
>>> +
>>> +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
>>> + const struct kvaser_msg *msg)
>>> +{
>>> + struct kvaser_usb_net_priv *priv;
>>> + struct can_frame *cf;
>>> + struct sk_buff *skb;
>>> + struct net_device_stats *stats;
>>> + u8 channel = msg->u.rx_can.channel;
>>> +
>>> + if (channel >= dev->nchannels) {
>>> + dev_err(dev->udev->dev.parent,
>>> + "Invalid channel number (%d)\n", channel);
>>> + return;
>>> + }
>>> +
>>> + priv = dev->nets[channel];
>>> + stats = &priv->netdev->stats;
>>> +
>>> + skb = alloc_can_skb(priv->netdev, &cf);
>>> + if (skb == NULL) {
>>> + stats->tx_dropped++;
>>> + return;
>>> + }
>>> +
>>> + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
>>> + (msg->u.rx_can.msg[1] & 0x3f);
>>> + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
>>> +
>>> + if (msg->id == CMD_RX_EXT_MESSAGE) {
>>> + cf->can_id <<= 18;
>>> + cf->can_id += ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
>> |=
>>
>> is more appropriate here
>
> Ok.
>
>>
>>> + ((msg->u.rx_can.msg[3] & 0xff) << 6) |
>>> + (msg->u.rx_can.msg[4] & 0x3f);
>>> + cf->can_id |= CAN_EFF_FLAG;
>>> + }
>>> +
>>> + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) {
>>> + cf->can_id |= CAN_RTR_FLAG;
>>> + } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
>>> + MSG_FLAG_NERR)) {
>>> + cf->can_id |= CAN_ERR_FLAG;
>>> + cf->can_dlc = CAN_ERR_DLC;
>>
>> What kind of error is this? Can you set cf->data? What about the
>> original cd->can_id? What about the stats->rx_*error* stats?
>
> Good question I've to take a look to this.
>
>>
>>> + } else if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
>>> + cf->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
>>> + cf->can_dlc = CAN_ERR_DLC;
>>> + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
>>> +
>>> + stats->rx_over_errors++;
>>> + stats->rx_errors++;
>>> + } else if (!msg->u.rx_can.flag) {
>>> + memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
>>> + } else {
>>> + kfree_skb(skb);
>>> + return;
>>> + }
>>> +
>>> + netif_rx(skb);
>>> +
>>> + stats->rx_packets++;
>>> + stats->rx_bytes += cf->can_dlc;
>>> +}
>>> +
>>> +static void kvaser_usb_start_stop_chip_reply(const struct kvaser_usb *dev,
>>> + const struct kvaser_msg *msg)
>>> +{
>>> + struct kvaser_usb_net_priv *priv;
>>> + u8 channel = msg->u.simple.channel;
>>> +
>>> + if (channel >= dev->nchannels) {
>>> + dev_err(dev->udev->dev.parent,
>>> + "Invalid channel number (%d)\n", channel);
>>> + return;
>>> + }
>>> +
>>> + priv = dev->nets[channel];
>>> +
>>> + complete(&priv->start_stop_comp);
>>> +}
>>> +
>>> +static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
>>> + const struct kvaser_msg *msg)
>>> +{
>>> + switch (msg->id) {
>>> + case CMD_START_CHIP_REPLY:
>>> + case CMD_STOP_CHIP_REPLY:
>>> + kvaser_usb_start_stop_chip_reply(dev, msg);
>>> + break;
>>> +
>>> + case CMD_RX_STD_MESSAGE:
>>> + case CMD_RX_EXT_MESSAGE:
>>> + kvaser_usb_rx_can_msg(dev, msg);
>>> + break;
>>> +
>>> + case CMD_CHIP_STATE_EVENT:
>>> + case CMD_CAN_ERROR_EVENT:
>>> + kvaser_usb_rx_error(dev, msg);
>>> + break;
>>> +
>>> + case CMD_TX_ACKNOWLEDGE:
>>> + kvaser_usb_tx_acknowledge(dev, msg);
>>> + break;
>>> +
>>> + default:
>>> + dev_warn(dev->udev->dev.parent,
>>> + "Unhandled message (%d)\n", msg->id);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static void kvaser_usb_read_bulk_callback(struct urb *urb)
>>> +{
>>> + struct kvaser_usb *dev = urb->context;
>>> + struct kvaser_msg *msg;
>>> + int pos = 0;
>>> + int err, i;
>>> +
>>> + switch (urb->status) {
>>> + case 0:
>>> + break;
>>> + case -ENOENT:
>>> + case -ESHUTDOWN:
>>> + return;
>>> + default:
>>> + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
>>> + urb->status);
>>> + goto resubmit_urb;
>>> + }
>>> +
>>> + while (pos < urb->actual_length) {
>>
>> please check here for pos + sizeof(*msg), too
>
> Same as above.
>
>>
>>> + msg = urb->transfer_buffer + pos;
>>> +
>>> + if (!msg->len)
>>> + break;
>>> +
>>> + kvaser_usb_handle_message(dev, msg);
>>> +
>>> + if (pos > urb->actual_length) {
>>> + dev_err(dev->udev->dev.parent, "Format error\n");
>>> + break;
>>> + }
>>> +
>>> + pos += msg->len;
>>> + }
>>> +
>>> +resubmit_urb:
>>> + usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 129),
>> ^^^
>>
>> use #define
>
> Ok.
>
>>
>>> + urb->transfer_buffer, RX_BUFFER_SIZE,
>>> + kvaser_usb_read_bulk_callback, dev);
>>> +
>>> + err = usb_submit_urb(urb, GFP_ATOMIC);
>>> + if (err == -ENODEV) {
>>> + for (i = 0; i < dev->nchannels; i++) {
>>> + if (!dev->nets[i])
>>> + continue;
>>> +
>>> + netif_device_detach(dev->nets[i]->netdev);
>>> + }
>>> + } else if (err) {
>>> + dev_err(dev->udev->dev.parent,
>>> + "Failed resubmitting read bulk urb: %d\n", err);
>>> + }
>>> +
>>> + return;
>>> +}
>>> +
>>> +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
>>> +{
>>> + int i, err = 0;
>>> +
>>> + if (dev->rxinitdone)
>>> + return 0;
>>> +
>>> + for (i = 0; i < MAX_RX_URBS; i++) {
>>> + struct urb *urb = NULL;
>>> + u8 *buf = NULL;
>>> +
>>> + urb = usb_alloc_urb(0, GFP_KERNEL);
>>> + if (!urb) {
>>> + dev_warn(dev->udev->dev.parent,
>>> + "No memory left for URBs\n");
>>> + err = -ENOMEM;
>>> + break;
>>> + }
>>> +
>>> + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
>>> + GFP_KERNEL, &urb->transfer_dma);
>>> + if (!buf) {
>>> + dev_warn(dev->udev->dev.parent,
>>> + "No memory left for USB buffer\n");
>>> + usb_free_urb(urb);
>>> + err = -ENOMEM;
>>> + break;
>>> + }
>>> +
>>> + usb_fill_bulk_urb(urb, dev->udev,
>>> + usb_rcvbulkpipe(dev->udev, 129),
>>
>> use #define
>
> Ok.
>
>>
>>> + buf, RX_BUFFER_SIZE,
>>> + kvaser_usb_read_bulk_callback, dev);
>>> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>>> + usb_anchor_urb(urb, &dev->rx_submitted);
>>> +
>>> + err = usb_submit_urb(urb, GFP_KERNEL);
>>> + if (err) {
>>> + usb_unanchor_urb(urb);
>>> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
>>> + urb->transfer_dma);
>>> + break;
>>> + }
>>> +
>>> + usb_free_urb(urb);
>>> + }
>>> +
>>> + if (i == 0) {
>>> + dev_warn(dev->udev->dev.parent,
>>> + "Cannot setup read URBs, error %d\n", err);
>>> + return err;
>>> + } else if (i < MAX_RX_URBS) {
>>> + dev_warn(dev->udev->dev.parent,
>>> + "RX performances may be slow\n");
>>> + }
>>> +
>>> + dev->rxinitdone = true;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
>>> +{
>>> + struct kvaser_msg msg;
>>> +
>>> + memset(&msg, 0x00, sizeof(msg));
>>> + msg.id = CMD_SET_CTRL_MODE;
>>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_ctrl_mode);
>>> + msg.u.ctrl_mode.tid = 0xff;
>>> + msg.u.ctrl_mode.channel = priv->channel;
>>
>> please use C99 struct initializers
>
> Ok.
>
>>
>>> +
>>> + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
>>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
>>> + else
>>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
>>> +
>>> + return kvaser_usb_send_msg(priv->dev, &msg);
>>> +}
>>> +
>>> +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
>>> +{
>>> + int err;
>>> +
>>> + init_completion(&priv->start_stop_comp);
>>> +
>>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
>>> + priv->channel);
>>> + if (err)
>>> + return err;
>>> +
>>> + if (!wait_for_completion_timeout(&priv->start_stop_comp,
>>> + msecs_to_jiffies(START_TIMEOUT)))
>>> + return -ETIMEDOUT;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_open(struct net_device *netdev)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> + struct kvaser_usb *dev = priv->dev;
>>> + int err;
>>> +
>>> + err = open_candev(netdev);
>>> + if (err)
>>> + return err;
>>> +
>>> + err = kvaser_usb_setup_rx_urbs(dev);
>>> + if (err)
>>> + return err;
>>> +
>>> + err = kvaser_usb_set_opt_mode(priv);
>>> + if (err)
>>> + return err;
>>> +
>>> + err = kvaser_usb_start_chip(priv);
>>> + if (err) {
>>> + netdev_warn(netdev, "Cannot start device, error %d\n", err);
>>> + close_candev(netdev);
>>> + return err;
>>> + }
>>> +
>>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
>>> + priv->open_time = jiffies;
>>> + netif_start_queue(netdev);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
>>> +{
>>> + int i;
>>> +
>>> + usb_kill_anchored_urbs(&priv->tx_submitted);
>>> + atomic_set(&priv->active_tx_urbs, 0);
>>> +
>>> + for (i = 0; i < MAX_TX_URBS; i++)
>> ARRAY_SIZE(priv->tx_contexts) instead of MAX_TX_URBS
>
> Ok.
>
>>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
>>> +}
>>> +
>>> +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
>>> +{
>>> + int i;
>>> +
>>> + usb_kill_anchored_urbs(&dev->rx_submitted);
>>> +
>>> + for (i = 0; i < MAX_NET_DEVICES; i++) {
>> ARRAY_SIZE()
>>> + struct kvaser_usb_net_priv *priv = dev->nets[i];
>>> +
>>> + if (priv)
>>> + kvaser_usb_unlink_tx_urbs(priv);
>>> + }
>>> +}
>>> +
>>> +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
>>> +{
>>> + int err;
>>> +
>>> + init_completion(&priv->start_stop_comp);
>>> +
>>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
>>> + priv->channel);
>>> + if (err)
>>> + return err;
>>> +
>>> + if (!wait_for_completion_timeout(&priv->start_stop_comp,
>>> + msecs_to_jiffies(STOP_TIMEOUT)))
>>> + return -ETIMEDOUT;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
>>> +{
>>> + struct kvaser_msg msg;
>>> +
>>> + memset(&msg, 0x00, sizeof(msg));
>>> + msg.id = CMD_FLUSH_QUEUE;
>>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_flush_queue);
>>> + msg.u.flush_queue.channel = priv->channel;
>> C99 initialziers, please
>
> Ok.
>
>>> +
>>> + return kvaser_usb_send_msg(priv->dev, &msg);
>>> +}
>>> +
>>> +static int kvaser_usb_close(struct net_device *netdev)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> + int err;
>>> +
>>> + netif_stop_queue(netdev);
>>> +
>>> + err = kvaser_usb_flush_queue(priv);
>>> + if (err)
>>> + netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
>>> +
>>> + err = kvaser_usb_stop_chip(priv);
>>> + if (err) {
>>> + netdev_warn(netdev, "Cannot stop device, error %d\n", err);
>>> + return err;
>>> + }
>>> +
>>> + kvaser_usb_unlink_tx_urbs(priv);
>>> +
>>> + priv->can.state = CAN_STATE_STOPPED;
>>> + close_candev(priv->netdev);
>>> + priv->open_time = 0;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static void kvaser_usb_write_bulk_callback(struct urb *urb)
>>> +{
>>> + struct kvaser_usb_tx_urb_context *context = urb->context;
>>> + struct kvaser_usb_net_priv *priv;
>>> + struct net_device *netdev;
>>> +
>>> + if (WARN_ON(!context))
>>> + return;
>>> +
>>> + priv = context->priv;
>>> + netdev = priv->netdev;
>>> +
>>> + usb_free_coherent(urb->dev, urb->transfer_buffer_length,
>>> + urb->transfer_buffer, urb->transfer_dma);
>>> +
>>> + if (!netif_device_present(netdev))
>>> + return;
>>> +
>>> + if (urb->status)
>>> + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
>>> +
>>> + netdev->trans_start = jiffies;
>>
>> Is trans_start needed? at least for non-usb devices it works without.
>
> I don't know, I'll try to figure this out.
> I see it's used in the two others CAN/USB drivers, 'ems_usb.c' and
> 'esd_usb2.c'
>
>>
>>> +}
>>> +
>>> +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
>>> + struct net_device *netdev)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> + struct kvaser_usb *dev = priv->dev;
>>> + struct net_device_stats *stats = &netdev->stats;
>>> + struct can_frame *cf = (struct can_frame *)skb->data;
>>> + struct kvaser_usb_tx_urb_context *context = NULL;
>>> + struct urb *urb;
>>> + void *buf;
>>> + struct kvaser_msg *msg;
>>> + int i, err;
>>> + int ret = NETDEV_TX_OK;
>>> +
>>> + if (can_dropped_invalid_skb(netdev, skb))
>>> + return NETDEV_TX_OK;
>>> +
>>> + urb = usb_alloc_urb(0, GFP_ATOMIC);
>>> + if (!urb) {
>>> + netdev_err(netdev, "No memory left for URBs\n");
>>> + stats->tx_dropped++;
>>> + dev_kfree_skb(skb);
>>> + goto nourbmem;
>>> + }
>>> +
>>> + buf = usb_alloc_coherent(dev->udev, sizeof(struct kvaser_msg),
>>> + GFP_ATOMIC, &urb->transfer_dma);
>>> + if (!buf) {
>>> + netdev_err(netdev, "No memory left for USB buffer\n");
>>> + stats->tx_dropped++;
>>> + dev_kfree_skb(skb);
>>> + goto nobufmem;
>>> + }
>>> +
>>> + msg = (struct kvaser_msg *)buf;
>>> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
>>> + msg->u.tx_can.flags = 0;
>>> + msg->u.tx_can.channel = priv->channel;
>>> +
>>> + if (cf->can_id & CAN_EFF_FLAG) {
>>> + msg->id = CMD_TX_EXT_MESSAGE;
>>> + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
>>> + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
>>> + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
>>> + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
>>> + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
>>> + } else {
>>> + msg->id = CMD_TX_STD_MESSAGE;
>>> + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
>>> + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
>>> + }
>>> +
>>> + msg->u.tx_can.msg[5] = cf->can_dlc;
>>> + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
>>> +
>>> + if (cf->can_id & CAN_RTR_FLAG)
>>> + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
>>> +
>>> + for (i = 0; i < MAX_TX_URBS; i++) {
>> ARRAY_SIZE
>
> Ok.
>
>>> + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
>>> + context = &priv->tx_contexts[i];
>>> + break;
>>> + }
>>> + }
>>> +
>>> + if (!context) {
>>> + netdev_warn(netdev, "cannot find free context\n");
>>> + ret = NETDEV_TX_BUSY;
>>> + goto releasebuf;
>>> + }
>>> +
>>> + context->priv = priv;
>>> + context->echo_index = i;
>>> + context->dlc = cf->can_dlc;
>>> +
>>> + msg->u.tx_can.tid = context->echo_index;
>>> +
>>> + usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
>>> + buf, msg->len,
>>> + kvaser_usb_write_bulk_callback, context);
>>> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>>> + usb_anchor_urb(urb, &priv->tx_submitted);
>>> +
>>> + can_put_echo_skb(skb, netdev, context->echo_index);
>>> +
>>> + atomic_inc(&priv->active_tx_urbs);
>>> +
>>> + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
>>> + netif_stop_queue(netdev);
>>> +
>>> + err = usb_submit_urb(urb, GFP_ATOMIC);
>>> + if (unlikely(err)) {
>>> + can_free_echo_skb(netdev, context->echo_index);
>>> +
>>> + atomic_dec(&priv->active_tx_urbs);
>>> + usb_unanchor_urb(urb);
>>> +
>>> + stats->tx_dropped++;
>>> +
>>> + if (err == -ENODEV)
>>> + netif_device_detach(netdev);
>>> + else
>>> + netdev_warn(netdev, "Failed tx_urb %d\n", err);
>>> +
>>> + goto releasebuf;
>>> + }
>>> +
>>> + netdev->trans_start = jiffies;
>>> +
>>> + usb_free_urb(urb);
>>> +
>>> + return NETDEV_TX_OK;
>>> +
>>> +releasebuf:
>>> + usb_free_coherent(dev->udev, sizeof(struct kvaser_msg),
>>> + buf, urb->transfer_dma);
>>> +nobufmem:
>>> + usb_free_urb(urb);
>>> +nourbmem:
>>> + return ret;
>>> +}
>>> +
>>> +static const struct net_device_ops kvaser_usb_netdev_ops = {
>>> + .ndo_open = kvaser_usb_open,
>>> + .ndo_stop = kvaser_usb_close,
>>> + .ndo_start_xmit = kvaser_usb_start_xmit,
>>> +};
>>> +
>>> +static struct can_bittiming_const kvaser_usb_bittiming_const = {
>>> + .name = "kvaser_usb",
>>> + .tseg1_min = KVASER_USB_TSEG1_MIN,
>>> + .tseg1_max = KVASER_USB_TSEG1_MAX,
>>> + .tseg2_min = KVASER_USB_TSEG2_MIN,
>>> + .tseg2_max = KVASER_USB_TSEG2_MAX,
>>> + .sjw_max = KVASER_USB_SJW_MAX,
>>> + .brp_min = KVASER_USB_BRP_MIN,
>>> + .brp_max = KVASER_USB_BRP_MAX,
>>> + .brp_inc = KVASER_USB_BRP_INC,
>>> +};
>>> +
>>> +static int kvaser_usb_set_bittiming(struct net_device *netdev)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> + struct can_bittiming *bt = &priv->can.bittiming;
>>> + struct kvaser_usb *dev = priv->dev;
>>> + struct kvaser_msg msg;
>>> +
>>> + msg.id = CMD_SET_BUS_PARAMS;
>>> + msg.len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_busparams);
>>> + msg.u.busparams.channel = priv->channel;
>>> + msg.u.busparams.tid = 0xff;
>>> + msg.u.busparams.bitrate = bt->bitrate;
>>
>> bitrate is le32
>
> Indeed ! I'll fix this.
>
>>
>>> + msg.u.busparams.sjw = bt->sjw;
>>> + msg.u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
>>> + msg.u.busparams.tseg2 = bt->phase_seg2;
>>
>> C99 initializers, please
>>
>>> +
>>> + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
>>> + msg.u.busparams.no_samp = 3;
>>> + else
>>> + msg.u.busparams.no_samp = 1;
>>> +
>>> + return kvaser_usb_send_msg(dev, &msg);
>>> +}
>>> +
>>> +static int kvaser_usb_set_mode(struct net_device *netdev,
>>> + enum can_mode mode)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> +
>>> + if (!priv->open_time)
>>> + return -EINVAL;
>>> +
>>> + switch (mode) {
>>> + case CAN_MODE_START:
>>> + if (netif_queue_stopped(netdev))
>>> + netif_wake_queue(netdev);
>>
>> No need to restart your USB device?
>
> No. I don't think so.
> The module continuously tries to transmit the frame and isn't stopped.
> So there is no need to restart it if it has been explicitely stopped.
>
> When it cannot transmit, the module try again and sends continuously
> CMD_CAN_ERROR_EVENT frames until it succeeds to transmit the frame.
> If the device is stopped with the command CMD_STOP_CHIP then it stops
> sending these CMD_CAN_ERROR_EVENT.
> Should I handle this in another manner?
If the firmware automatically recovers from busoff (like the at91 does),
you should stop the chip it priv->can.restart_ms == 0 and let the chip
continue working otherwise.
>
>>
>>> + break;
>>> + default:
>>> + return -EOPNOTSUPP;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
>>> + struct can_berr_counter *bec)
>>> +{
>>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>>> +
>>> + bec->txerr = priv->bec.txerr;
>>> + bec->rxerr = priv->bec.rxerr;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_init_one(struct usb_interface *intf,
>>> + const struct usb_device_id *id, int channel)
>>> +{
>>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
>>> + struct net_device *netdev;
>>> + struct kvaser_usb_net_priv *priv;
>>> + int i, err;
>>> +
>>> + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
>>> + if (!netdev) {
>>> + dev_err(&intf->dev, "Cannot alloc candev\n");
>>> + return -ENOMEM;
>>> + }
>>> +
>>> + priv = netdev_priv(netdev);
>>> +
>>> + init_usb_anchor(&priv->tx_submitted);
>>> + atomic_set(&priv->active_tx_urbs, 0);
>>> +
>>> + for (i = 0; i < MAX_TX_URBS; i++)
>>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
>>> +
>>> + priv->dev = dev;
>>> + priv->netdev = netdev;
>>> + priv->channel = channel;
>>> +
>>> + priv->can.state = CAN_STATE_STOPPED;
>>> + priv->can.clock.freq = CAN_USB_CLOCK;
>>> + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
>>> + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
>>> + priv->can.do_set_mode = kvaser_usb_set_mode;
>>> + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
>>> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
>>> + if (id->driver_info & KVASER_HAS_SILENT_MODE)
>>> + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
>>> +
>>> + netdev->flags |= IFF_ECHO;
>>> +
>>> + netdev->netdev_ops = &kvaser_usb_netdev_ops;
>>> +
>>> + SET_NETDEV_DEV(netdev, &intf->dev);
>>> +
>>> + err = register_candev(netdev);
>>> + if (err) {
>>> + dev_err(&intf->dev, "Failed to register can device\n");
>>> + free_candev(netdev);
>>> + return err;
>>> + }
>>> +
>>> + dev->nets[channel] = priv;
>>> + netdev_info(netdev, "device %s registered\n", netdev->name);
>>
>> netdev_info should take care of printing the device's name.
>
> Ok.
>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int kvaser_usb_probe(struct usb_interface *intf,
>>> + const struct usb_device_id *id)
>>> +{
>>> + struct kvaser_usb *dev;
>>> + int err = -ENOMEM;
>>> + int i;
>>> +
>>> + dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>>
>> Who will free dev on driver unload? Please make use of devm_kzalloc().
>
> Ok. kfree is missing is disconnect().
> I'll replace it by devm_kzalloc() and devm_free().
The beauty of devm_kzalloc is you don't have to call *_free, its
automatically called if probe fails or when remove function has been called.
>
>>
>>> + if (!dev)
>>> + return -ENOMEM;
>>> +
>>> + dev->udev = interface_to_usbdev(intf);
>>> +
>>> + init_usb_anchor(&dev->rx_submitted);
>>> +
>>> + usb_set_intfdata(intf, dev);
>>> +
>>> + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, 0)) {
>>> + dev_err(&intf->dev, "Cannot reset kvaser\n");
>>> + goto error;
>>> + }
>>> +
>>> + if (kvaser_usb_get_software_info(dev)) {
>>> + dev_err(&intf->dev, "Cannot get software infos\n");
>>> + goto error;
>>> + }
>>> +
>>> + if (kvaser_usb_get_card_info(dev)) {
>>> + dev_err(&intf->dev, "Cannot get card infos\n");
>>> + goto error;
>>> + }
>>> +
>>> + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
>>> + ((dev->fw_version >> 24) & 0xff),
>>> + ((dev->fw_version >> 16) & 0xff),
>>> + (dev->fw_version & 0xffff));
>>> +
>>> + for (i = 0; i < dev->nchannels; i++)
>>> + kvaser_usb_init_one(intf, id, i);
>>> +
>>> + return 0;
>>> +
>>> +error:
>>> + kfree(dev);
>>> + return err;
>>> +}
>>> +
>>> +static void kvaser_usb_disconnect(struct usb_interface *intf)
>>> +{
>>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
>>> + int i;
>>> +
>>> + usb_set_intfdata(intf, NULL);
>>> +
>>> + if (!dev)
>>> + return;
>>> +
>>> + for (i = 0; i < dev->nchannels; i++) {
>>> + if (!dev->nets[i])
>>> + continue;
>>> +
>>> + unregister_netdev(dev->nets[i]->netdev);
>>> + free_candev(dev->nets[i]->netdev);
>>> + }
>>> +
>>> + kvaser_usb_unlink_all_urbs(dev);
>>> +}
>>> +
>>> +static struct usb_driver kvaser_usb_driver = {
>>> + .name = "kvaser_usb",
>>> + .probe = kvaser_usb_probe,
>>> + .disconnect = kvaser_usb_disconnect,
>>> + .id_table = kvaser_usb_table
>>> +};
>>> +
>>> +module_usb_driver(kvaser_usb_driver);
>>> +
>>> +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
>>> +MODULE_DESCRIPTION("Can driver for Kvaser CAN/USB devices");
>>> +MODULE_LICENSE("GPL v2");
>>> diff --git a/drivers/net/can/usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb.h
>>> new file mode 100644
>>> index 0000000..8e0b6ab
>>> --- /dev/null
>>> +++ b/drivers/net/can/usb/kvaser_usb.h
>>> @@ -0,0 +1,237 @@
>>> +#ifndef _KVASER_USB_H_
>>> +#define _KVASER_USB_H_
>>> +
>>> +#define MAX_TX_URBS 16
>> Please no tab between define and macro name
>
> Ok I didn't know it was not allowed... checkpatch didn't complain.
It's allowed, but not used without tab it's more common, at least among
CAN drivers.
>
>>> +#define MAX_RX_URBS 4
>>> +#define START_TIMEOUT 1000
>>> +#define STOP_TIMEOUT 1000
>>> +#define USB_SEND_TIMEOUT 1000
>>> +#define USB_RECEIVE_TIMEOUT 1000
>>> +#define RX_BUFFER_SIZE 3072
>>> +#define CAN_USB_CLOCK 8000000
>>> +#define MAX_NET_DEVICES 3
>>> +
>>> +/* Kvaser USB devices */
>>> +#define KVASER_VENDOR_ID 0x0bfd
>>> +#define USB_LEAF_DEVEL_PRODUCT_ID 10
>>> +#define USB_LEAF_LITE_PRODUCT_ID 11
>>> +#define USB_LEAF_PRO_PRODUCT_ID 12
>>> +#define USB_LEAF_SPRO_PRODUCT_ID 14
>>> +#define USB_LEAF_PRO_LS_PRODUCT_ID 15
>>> +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
>>> +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
>>> +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
>>> +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
>>> +#define USB_MEMO2_DEVEL_PRODUCT_ID 22
>>> +#define USB_MEMO2_HSHS_PRODUCT_ID 23
>>> +#define USB_UPRO_HSHS_PRODUCT_ID 24
>>> +#define USB_LEAF_LITE_GI_PRODUCT_ID 25
>>> +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
>>> +#define USB_MEMO2_HSLS_PRODUCT_ID 27
>>> +#define USB_LEAF_LITE_CH_PRODUCT_ID 28
>>> +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
>>> +#define USB_OEM_MERCURY_PRODUCT_ID 34
>>> +#define USB_OEM_LEAF_PRODUCT_ID 35
>>> +#define USB_CAN_R_PRODUCT_ID 39
>>> +
>>> +/* USB devices features */
>>> +#define KVASER_HAS_SILENT_MODE (1 << 0)
>> pleae use BIT(0)
>>> +
>>> +/* Message header size */
>>> +#define MSG_HEADER_LEN 2
>>> +
>>> +/* Can message flags */
>>> +#define MSG_FLAG_ERROR_FRAME (1 << 0)
>>> +#define MSG_FLAG_OVERRUN (1 << 1)
>>> +#define MSG_FLAG_NERR (1 << 2)
>>> +#define MSG_FLAG_WAKEUP (1 << 3)
>>> +#define MSG_FLAG_REMOTE_FRAME (1 << 4)
>>> +#define MSG_FLAG_RESERVED (1 << 5)
>>> +#define MSG_FLAG_TX_ACK (1 << 6)
>>> +#define MSG_FLAG_TX_REQUEST (1 << 7)
>>> +
>>> +/* Can states */
>>> +#define M16C_STATE_BUS_RESET (1 << 0)
>>> +#define M16C_STATE_BUS_ERROR (1 << 4)
>>> +#define M16C_STATE_BUS_PASSIVE (1 << 5)
>>> +#define M16C_STATE_BUS_OFF (1 << 6)
>>> +
>>> +/* Can msg ids */
>>> +#define CMD_RX_STD_MESSAGE 12
>>> +#define CMD_TX_STD_MESSAGE 13
>>> +#define CMD_RX_EXT_MESSAGE 14
>>> +#define CMD_TX_EXT_MESSAGE 15
>>> +#define CMD_SET_BUS_PARAMS 16
>>> +#define CMD_GET_BUS_PARAMS 17
>>> +#define CMD_GET_BUS_PARAMS_REPLY 18
>>> +#define CMD_GET_CHIP_STATE 19
>>> +#define CMD_CHIP_STATE_EVENT 20
>>> +#define CMD_SET_CTRL_MODE 21
>>> +#define CMD_GET_CTRL_MODE 22
>>> +#define CMD_GET_CTRL_MODE_REPLY 23
>>> +#define CMD_RESET_CHIP 24
>>> +#define CMD_RESET_CHIP_REPLY 25
>>> +#define CMD_START_CHIP 26
>>> +#define CMD_START_CHIP_REPLY 27
>>> +#define CMD_STOP_CHIP 28
>>> +#define CMD_STOP_CHIP_REPLY 29
>>> +#define CMD_GET_CARD_INFO2 32
>>> +#define CMD_GET_CARD_INFO 34
>>> +#define CMD_GET_CARD_INFO_REPLY 35
>>> +#define CMD_GET_SOFTWARE_INFO 38
>>> +#define CMD_GET_SOFTWARE_INFO_REPLY 39
>>> +#define CMD_ERROR_EVENT 45
>>> +#define CMD_FLUSH_QUEUE 48
>>> +#define CMD_TX_ACKNOWLEDGE 50
>>> +#define CMD_CAN_ERROR_EVENT 51
>>> +#define CMD_USB_THROTTLE 77
>>> +
>>> +/* error factors */
>>> +#define M16C_EF_ACKE (1 << 0)
>>> +#define M16C_EF_CRCE (1 << 1)
>>> +#define M16C_EF_FORME (1 << 2)
>>> +#define M16C_EF_STFE (1 << 3)
>>> +#define M16C_EF_BITE0 (1 << 4)
>>> +#define M16C_EF_BITE1 (1 << 5)
>>> +#define M16C_EF_RCVE (1 << 6)
>>> +#define M16C_EF_TRE (1 << 7)
>>> +
>>> +/* bittiming parameters */
>>> +#define KVASER_USB_TSEG1_MIN 1
>>> +#define KVASER_USB_TSEG1_MAX 16
>>> +#define KVASER_USB_TSEG2_MIN 1
>>> +#define KVASER_USB_TSEG2_MAX 8
>>> +#define KVASER_USB_SJW_MAX 4
>>> +#define KVASER_USB_BRP_MIN 1
>>> +#define KVASER_USB_BRP_MAX 64
>>> +#define KVASER_USB_BRP_INC 1
>>> +
>>> +/* ctrl modes */
>>> +#define KVASER_CTRL_MODE_NORMAL 1
>>> +#define KVASER_CTRL_MODE_SILENT 2
>>> +#define KVASER_CTRL_MODE_SELFRECEPTION 3
>>> +#define KVASER_CTRL_MODE_OFF 4
>>> +
>>> +struct kvaser_msg_simple {
>>> + u8 tid;
>>> + u8 channel;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_cardinfo {
>>> + u8 tid;
>>> + u8 nchannels;
>>> + __le32 serial_number;
>>> + __le32 padding;
>>> + __le32 clock_resolution;
>>> + __le32 mfgdate;
>>> + u8 ean[8];
>>> + u8 hw_revision;
>>> + u8 usb_hs_mode;
>>> + __le16 padding2;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_cardinfo2 {
>>> + u8 tid;
>>> + u8 channel;
>>> + u8 pcb_id[24];
>>> + __le32 oem_unlock_code;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_softinfo {
>>> + u8 tid;
>>> + u8 channel;
>>> + __le32 sw_options;
>>> + __le32 fw_version;
>>> + __le16 max_outstanding_tx;
>>> + __le16 padding[9];
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_busparams {
>>> + u8 tid;
>>> + u8 channel;
>>> + __le32 bitrate;
>>> + u8 tseg1;
>>> + u8 tseg2;
>>> + u8 sjw;
>>> + u8 no_samp;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_tx_can {
>>> + u8 channel;
>>> + u8 tid;
>>> + u8 msg[14];
>>> + u8 padding;
>>> + u8 flags;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_rx_can {
>>> + u8 channel;
>>> + u8 flag;
>>> + __le16 time[3];
>>> + u8 msg[14];
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_chip_state_event {
>>> + u8 tid;
>>> + u8 channel;
>>> + __le16 time[3];
>>> + u8 tx_errors_count;
>>> + u8 rx_errors_count;
>>> + u8 status;
>>> + u8 padding[3];
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_tx_acknowledge {
>>> + u8 channel;
>>> + u8 tid;
>>> + __le16 time[3];
>>> + u8 flags;
>>> + u8 time_offset;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_error_event {
>>> + u8 tid;
>>> + u8 flags;
>>> + __le16 time[3];
>>> + u8 channel;
>>> + u8 padding;
>>> + u8 tx_errors_count;
>>> + u8 rx_errors_count;
>>> + u8 status;
>>> + u8 error_factor;
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_ctrl_mode {
>>> + u8 tid;
>>> + u8 channel;
>>> + u8 ctrl_mode;
>>> + u8 padding[3];
>>> +} __packed;
>>> +
>>> +struct kvaser_msg_flush_queue {
>>> + u8 tid;
>>> + u8 channel;
>>> + u8 flags;
>>> + u8 padding[3];
>>> +} __packed;
>>> +
>>> +struct kvaser_msg {
>>> + u8 len;
>>> + u8 id;
>>> + union {
>>> + struct kvaser_msg_simple simple;
>>> + struct kvaser_msg_cardinfo cardinfo;
>>> + struct kvaser_msg_cardinfo2 cardinfo2;
>>> + struct kvaser_msg_softinfo softinfo;
>>> + struct kvaser_msg_busparams busparams;
>>> + struct kvaser_msg_tx_can tx_can;
>>> + struct kvaser_msg_rx_can rx_can;
>>> + struct kvaser_msg_chip_state_event chip_state_event;
>>> + struct kvaser_msg_tx_acknowledge tx_acknowledge;
>>> + struct kvaser_msg_error_event error_event;
>>> + struct kvaser_msg_ctrl_mode ctrl_mode;
>>> + struct kvaser_msg_ctrl_mode flush_queue;
>>> + } u;
>>> +} __packed;
>>> +
>>> +#endif
>>>
>>
>>
>> --
>> Pengutronix e.K. | Marc Kleine-Budde |
>> Industrial Linux Solutions | Phone: +49-231-2826-924 |
>> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
>> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
>>
>
> Thanks for the review.
np,
regards, Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] net: Allow to create links with given ifindex
From: Pavel Emelyanov @ 2012-07-31 9:06 UTC (permalink / raw)
To: Eric W. Biederman, Eric Dumazet; +Cc: Linux Netdev List, David Miller
In-Reply-To: <87k3xlfmym.fsf@xmission.com>
> I'm not seeing anything obvious in the network stack with a quick skim,
> but before we start relying on the property that interface indicies are
> not globally unique I expect an good hard look at the networking stack
> to see if any of those cases where there were problems still exist.
Just an idea -- is it worth moving the possibility to have ifindidces intersect
under CONFIG_<SOMETHING> (EXPERT/CHECKPOINT_RESTORE) to let wider audience check
the code in real-life?
> Eric
>
> .
>
Thanks,
Pavel
^ permalink raw reply
* Re: [PATCH 1/2] net: Allow to create links with given ifindex
From: Pavel Emelyanov @ 2012-07-31 9:03 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Linux Netdev List, David Miller
In-Reply-To: <87fw89h5zk.fsf@xmission.com>
On 07/30/2012 02:56 PM, Eric W. Biederman wrote:
> ebiederm@xmission.com (Eric W. Biederman) writes:
>
>> Pavel Emelyanov <xemul@parallels.com> writes:
>>
>>> Currently the RTM_NEWLINK results in -EOPNOTSUPP if the ifinfomsg->ifi_index
>>> is not zero. I propose to allow requesting ifindices on link creation. This
>>> is required by the checkpoint-restore to correctly restore a net namespace
>>> (i.e. -- a container). The question what to do with pre-created devices such
>>> as lo or sit fbdev is open, but for manually created devices this can be
>>> solved by this patch.
>>
>> Have you walked through and found the locations where we still rely on
>> ifindex being globally unique?
>>
>> Last time I was working in this area there were serveral places where
>> things were indexed by just the interface index.
>
> If it is really safe to make ifindex per network namespace at this
> point you can make dev_new_ifindex have a per network namespace base
> counter, and that will fix your problems with the loopback device.
Not it's not so unfortunately :(
First, let's imagine that on host A the loopback device got registered as
first device, but on host B for some reason some other device got registered
first. In that case after migration from A to B the lo on B will have index
equals 2. And there's no any strict requirement that lo's per net operations
are registered first. Please, correct me if I'm wrong.
Next. In fact, lo is not the only problem. Look at the e.g. sit versus ipgre
fallback devices. Both gets created on netns creation and obtain whatever
ifindices are generated for them. Even if we make ifidex per netns chances
that sit gets registered _strictly_ before ipgre equal zero, since they are
both modules.
> Unless you have done the work to root out the last of dependencies on
> ifindex being globally unique I think you will run into some operational
> problems.
I totally agree with that. Before doing this patch I revisited the ancient
attempt to make ifindices per netns and checked the issues Dave and you
discussed then -- I have looked through how the ifindices are used in the
networking code and found no places where the system-wide uniqueness is still
required. That's why I proposed this patch for inclusion. If you know the
places I've missed, please let me know, I will work on it.
> Eric
>
> .
>
Thanks,
Pavel
^ permalink raw reply
* Re: [BUG] igb: panic at boot time with latest Linus tree
From: Jeff Kirsher @ 2012-07-31 8:51 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1343724174.21269.168.camel@edumazet-glaptop>
[-- Attachment #1: Type: text/plain, Size: 889 bytes --]
On Tue, 2012-07-31 at 10:42 +0200, Eric Dumazet wrote:
> On Mon, 2012-07-30 at 23:26 -0700, Jeff Kirsher wrote:
> > On Tue, 2012-07-31 at 08:14 +0200, Eric Dumazet wrote:
> > > For information, I get this each time I boot on latest Linus tree :
> > >
> > > RTNL is left locked, so machine unusable.
> > >
> > > No problem with David net tree, so thats a bit strange...
> > >
> > > Not sure I'll have time to investigate today
> > > (And tomorrow I am off for the day)
> > >
> > >
> > >
> >
> > I have an igb patch current in test to fix a panic in igb. Here is the
> > patch:
> >
>
>
>
> Ah sorry for the false alarm, it appears I had igb module in a out of date initrd file (coming from my net tree)
No problem, thanks for the feedback. Whether or not it was false alarm,
the feedback is always a good thing which helps us improve.
Cheers,
Jeff
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [BUG] igb: panic at boot time with latest Linus tree
From: Eric Dumazet @ 2012-07-31 8:42 UTC (permalink / raw)
To: jeffrey.t.kirsher; +Cc: David Miller, netdev
In-Reply-To: <1343715971.2230.4.camel@jtkirshe-mobl>
On Mon, 2012-07-30 at 23:26 -0700, Jeff Kirsher wrote:
> On Tue, 2012-07-31 at 08:14 +0200, Eric Dumazet wrote:
> > For information, I get this each time I boot on latest Linus tree :
> >
> > RTNL is left locked, so machine unusable.
> >
> > No problem with David net tree, so thats a bit strange...
> >
> > Not sure I'll have time to investigate today
> > (And tomorrow I am off for the day)
> >
> >
> >
>
> I have an igb patch current in test to fix a panic in igb. Here is the
> patch:
>
Ah sorry for the false alarm, it appears I had igb module in a out of date initrd file (coming from my net tree)
^ permalink raw reply
* [XFRM][PATCH v5] Fix unexpected SA hard expiration after setting new date
From: Fan Du @ 2012-07-31 7:43 UTC (permalink / raw)
To: davem, herbert; +Cc: netdev
Hi, Dave
Hope v5 is better than previous ones :)
Any comments are really welcome!
Thanks
Changelog:
v1->v2
1) use xflags instead of creating new flags(suggested by Steffen Klassert)
v2->v3
1) fix email problem, and remove cc to myself(requested by David Miller)
v3->v4
1) fix typo when clearing XFRM_SOFT_EXPIRE(thanks for David Miller)
2) fix email problem, and remove cc to myself AGAIN!!!
v4->v5
1) remove unnecessary empty line (David Miller)
*Background*:
Once IPsec SAs are created between two peers, kernel setup a timer to monitor
two events: soft/hard expiration. However the timer handler use xtime to
caculate whether it's soft or hard expiration event.
normal code flow(hard expire time:100s, soft expire time:82s)
a) When new SAs created, xfrm_timer_handler is called one second
after its creation. At this point, calculate soft expire
interval(81s), setup the timer;
b) soft expire occur, rearm the timer with hard expire interval(18s)
then notify racoon2 about soft expire event. racoon2 will create
new SAs.
c) hard expire happen, notify racoon2 about it. racoon2 will delete
the old SAs.
*Scenario*:
Setting a new date before b),and after a) could result c) happens first,
As a result, old SAs is deleted before new ones are created. Normally
new SAs will be created by the next time networking traffic, but there
is a small time being when networking connection is down, this could
result in upper layer connections failed in tel comm area, thus it's
better to keep it strict in sequence.
*Workaround*:
set new time could happen:
1) before a), then SAs is updated with new time.
2) before b),and after a)
2a) When new SAs created, xfrm_timer_handler is called one second
after its creation. At this point, calculate soft expire
interval(81s), setup the timer;(set flag to mark next time should
be soft time expire)
<<---- new date comes
2b) soft expire occur, the calculation results in a hard time expire
event, but flag is set, so catch ya. Sync the addtime, and rearm
the timer with hard expire interval(18s), then notify racoon2
about soft expire event;
2c) hard expire happen, notify racoon2 about it;
so everything is in order.
3) after b), hard expire always happened anyway.
^ permalink raw reply
* [PATCH] [XFRM] Fix unexpected SA hard expiration after changing date
From: Fan Du @ 2012-07-31 7:43 UTC (permalink / raw)
To: davem, herbert; +Cc: netdev
In-Reply-To: <1343720634-1176-1-git-send-email-fdu@windriver.com>
After SA is setup, one timer is armed to detect soft/hard expiration,
however the timer handler uses xtime to do the math. This makes hard
expiration occurs first before soft expiration after setting new date
with big interval. As a result new child SA is deleted before rekeying
the new one.
Signed-off-by: Fan Du <fdu@windriver.com>
---
include/net/xfrm.h | 4 ++++
net/xfrm/xfrm_state.c | 22 ++++++++++++++++++----
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d9509eb..62b619e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -213,6 +213,9 @@ struct xfrm_state {
struct xfrm_lifetime_cur curlft;
struct tasklet_hrtimer mtimer;
+ /* used to fix curlft->add_time when changing date */
+ long saved_tmo;
+
/* Last used time */
unsigned long lastused;
@@ -238,6 +241,7 @@ static inline struct net *xs_net(struct xfrm_state *x)
/* xflags - make enum if more show up */
#define XFRM_TIME_DEFER 1
+#define XFRM_SOFT_EXPIRE 2
enum {
XFRM_STATE_VOID,
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5b228f9..fb64dc6 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -415,8 +415,17 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
if (x->lft.hard_add_expires_seconds) {
long tmo = x->lft.hard_add_expires_seconds +
x->curlft.add_time - now;
- if (tmo <= 0)
- goto expired;
+ if (tmo <= 0) {
+ if (x->xflags & XFRM_SOFT_EXPIRE) {
+ /* enter hard expire without soft expire first?!
+ * setting a new date could trigger this.
+ * workarbound: fix x->curflt.add_time by below:
+ */
+ x->curlft.add_time = now - x->saved_tmo - 1;
+ tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
+ } else
+ goto expired;
+ }
if (tmo < next)
next = tmo;
}
@@ -433,10 +443,14 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
if (x->lft.soft_add_expires_seconds) {
long tmo = x->lft.soft_add_expires_seconds +
x->curlft.add_time - now;
- if (tmo <= 0)
+ if (tmo <= 0) {
warn = 1;
- else if (tmo < next)
+ x->xflags &= ~XFRM_SOFT_EXPIRE;
+ } else if (tmo < next) {
next = tmo;
+ x->xflags |= XFRM_SOFT_EXPIRE;
+ x->saved_tmo = tmo;
+ }
}
if (x->lft.soft_use_expires_seconds) {
long tmo = x->lft.soft_use_expires_seconds +
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] sctp: Make "Invalid Stream Identifier" ERROR follows SACK when bundling
From: xufeng zhang @ 2012-07-31 6:51 UTC (permalink / raw)
To: Vlad Yasevich
Cc: Xufeng Zhang, Neil Horman, sri, davem, linux-sctp, netdev,
linux-kernel
In-Reply-To: <CA+=dFzhXY9aJ6_Yu-4a3g+6RyN5_mxXY=U3HnzKdi8TH-rqWcA@mail.gmail.com>
Sorry, please ignore the above patch, there was an paste error.
Please check the following patch.
============================================
I'm wondering if the below solution is fine to you which is based on
your changes.
BTW, I have verified this patch and it works ok for all the situation,
but only one problem persists:
there is a potential that commands will exceeds SCTP_MAX_NUM_COMMANDS
which happens during sending lots of small error DATA chunks.
Thanks,
Xufeng Zhang
---
include/net/sctp/command.h | 1 +
include/net/sctp/structs.h | 3 +++
net/sctp/outqueue.c | 7 +++++++
net/sctp/sm_sideeffect.c | 16 ++++++++++++++++
net/sctp/sm_statefuns.c | 17 ++++++++++++++---
5 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 712b3be..62c34f5 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -110,6 +110,7 @@ typedef enum {
SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/
SCTP_CMD_SET_ASOC, /* Restore association context */
+ SCTP_CMD_GEN_BAD_STREAM, /* Invalid Stream errors happened command */
SCTP_CMD_LAST
} sctp_verb_t;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index fc5e600..3d218e0 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1183,6 +1183,9 @@ struct sctp_outq {
*/
struct list_head abandoned;
+ /* Put Invalid Stream error chunks on this list */
+ struct list_head bad_stream_err;
+
/* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index e7aa177..1e87b0b 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -211,6 +211,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned);
+ INIT_LIST_HEAD(&q->bad_stream_err);
q->fast_rtx = 0;
q->outstanding_bytes = 0;
@@ -283,6 +284,12 @@ void sctp_outq_teardown(struct sctp_outq *q)
list_del_init(&chunk->list);
sctp_chunk_free(chunk);
}
+
+ /* Throw away any pending Invalid Stream error chunks */
+ list_for_each_entry_safe(chunk, tmp,&q->bad_stream_err, list) {
+ list_del_init(&chunk->list);
+ sctp_chunk_free(chunk);
+ }
}
/* Free the outqueue structure and any related pending chunks. */
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index fe99628..4698593 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1060,6 +1060,18 @@ static void sctp_cmd_send_asconf(struct sctp_association *asoc)
}
}
+static void sctp_cmd_make_inv_stream_err(sctp_cmd_seq_t *commands,
+ struct sctp_association *asoc)
+{
+ struct sctp_chunk *err, *tmp;
+ struct sctp_outq *q =&asoc->outqueue;
+
+ list_for_each_entry_safe(err, tmp,&q->bad_stream_err, list) {
+ list_del_init(&err->list);
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+ SCTP_CHUNK(err));
+ }
+}
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
@@ -1724,6 +1736,10 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
asoc = cmd->obj.asoc;
break;
+ case SCTP_CMD_GEN_BAD_STREAM:
+ sctp_cmd_make_inv_stream_err(commands, asoc);
+ break;
+
default:
pr_warn("Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 9fca103..1c1bcd9 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -2967,8 +2967,14 @@ discard_force:
return SCTP_DISPOSITION_DISCARD;
discard_noforce:
- if (chunk->end_of_packet)
+ if (chunk->end_of_packet) {
+ struct sctp_outq *q =&asoc->outqueue;
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, force);
+ /* Queue the INVALID STREAM error after the SACK if one is needed. */
+ if (!list_empty(&q->bad_stream_err))
+ sctp_add_cmd_sf(commands, SCTP_CMD_GEN_BAD_STREAM,
+ SCTP_NULL());
+ }
return SCTP_DISPOSITION_DISCARD;
consume:
@@ -3037,11 +3043,16 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
* with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer
*/
if (chunk->end_of_packet) {
+ struct sctp_outq *q =&asoc->outqueue;
/* We must delay the chunk creation since the cumulative
* TSN has not been updated yet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
+ /* Queue the INVALID STREAM error after the SACK if one is needed. */
+ if (!list_empty(&q->bad_stream_err))
+ sctp_add_cmd_sf(commands, SCTP_CMD_GEN_BAD_STREAM,
+ SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
}
@@ -6136,6 +6147,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
*/
sid = ntohs(data_hdr->stream);
if (sid>= asoc->c.sinit_max_instreams) {
+ struct sctp_outq *q =&asoc->outqueue;
/* Mark tsn as received even though we drop it */
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
@@ -6144,8 +6156,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
sizeof(data_hdr->stream),
sizeof(u16));
if (err)
- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
- SCTP_CHUNK(err));
+ list_add_tail(&err->list,&q->bad_stream_err);
return SCTP_IERROR_BAD_STREAM;
}
--
1.7.0.2
^ permalink raw reply related
* Re: [BUG] igb: panic at boot time with latest Linus tree
From: Jeff Kirsher @ 2012-07-31 6:26 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1343715255.21269.47.camel@edumazet-glaptop>
[-- Attachment #1: Type: text/plain, Size: 7783 bytes --]
On Tue, 2012-07-31 at 08:14 +0200, Eric Dumazet wrote:
> For information, I get this each time I boot on latest Linus tree :
>
> RTNL is left locked, so machine unusable.
>
> No problem with David net tree, so thats a bit strange...
>
> Not sure I'll have time to investigate today
> (And tomorrow I am off for the day)
>
> [ 11.153682] BUG: unable to handle kernel NULL pointer dereference at (null)
> [ 11.153806] IP: [< (null)>] (null)
> [ 11.153872] PGD 310544067 PUD 311b2d067 PMD 0
> [ 11.153945] Oops: 0010 [#1] SMP
> [ 11.154012] Modules linked in: nfsd exportfs nfs lockd auth_rpcgss sunrpc asix usbnet rt61pci crc_itu_t rt2x00pci rt2x00lib eeprom_93cx6 tg3 ixgbe mdio igb
> [ 11.154227] CPU 10
> [ 11.154239] Pid: 2476, comm: NetworkManager Not tainted 3.5.0+ #123 Hewlett-Packard HP Z600 Workstation/0B54h
> [ 11.154437] RIP: 0010:[<0000000000000000>] [< (null)>] (null)
> [ 11.154574] RSP: 0018:ffff88030f667630 EFLAGS: 00010282
> [ 11.154645] RAX: 0000000017cf7980 RBX: ffff88031080f100 RCX: 0000000000000200
> [ 11.154720] RDX: 0000000000000040 RSI: ffffea0017cf7980 RDI: ffff880611bc1098
> [ 11.154794] RBP: ffff88030f667678 R08: 0000000000000002 R09: 0000000000000000
> [ 11.154868] R10: ffffea0017cf7980 R11: 0000000000000000 R12: ffffc90007d58000
> [ 11.154942] R13: ffff880611bc1098 R14: ffff8803106ff000 R15: ffff8805f3de6040
> [ 11.155016] FS: 00007fa2e4b94800(0000) GS:ffff88061fc80000(0000) knlGS:0000000000000000
> [ 11.155148] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 11.155220] CR2: 0000000000000000 CR3: 000000031066a000 CR4: 00000000000007e0
> [ 11.155283] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [ 11.155347] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> [ 11.155411] Process NetworkManager (pid: 2476, threadinfo ffff88030f666000, task ffff880310dd2d00)
> [ 11.155523] Stack:
> [ 11.155579] ffffffffa00071fe 0000000000000000 00ffff00a000400a ffff88030f667678
> [ 11.155712] ffff88030f610700 0000000000000001 ffff88030f610708 ffff88030f610740
> [ 11.155840] 0000000000000001 ffff88030f6676b8 ffffffffa000834b ffff88030f610700
> [ 11.155969] Call Trace:
> [ 11.156036] [<ffffffffa00071fe>] ? igb_alloc_rx_buffers+0x13e/0x2d0 [igb]
> [ 11.156104] [<ffffffffa000834b>] igb_configure+0x34b/0x4d0 [igb]
> [ 11.156170] [<ffffffffa0008572>] __igb_open+0xa2/0x510 [igb]
> [ 11.156237] [<ffffffff812c0731>] ? find_next_bit+0x21/0xd0
> [ 11.156303] [<ffffffffa0008b50>] igb_open+0x10/0x20 [igb]
> [ 11.156369] [<ffffffff8155288f>] __dev_open+0x8f/0xe0
> [ 11.156432] [<ffffffff81552b31>] __dev_change_flags+0xa1/0x180
> [ 11.156495] [<ffffffff81552cc8>] dev_change_flags+0x28/0x70
> [ 11.156559] [<ffffffff8155f664>] do_setlink+0x284/0x9e0
> [ 11.156624] [<ffffffff81560c8a>] ? rtnl_fill_ifinfo+0x92a/0xb30
> [ 11.156690] [<ffffffff812cc220>] ? nla_parse+0x30/0xe0
> [ 11.156755] [<ffffffff81561b35>] rtnl_newlink+0x345/0x580
> [ 11.156820] [<ffffffff812655b9>] ? selinux_capable+0x39/0x50
> [ 11.156885] [<ffffffff81262538>] ? security_capable+0x18/0x20
> [ 11.156948] [<ffffffff81561384>] rtnetlink_rcv_msg+0x124/0x310
> [ 11.157012] [<ffffffff8113794b>] ? kfree+0x3b/0x160
> [ 11.157074] [<ffffffff81561260>] ? __rtnl_unlock+0x20/0x20
> [ 11.157137] [<ffffffff8157a569>] netlink_rcv_skb+0xa9/0xd0
> [ 11.157200] [<ffffffff8155ed55>] rtnetlink_rcv+0x25/0x40
> [ 11.157262] [<ffffffff81579f4d>] netlink_unicast+0x1ad/0x230
> [ 11.157326] [<ffffffff8157a286>] netlink_sendmsg+0x2b6/0x310
> [ 11.157396] [<ffffffff815381ac>] sock_sendmsg+0xdc/0xf0
> [ 11.157459] [<ffffffff8153aab8>] ? move_addr_to_kernel+0x68/0xb0
> [ 11.157526] [<ffffffff81539b12>] __sys_sendmsg+0x392/0x3a0
> [ 11.157590] [<ffffffff81118bbe>] ? handle_mm_fault+0x13e/0x210
> [ 11.157656] [<ffffffff81155008>] ? __d_free+0x48/0x70
> [ 11.157720] [<ffffffff8115e616>] ? mntput+0x26/0x40
> [ 11.157783] [<ffffffff81140371>] ? __fput+0x191/0x250
> [ 11.157846] [<ffffffff8153b809>] sys_sendmsg+0x49/0x90
> [ 11.157911] [<ffffffff816ca652>] system_call_fastpath+0x16/0x1b
> [ 11.157973] Code: Bad RIP value.
> [ 11.158041] RIP [< (null)>] (null)
> [ 11.158106] RSP <ffff88030f667630>
> [ 11.158163] CR2: 0000000000000000
> [ 11.158227] ---[ end trace bbfaed088efd61cb ]---
> [ 11.158300] NetworkManager (2476) used greatest stack depth: 2936 bytes left
>
>
I have an igb patch current in test to fix a panic in igb. Here is the
patch:
From: Emil Tantilov <emil.s.tantilov@intel.com>
Subject: igb: fix panic while dumping packets on Tx hang with IOMMU
This patch resolves a "BUG: unable to handle kernel paging request
at ..." oops while dumping packet data. The issue occurs with IOMMU
enabled due to the address provided by phys_to_virt().
This patch avoids phys_to_virt() by making using skb->data and the
address of the pages allocated for Rx.
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 19 +++++++++----------
1 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c
b/drivers/net/ethernet/intel/igb/igb_main.c
index 447e131..8d7e5da 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -462,10 +462,10 @@ static void igb_dump(struct igb_adapter *adapter)
(u64)buffer_info->time_stamp,
buffer_info->skb, next_desc);
- if (netif_msg_pktdata(adapter) &&
buffer_info->dma != 0)
+ if (netif_msg_pktdata(adapter) &&
buffer_info->skb)
print_hex_dump(KERN_INFO, "",
DUMP_PREFIX_ADDRESS,
- 16, 1,
phys_to_virt(buffer_info->dma),
+ 16, 1, buffer_info->skb->data,
buffer_info->length, true);
}
}
@@ -547,18 +547,17 @@ rx_ring_summary:
(u64)buffer_info->dma,
buffer_info->skb, next_desc);
- if (netif_msg_pktdata(adapter)) {
+ if (netif_msg_pktdata(adapter) &&
+ buffer_info->dma &&
buffer_info->skb) {
print_hex_dump(KERN_INFO, "",
- DUMP_PREFIX_ADDRESS,
- 16, 1,
-
phys_to_virt(buffer_info->dma),
- IGB_RX_HDR_LEN, true);
+ DUMP_PREFIX_ADDRESS,
+ 16, 1,
buffer_info->skb->data,
+ IGB_RX_HDR_LEN, true);
print_hex_dump(KERN_INFO, "",
DUMP_PREFIX_ADDRESS,
16, 1,
- phys_to_virt(
- buffer_info->page_dma +
- buffer_info->page_offset),
+
page_address(buffer_info->page) +
+
buffer_info->page_offset,
PAGE_SIZE/2, true);
}
}
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply related
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