* Re: [PATCH net-next-2.6 v3 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Oliver Hartkopp @ 2011-01-09 11:01 UTC (permalink / raw)
To: Wolfgang Grandegger, Tomoya MORINAGA, Bhupesh Sharma
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA, Marc Kleine-Budde, David Miller
In-Reply-To: <4D262158.4030301-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
On 06.01.2011 21:08, Wolfgang Grandegger wrote:
> Hi Marc,
>
> On 01/06/2011 08:44 PM, Marc Kleine-Budde wrote:
>> If this driver will be merged, we'll have two drivers for the same can
>> core in the tree. The other one is the pch_can. What do you think should
>> be the mid term perspective for ccan based hardware?
>
> Yes, I know. Unfortunately, we did realize rather late the the PCH
> controller is a C_CAN clone and the OKI/Intel ppls did not tell us
> either. Therefore I asked Bhupesh to provide a SJA1000-a-like interface
> for the C_CAN, which would allow us to provide an alternative PCI driver
> "pch_pci.c" for the PCH. If that driver works well on the PCH hardware
> as well, we should merge the best of both, if necessary, and then
> finally remove the pch_can driver. Would that be a reasonable proposal.
At least for me this looks great. The idea to have a similar approach as we
successfully implemented for the sja1000 will solve future hardware
implementations based on the ccan controller core.
BTW. for the next submission of Bhupeshs patchset, i would propose to name the
driver 'ccan' instead of 'c_can', so that we have a
linux/drivers/net/can/ccan/...
path.
Checking directory names in linux/drivers with
find . -type d | grep '_'
driver names with underscores are pretty unusual and mostly selected without
fortune:
./staging/olpc_dcon
./staging/wlags49_h2
./staging/wlags49_h2/man
./staging/serqt_usb2
./staging/intel_sst
./staging/quatech_usb2
./staging/asus_oled
./staging/wlags49_h25
./staging/ath6kl/hif/sdio/linux_sdio <- Ugh!
./staging/ath6kl/hif/sdio/linux_sdio/src
./staging/ath6kl/hif/sdio/linux_sdio/include
./net/pch_gbe
./net/fs_enet
./net/wireless/libertas_tf
./net/ibm_newemacds
For that reason i would prefer 'ccan' to name this driver core.
Best regards,
Oliver
^ permalink raw reply
* Re: [PATCH]netdev: add driver for enc424j600 ethernet chip on SPI bus
From: Balaji Venkatachalam @ 2011-01-09 9:00 UTC (permalink / raw)
To: Michał Mirosław
Cc: netdev, mohan, blue.cube, lanconelli.claudio, Sriram Subramanian
In-Reply-To: <AANLkTinosxXKgfkqGKqCLGi8tWeP4xnT1P3kMRu51CvS@mail.gmail.com>
Thanks for the comments. I am working on them. Will post the updated patch soon.
^ permalink raw reply
* [PATCH 6/6] net: fix kernel-doc warning in core/filter.c
From: Randy Dunlap @ 2011-01-09 3:41 UTC (permalink / raw)
To: netdev; +Cc: Linus, davem
From: Randy Dunlap <randy.dunlap@oracle.com>
Fix new kernel-doc notation warning in net/core/filter.c:
Warning(net/core/filter.c:172): No description found for parameter 'fentry'
Warning(net/core/filter.c:172): Excess function parameter 'filter' description in 'sk_run_filter'
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
---
net/core/filter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- lnx0107.orig/net/core/filter.c
+++ lnx0107/net/core/filter.c
@@ -158,7 +158,7 @@ EXPORT_SYMBOL(sk_filter);
/**
* sk_run_filter - run a filter on a socket
* @skb: buffer to run the filter on
- * @filter: filter to apply
+ * @fentry: filter to apply
*
* Decode and apply filter instructions to the skb->data.
* Return length to keep, 0 for none. @skb is the data we are
^ permalink raw reply
* [PATCH 4/6] net/sock.h: make some fields private to fix kernel-doc warning(s)
From: Randy Dunlap @ 2011-01-09 3:39 UTC (permalink / raw)
To: lkml, Linus; +Cc: netdev, davem
From: Randy Dunlap <randy.dunlap@oracle.com>
Fix new kernel-doc notation warning in sock.h by annotating skc_dontcopy_*
as private fields.
Warning(include/net/sock.h:163): No description found for parameter 'skc_dontcopy_end[0]'
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
---
include/net/sock.h | 4 ++++
1 file changed, 4 insertions(+)
--- lnx0107.orig/include/net/sock.h
+++ lnx0107/include/net/sock.h
@@ -152,14 +152,18 @@ struct sock_common {
* fields between dontcopy_begin/dontcopy_end
* are not copied in sock_copy()
*/
+ /* private: */
int skc_dontcopy_begin[0];
+ /* public: */
union {
struct hlist_node skc_node;
struct hlist_nulls_node skc_nulls_node;
};
int skc_tx_queue_mapping;
atomic_t skc_refcnt;
+ /* private: */
int skc_dontcopy_end[0];
+ /* public: */
};
/**
^ permalink raw reply
* Re: [PATCH 3/5] NET: IPV4: ARP: allow to invalidate specific ARP entries
From: Maxim Levitsky @ 2011-01-08 23:57 UTC (permalink / raw)
To: Eric Dumazet
Cc: linux1394-devel, Stefan Richter, netdev, David S. Miller,
Alexey Kuznetsov, James Morris, Patrick McHardy
In-Reply-To: <1294405062.3306.11.camel@edumazet-laptop>
On Fri, 2011-01-07 at 13:57 +0100, Eric Dumazet wrote:
> Le vendredi 07 janvier 2011 à 14:47 +0200, Maxim Levitsky a écrit :
> > On Mon, 2010-11-29 at 04:09 +0200, Maxim Levitsky wrote:
> > > IPv4 over firewire needs to be able to remove ARP entries
> > > from the ARP cache that belong to nodes that are removed, because
> > > IPv4 over firewire uses ARP packets for private information
> > > about nodes.
> > >
> > > This information becomes invalid as soon as node drops
> > > off the bus and when it reconnects, its only possible
> > > to start takling to is after it responded to an ARP packet.
> > > But ARP cache prevents such packets from being sent.
> > >
> > > CC: netdev@vger.kernel.org
> > > CC: "David S. Miller" <davem@davemloft.net>
> > > CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
> > > CC: James Morris <jmorris@namei.org>
> > > CC: Patrick McHardy <kaber@trash.net>
> >
> > Anybody?
> >
> > Best regards,
> > Maxim Levitsky
> >
> > >
> > >
> > > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > > ---
> > > include/net/arp.h | 1 +
> > > net/ipv4/arp.c | 29 ++++++++++++++++++-----------
> > > 2 files changed, 19 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/include/net/arp.h b/include/net/arp.h
> > > index f4cf6ce..91f0568 100644
> > > --- a/include/net/arp.h
> > > +++ b/include/net/arp.h
> > > @@ -25,5 +25,6 @@ extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
> > > const unsigned char *src_hw,
> > > const unsigned char *target_hw);
> > > extern void arp_xmit(struct sk_buff *skb);
> > > +int arp_invalidate(struct net_device *dev, __be32 ip);
> > >
> > > #endif /* _ARP_H */
> > > diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
> > > index d8e540c..35b1272 100644
> > > --- a/net/ipv4/arp.c
> > > +++ b/net/ipv4/arp.c
> > > @@ -1142,6 +1142,23 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
> > > return err;
> > > }
> > >
> > > +int arp_invalidate(struct net_device *dev, __be32 ip)
> > > +{
> > > + int err = -ENXIO;
> > > + struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
> > > +
> > > + if (neigh) {
> > > + if (neigh->nud_state & ~NUD_NOARP)
> > > + err = neigh_update(neigh, NULL, NUD_FAILED,
> > > + NEIGH_UPDATE_F_OVERRIDE|
> > > + NEIGH_UPDATE_F_ADMIN);
> > > + neigh_release(neigh);
> > > + }
> > > +
> > > + return err;
> > > +}
> > > +EXPORT_SYMBOL(arp_invalidate);
> > > +
> > > static int arp_req_delete_public(struct net *net, struct arpreq *r,
> > > struct net_device *dev)
> > > {
> > > @@ -1162,7 +1179,6 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
> > > {
> > > int err;
> > > __be32 ip;
> > > - struct neighbour *neigh;
> > >
> > > if (r->arp_flags & ATF_PUBL)
> > > return arp_req_delete_public(net, r, dev);
> > > @@ -1180,16 +1196,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
> > > if (!dev)
> > > return -EINVAL;
> > > }
> > > - err = -ENXIO;
> > > - neigh = neigh_lookup(&arp_tbl, &ip, dev);
> > > - if (neigh) {
> > > - if (neigh->nud_state & ~NUD_NOARP)
> > > - err = neigh_update(neigh, NULL, NUD_FAILED,
> > > - NEIGH_UPDATE_F_OVERRIDE|
> > > - NEIGH_UPDATE_F_ADMIN);
> > > - neigh_release(neigh);
> > > - }
> > > - return err;
> > > + return arp_invalidate(dev, ip);
> > > }
> > >
> > > /*
> >
>
> Hi Maxim
>
> You were supposed to respin your patch after my commit :
>
> (941666c2e3e0f9f6a1 net: RCU conversion of dev_getbyhwaddr() and
> arp_ioctl())
>
> Thanks
Hi,
After looking at the code (and honestly its hard to work with it as it
has no documentation at all), I think I don't need any changes in my
patch.
Here is the latest version for I use with the above commit applied (it
is in mainline now).
---
commit 7da91d68d78b6a44ba6337be3b29b22ba2909b9e
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date: Sat Nov 27 00:50:45 2010 +0200
NET: IPV4: ARP: allow to invalidate specific ARP entries
IPv4 over firewire needs to be able to remove ARP entries
from the ARP cache that belong to nodes that are removed, because
IPv4 over firewire uses ARP packets for private information
about nodes.
This information becomes invalid as soon as node drops
off the bus and when it reconnects, its only possible
to start takling to is after it responded to an ARP packet.
But ARP cache prevents such packets from being sent.
CC: netdev@vger.kernel.org
CC: "David S. Miller" <davem@davemloft.net>
CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
CC: James Morris <jmorris@namei.org>
CC: Patrick McHardy <kaber@trash.net>
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
diff --git a/include/net/arp.h b/include/net/arp.h
index f4cf6ce..91f0568 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -25,5 +25,6 @@ extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
const unsigned char *src_hw,
const unsigned char *target_hw);
extern void arp_xmit(struct sk_buff *skb);
+int arp_invalidate(struct net_device *dev, __be32 ip);
#endif /* _ARP_H */
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index a2fc7b9..e941c75 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1143,6 +1143,23 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
return err;
}
+int arp_invalidate(struct net_device *dev, __be32 ip)
+{
+ int err = -ENXIO;
+ struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
+
+ if (neigh) {
+ if (neigh->nud_state & ~NUD_NOARP)
+ err = neigh_update(neigh, NULL, NUD_FAILED,
+ NEIGH_UPDATE_F_OVERRIDE|
+ NEIGH_UPDATE_F_ADMIN);
+ neigh_release(neigh);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(arp_invalidate);
+
static int arp_req_delete_public(struct net *net, struct arpreq *r,
struct net_device *dev)
{
@@ -1163,7 +1180,6 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
{
int err;
__be32 ip;
- struct neighbour *neigh;
if (r->arp_flags & ATF_PUBL)
return arp_req_delete_public(net, r, dev);
@@ -1181,16 +1197,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
if (!dev)
return -EINVAL;
}
- err = -ENXIO;
- neigh = neigh_lookup(&arp_tbl, &ip, dev);
- if (neigh) {
- if (neigh->nud_state & ~NUD_NOARP)
- err = neigh_update(neigh, NULL, NUD_FAILED,
- NEIGH_UPDATE_F_OVERRIDE|
- NEIGH_UPDATE_F_ADMIN);
- neigh_release(neigh);
- }
- return err;
+ return arp_invalidate(dev, ip);
}
/*
^ permalink raw reply related
* [PATCH v1] TCPCT socket API update to draft -02
From: William Allen Simpson @ 2011-01-08 22:07 UTC (permalink / raw)
To: Linux Kernel Network Developers
In-Reply-To: <4D28D8EF.5010008@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 581 bytes --]
Use most recently specified symbols of RFC-to-be-6013.
Permit setting either cookie or s_data or both (sequentially).
Allows different s_data limits for SYN and SYN_ACK.
Split the data value from socket option header, saving more than
1K of stack space in the handler by copying long data values
directly from user space into the kref block.
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 35 ++++++++++++++++-----
net/ipv4/tcp.c | 86 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 89 insertions(+), 32 deletions(-)
[-- Attachment #2: TCPCT+API-02v1+2.6.37.patch --]
[-- Type: text/plain, Size: 7093 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index e64f4c6..ddfdd26 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -184,23 +184,42 @@ struct tcp_md5sig {
#define TCP_COOKIE_MAX 16 /* 128-bits */
#define TCP_COOKIE_PAIR_SIZE (2*TCP_COOKIE_MAX)
+/* Implementation-specific data limits */
+#define TCP_SYN_DATA_LIMIT (TCP_MSS_DEFAULT - sizeof(struct tcphdr))
+#define TCP_SYN_ACK_DATA_LIMIT (TCP_MSS_DESIRED)
+
/* Flags for both getsockopt and setsockopt */
-#define TCP_COOKIE_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
-#define TCP_COOKIE_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
+#define TCPCT_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
+#define TCPCT_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
* supercedes everything. */
-
-/* Flags for getsockopt */
-#define TCP_S_DATA_IN (1 << 2) /* Was data received? */
-#define TCP_S_DATA_OUT (1 << 3) /* Was data sent? */
-
-/* TCP_COOKIE_TRANSACTIONS data */
+#define TCPCT_IN_DATA (1 << 2) /* Was data received? */
+#define TCPCT_OUT_DATA (1 << 3) /* Was data sent? */
+/* reserved for future use: bits 4 .. 6 */
+#define TCPCT_EXTEND (1 << 7)
+
+/* Extended Option flags for both getsockopt and setsockopt */
+#define TCPCT_EXTEND_SIZE (0x7) /* mask */
+#define TCPCT_EXTEND_TS32 (0x1) /* default */
+#define TCPCT_EXTEND_TS64 (0x2)
+#define TCPCT_EXTEND_TS128 (0x4)
+
+/* TCP_COOKIE_TRANSACTIONS socket option header */
struct tcp_cookie_transactions {
__u16 tcpct_flags; /* see above */
- __u8 __tcpct_pad1; /* zero */
+ __u8 tcpct_extended;
__u8 tcpct_cookie_desired; /* bytes */
__u16 tcpct_s_data_desired; /* bytes of variable data */
__u16 tcpct_used; /* bytes in value */
- __u8 tcpct_value[TCP_MSS_DEFAULT];
+};
+
+struct tcpct_full {
+ struct tcp_cookie_transactions soh;
+ __u8 tcpct_value[TCP_COOKIE_PAIR_SIZE];
+};
+
+struct tcpct_half {
+ struct tcp_cookie_transactions soh;
+ __u8 tcpct_value[TCP_COOKIE_MAX];
};
#ifdef __KERNEL__
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6c11eec..28dd6a1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2143,16 +2143,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
case TCP_COOKIE_TRANSACTIONS: {
struct tcp_cookie_transactions ctd;
struct tcp_cookie_values *cvp = NULL;
+ int s_data_used = 0;
if (sizeof(ctd) > optlen)
return -EINVAL;
if (copy_from_user(&ctd, optval, sizeof(ctd)))
return -EFAULT;
- if (ctd.tcpct_used > sizeof(ctd.tcpct_value) ||
- ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
- return -EINVAL;
-
if (ctd.tcpct_cookie_desired == 0) {
/* default to global value */
} else if ((0x1 & ctd.tcpct_cookie_desired) ||
@@ -2161,7 +2158,33 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
return -EINVAL;
}
- if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
+ if (ctd.tcpct_used > 0) {
+ if (ctd.tcpct_used + sizeof(ctd) > optlen)
+ return -EINVAL;
+ if (TCPCT_OUT_DATA & ctd.tcpct_flags) {
+ if (ctd.tcpct_used > TCP_SYN_ACK_DATA_LIMIT)
+ return -EINVAL;
+ if (ctd.tcpct_s_data_desired > 0)
+ return -EINVAL;
+ s_data_used = ctd.tcpct_used;
+ } else {
+ if (ctd.tcpct_used > TCP_COOKIE_PAIR_SIZE)
+ return -EINVAL;
+ if (ctd.tcpct_used !=
+ ctd.tcpct_cookie_desired &&
+ ctd.tcpct_used !=
+ ctd.tcpct_cookie_desired * 2)
+ return -EINVAL;
+ if (ctd.tcpct_s_data_desired >
+ TCP_SYN_DATA_LIMIT)
+ return -EINVAL;
+ }
+ } else if (TCPCT_OUT_DATA & ctd.tcpct_flags) {
+ /* unexpected flag without s_data */
+ return -EINVAL;
+ }
+
+ if (TCPCT_OUT_NEVER & ctd.tcpct_flags) {
/* Supercedes all other values */
lock_sock(sk);
if (tp->cookie_values != NULL) {
@@ -2177,12 +2200,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
/* Allocate ancillary memory before locking.
*/
- if (ctd.tcpct_used > 0 ||
+ if (s_data_used > 0 ||
(tp->cookie_values == NULL &&
(sysctl_tcp_cookie_size > 0 ||
ctd.tcpct_cookie_desired > 0 ||
ctd.tcpct_s_data_desired > 0))) {
- cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
+ cvp = kzalloc(sizeof(*cvp) + s_data_used,
GFP_KERNEL);
if (cvp == NULL)
return -ENOMEM;
@@ -2191,7 +2214,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
}
lock_sock(sk);
tp->rx_opt.cookie_in_always =
- (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
+ (TCPCT_IN_ALWAYS & ctd.tcpct_flags);
tp->rx_opt.cookie_out_never = 0; /* false */
if (tp->cookie_values != NULL) {
@@ -2210,11 +2233,26 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (cvp != NULL) {
cvp->cookie_desired = ctd.tcpct_cookie_desired;
- if (ctd.tcpct_used > 0) {
- memcpy(cvp->s_data_payload, ctd.tcpct_value,
- ctd.tcpct_used);
- cvp->s_data_desired = ctd.tcpct_used;
+ if (s_data_used > 0) {
+ if (copy_from_user(cvp->s_data_payload,
+ optval + sizeof(ctd),
+ s_data_used)) {
+ kref_put(&cvp->kref,
+ tcp_cookie_values_release);
+ return -EFAULT;
+ }
+ cvp->s_data_desired = s_data_used;
cvp->s_data_constant = 1; /* true */
+ } else if (ctd.tcpct_used > 0) {
+ if (copy_from_user(cvp->cookie_pair,
+ optval + sizeof(ctd),
+ ctd.tcpct_used)) {
+ kref_put(&cvp->kref,
+ tcp_cookie_values_release);
+ return -EFAULT;
+ }
+ cvp->s_data_desired = ctd.tcpct_s_data_desired;
+ cvp->s_data_constant = 0; /* false */
} else {
/* No constant payload data. */
cvp->s_data_desired = ctd.tcpct_s_data_desired;
@@ -2574,7 +2612,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return 0;
case TCP_COOKIE_TRANSACTIONS: {
- struct tcp_cookie_transactions ctd;
+ struct tcpct_full ctd;
struct tcp_cookie_values *cvp = tp->cookie_values;
if (get_user(len, optlen))
@@ -2583,23 +2621,23 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return -EINVAL;
memset(&ctd, 0, sizeof(ctd));
- ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ?
- TCP_COOKIE_IN_ALWAYS : 0)
- | (tp->rx_opt.cookie_out_never ?
- TCP_COOKIE_OUT_NEVER : 0);
+ ctd.soh.tcpct_flags = (tp->rx_opt.cookie_in_always ?
+ TCPCT_IN_ALWAYS : 0)
+ | (tp->rx_opt.cookie_out_never ?
+ TCPCT_OUT_NEVER : 0);
if (cvp != NULL) {
- ctd.tcpct_flags |= (cvp->s_data_in ?
- TCP_S_DATA_IN : 0)
- | (cvp->s_data_out ?
- TCP_S_DATA_OUT : 0);
+ ctd.soh.tcpct_flags |= (cvp->s_data_in ?
+ TCPCT_IN_DATA : 0)
+ | (cvp->s_data_out ?
+ TCPCT_OUT_DATA : 0);
- ctd.tcpct_cookie_desired = cvp->cookie_desired;
- ctd.tcpct_s_data_desired = cvp->s_data_desired;
+ ctd.soh.tcpct_cookie_desired = cvp->cookie_desired;
+ ctd.soh.tcpct_s_data_desired = cvp->s_data_desired;
memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
cvp->cookie_pair_size);
- ctd.tcpct_used = cvp->cookie_pair_size;
+ ctd.soh.tcpct_used = cvp->cookie_pair_size;
}
if (put_user(sizeof(ctd), optlen))
--
1.7.1
^ permalink raw reply related
* TCPCT API update for 2.6.37
From: William Allen Simpson @ 2011-01-08 21:36 UTC (permalink / raw)
To: Linux Kernel Network Developers
With the recent flurry of messages related to TCPCT, I devoted a nice
snowy Saturday afternoon to updating the socket option code. Linux is
rather fair behind on TCPCT implementation, so this will help with
future software compatibility.
I'm not on this list, so anybody with comments should CC me. Thanks.
^ permalink raw reply
* Re: [PATCH] iproute2: ip: add wilcard support for device matching
From: Philip Prindeville @ 2011-01-08 21:10 UTC (permalink / raw)
To: hadi
Cc: Vlad Dogaru, Octavian Purdila, Eric Dumazet, Stephen Hemminger,
netdev, Lucian Adrian Grijincu
In-Reply-To: <1292937262.6535.15.camel@mojatatu>
On 12/21/10 5:14 AM, jamal wrote:
> On Mon, 2010-12-20 at 11:23 -0800, Vlad Dogaru wrote:
>
>> I'll try to implement this approach in the next few days.
> Excellent ;-> Remember, this is general purpose tag, sort
> like socket/route/skb->mark. It is upto the administrator to
> define its use via policy.
>
> cheers,
> jamal
Did that end up going anywhere?
There are a lot of cases where matching on "ppp*" would be handy.
^ permalink raw reply
* Re: Seeing transmit timeouts on 8139cp
From: Philip Prindeville @ 2011-01-08 21:09 UTC (permalink / raw)
To: Francois Romieu; +Cc: Linux Netdev List
In-Reply-To: <4C99A289.2030109@redfish-solutions.com>
On 9/21/10 11:30 PM, Philip Prindeville wrote:
> On 9/17/10 1:00 PM, Francois Romieu wrote:
>> Philip Prindeville<philipp_subx@redfish-solutions.com> :
>> [...]
>>> Does this look familiar to anyone?
>> 349124a00754129a5f1e43efa84733e364bf3749 ?
>>
>> It would be a bit too easy.
>>
> Thanks. I'll give it a try now.
No, that's not the problem. Still seeing traces, even after applying that patch.
This is in 2.6.27.57:
Jan 8 00:11:25 pdx user.warn kernel: ------------[ cut here ]------------
Jan 8 00:11:25 pdx user.warn kernel: WARNING: at net/sched/sch_generic.c:219 dev_watchdog+0xf1/0x176()
Jan 8 00:11:25 pdx user.info kernel: NETDEV WATCHDOG: eth1 (8139cp): transmit timed out
Jan 8 00:11:25 pdx user.warn kernel: Modules linked in: pppoatm pppox ppp_generic slhc bridge stp llc solos_pci atm dummy ath5k mac80211 ath cfg80211 rfkill_backport compat dahdi sha512_generic sha256_generic deflate zlib_deflate arc4 ecb sha1_generic blowfish des
Jan 8 00:11:25 pdx user.warn kernel: Pid: 0, comm: swapper Tainted: P 2.6.27.57-astlinux #1
Jan 8 00:11:25 pdx user.warn kernel: [<c0115462>] warn_slowpath+0x61/0x84
Jan 8 00:11:25 pdx user.warn kernel: [<c026649b>] nf_hook_slow+0x44/0xb1
Jan 8 00:11:25 pdx user.warn kernel: [<e018d968>] br_nf_pre_routing_finish+0x0/0x257 [bridge]
Jan 8 00:11:25 pdx user.warn kernel: [<e018e5a3>] br_nf_pre_routing+0x532/0x54b [bridge]
Jan 8 00:11:25 pdx user.warn kernel: [<c01065e8>] read_tsc+0x6/0x22
Jan 8 00:11:25 pdx user.warn kernel: [<c01289a6>] getnstimeofday+0x4a/0xc7
Jan 8 00:11:25 pdx user.warn kernel: [<c01267ca>] ktime_get_ts+0x1d/0x3f
Jan 8 00:11:25 pdx user.warn kernel: [<c0126056>] hrtimer_forward+0xe2/0xfe
Jan 8 00:11:25 pdx user.warn kernel: [<c025e0b3>] dev_watchdog+0x0/0x176
Jan 8 00:11:25 pdx user.warn kernel: [<c01cfb57>] strlcpy+0x15/0x62
Jan 8 00:11:25 pdx user.warn kernel: [<c025e1a4>] dev_watchdog+0xf1/0x176
Jan 8 00:11:25 pdx user.warn kernel: [<e00e7f3c>] coretimer_func+0xb1/0x133 [dahdi]
Jan 8 00:11:25 pdx user.warn kernel: [<c011c05a>] run_timer_softirq+0x116/0x17a
Jan 8 00:11:25 pdx user.warn kernel: [<c0118ce4>] __do_softirq+0x35/0x75
Jan 8 00:11:25 pdx user.warn kernel: [<c0118d46>] do_softirq+0x22/0x26
Jan 8 00:11:25 pdx user.warn kernel: [<c0118f20>] irq_exit+0x25/0x30
Jan 8 00:11:25 pdx user.warn kernel: [<c010477c>] do_IRQ+0x4d/0x5d
Jan 8 00:11:25 pdx user.warn kernel: [<c010394b>] common_interrupt+0x23/0x28
Jan 8 00:11:25 pdx user.warn kernel: [<c0106f3d>] default_idle+0x25/0x38
Jan 8 00:11:25 pdx user.warn kernel: [<c010254b>] cpu_idle+0x37/0x5f
Jan 8 00:11:25 pdx user.warn kernel: =======================
Jan 8 00:11:25 pdx user.warn kernel: ---[ end trace 4eb2e0ef5bc6569d ]---
Jan 8 00:11:25 pdx user.warn kernel: eth1: Transmit timeout, status c 2b 0 80ff
Any other ideas?
Thanks.
^ permalink raw reply
* Re: iproute2 caching and batch mode
From: denys @ 2011-01-08 20:36 UTC (permalink / raw)
To: denys; +Cc: Stephen Hemminger, netdev
In-Reply-To: <0befc7c09f04936c1244eaa5a1d2620c@localhost>
On Sat, 08 Jan 2011 22:09:39 +0200, <denys@visp.net.lb> wrote:
> Hi,
>
> noticed some issue a while ago, and because of recent patches decided to
> post my thoughts:
>
> This issue can happen if ip or tc running in some kind of "daemon" batch
> mode, or processing large batch file on computer where interfaces can
> reappear with same name but different index (pppoe NAS for example).
>
> It is easy to reproduce the problem:
>
> centaur iproute2-2.6.37 # ip/ip -force -batch -
> tunnel add test0 mode ipip remote 1.1.1.2 local 1.1.1.1
> link show dev test0
> 201: test0: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN
> link/ipip 1.1.1.1 peer 1.1.1.2
> tunnel del test0
> Unsupported family:17
>
> Or:
>
> centaur iproute2-2.6.37 # ip/ip -force -batch -
> tunnel del test0
> tunnel add test0 mode ipip remote 1.1.1.2 local 1.1.1.1
> link show dev test0
> 202: test0: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN
> link/ipip 1.1.1.1 peer 1.1.1.2
> (another console, delete and create again test0)
> link show dev test0
> (nothing will appear)
Sorry, just got mail sent before i finish it.
Is it appropriate to implement some kind of "flush" command, to flush
internal cache?
I can try to do that, if this way is ok.
Sure maybe best way to monitor interface updates over netlink, in batch
mode, and update cache accordingly.
^ permalink raw reply
* iproute2 caching and batch mode
From: denys @ 2011-01-08 20:09 UTC (permalink / raw)
To: Stephen Hemminger, netdev
Hi,
noticed some issue a while ago, and because of recent patches decided to
post my thoughts:
This issue can happen if ip or tc running in some kind of "daemon" batch
mode, or processing large batch file on computer where interfaces can
reappear with same name but different index (pppoe NAS for example).
It is easy to reproduce the problem:
centaur iproute2-2.6.37 # ip/ip -force -batch -
tunnel add test0 mode ipip remote 1.1.1.2 local 1.1.1.1
link show dev test0
201: test0: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN
link/ipip 1.1.1.1 peer 1.1.1.2
tunnel del test0
Unsupported family:17
Or:
centaur iproute2-2.6.37 # ip/ip -force -batch -
tunnel del test0
tunnel add test0 mode ipip remote 1.1.1.2 local 1.1.1.1
link show dev test0
202: test0: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN
link/ipip 1.1.1.1 peer 1.1.1.2
(another console, delete and create again test0)
link show dev test0
(nothing will appear)
^ permalink raw reply
* Re: 2.6.37 vlans on bnx2 not functional, panic with tcpdump
From: Jarek Poplawski @ 2011-01-08 18:41 UTC (permalink / raw)
To: Iain Paton
Cc: Michael Chan, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <4D2754F9.8050707@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 276 bytes --]
Iain Paton wrote:
...
> So you can consider any bnx2 cause for this closed. I'll get back to the
> list if I can come up with any more useful info.
Hi Iain,
If it's not a problem, please try if the attached debugging patch
(not tested) can change anything.
Thanks,
Jarek P.
[-- Attachment #2: dev.c.deliver_skb.1.diff --]
[-- Type: text/plain, Size: 1286 bytes --]
diff --git a/net/core/dev.c b/net/core/dev.c
index 0dd54a6..9244373 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2720,6 +2720,17 @@ static inline int deliver_skb(struct sk_buff *skb,
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}
+static inline int deliver_skb_clone(struct sk_buff *skb,
+ struct packet_type *pt_prev,
+ struct net_device *orig_dev)
+{
+ struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+ if (!nskb)
+ return 0;
+ return pt_prev->func(nskb, nskb->dev, pt_prev, orig_dev);
+}
+
#if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \
(defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE))
/* This hook is defined here for ATM LANE */
@@ -2950,7 +2961,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
ptype->dev == orig_dev) {
if (pt_prev)
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb_clone(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
@@ -2976,7 +2987,7 @@ ncls:
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
- ret = deliver_skb(skb, pt_prev, orig_dev);
+ ret = deliver_skb_clone(skb, pt_prev, orig_dev);
pt_prev = NULL;
}
if (vlan_hwaccel_do_receive(&skb)) {
^ permalink raw reply related
* Re: [PATCH V8 02/13] ntp: add ADJ_SETOFFSET mode bit
From: Richard Cochran @ 2011-01-08 17:50 UTC (permalink / raw)
To: Kuwahara,T.
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
Alan Cox, Arnd Bergmann, Christoph Lameter, David Miller,
John Stultz, Krzysztof Halasa, Peter Zijlstra, Rodolfo Giometti,
Thomas Gleixner
In-Reply-To: <AANLkTini2WdT-1v4k9V3JOZYDkA59P+SyscTe8-fK2Wk-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Sun, Jan 02, 2011 at 05:38:19AM +0900, Kuwahara,T. wrote:
> As you know, it conflicts with MOD_PPSMAX. And also, it is logically
> the same as ADJ_OFFSET, unless the kernel PLL is enabled explicitly.
I choose another bit, for the next version of the patch series.
>
> So here's my simple solution:
>
I have read the API documentation in the nanokernel source archive. It
explains the (very complex looking) timex structure quite clearly and
nicely. Now I am more convinced than ever that adding a new mode bit
is the best way to go, as opposed to ADJ_OFFSET/!STA_PLL, because:
1. The mode bits update kernel variables. That is what we want.
2. Clearing STA_PLL means disable adjustments.
3. The range of the timex.offset is way too small.
I expand on each point, below. BTW, the API document is also available
for online reading here:
http://www.slac.stanford.edu/comp/unix/package/rtems/src/ssrlApps/ntpNanoclock/api.htm
1. Looking at the API, the documentation for the bits of the 'modes'
field states:
These bits control which field of the timex structure are used
to update the corresponding kernel variable. The bits may be
set in any combination. See the description below for which
bits control which variable.
With the ADJ_SETOFFSET mode, we are telling the kernel to update
the instantaneous value of the 'current time' variable. That usage
agrees with the sematics of the other mode bits.
2. The documentation for STA_PLL states:
Master enable switch for the PLL/FLL loop. The algorithm is
responsive to time and/or frequency updates if set; otherwise,
no change in the current time or frequency will be made other
than to complete a pending phase adjustment. This bit does not
affect the PPS loop.
So when we clear this bit, the kernel promises that it will make
"no change in the current time." The proposed ADJ_OFFSET/!STA_PLL
solution would break this pattern.
3. The timex.offset field is of type "long" and represents either
nanoseconds or microseconds. On 32 bit architectures, the maximum
possible adjustment would be
2^31 * 10^-6 = 2147.5 seconds
which is less than one hour. For the first adjustment of a clock,
we want to be able to jump the clock arbitrarily. Not every
computer has an RTC, and so some boot up believing that it is still
the year 1970.
Richard
^ permalink raw reply
* Re: [PATCH v4 net-next-2.6] netfilter: x_tables: dont block BH while reading counters
From: Eric Dumazet @ 2011-01-08 16:45 UTC (permalink / raw)
To: Patrick McHardy, David Miller
Cc: Jesper Dangaard Brouer, netfilter-devel, netdev,
Stephen Hemminger
In-Reply-To: <1292646579.7894.42.camel@edumazet-laptop>
David,
I am resending this patch, sent 3 weeks ago, Patrick gave no answer.
I believe it should be included in linux-2.6.38 and stable kernels.
Some people found they had to change NIC RX ring sizes in order not
missing frames (from 1024 to 2048), while root cause of the problem was
this.
Quoting Jesper : "I can now hit the system with a pktgen at 128 bytes,
and see no drops/overruns while running iptables. (This packet load at
128bytes is 822 kpps and 840Mbit/s) (iptables ruleset is the big chains:
20929 rules: 81239)."
Thanks
[PATCH v4] netfilter: x_tables: dont block BH while reading counters
Using "iptables -L" with a lot of rules have a too big BH latency.
Jesper mentioned ~6 ms and worried of frame drops.
Switch to a per_cpu seqlock scheme, so that taking a snapshot of
counters doesnt need to block BH (for this cpu, but also other cpus).
This adds two increments on seqlock sequence per ipt_do_table() call,
its a reasonable cost for allowing "iptables -L" not block BH
processing.
Reported-by: Jesper Dangaard Brouer <hawk@comx.dk>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Patrick McHardy <kaber@trash.net>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Acked-by: Jesper Dangaard Brouer <hawk@comx.dk>
---
include/linux/netfilter/x_tables.h | 10 +++---
net/ipv4/netfilter/arp_tables.c | 45 ++++++++-------------------
net/ipv4/netfilter/ip_tables.c | 45 ++++++++-------------------
net/ipv6/netfilter/ip6_tables.c | 45 ++++++++-------------------
net/netfilter/x_tables.c | 3 +
5 files changed, 49 insertions(+), 99 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 742bec0..6712e71 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -472,7 +472,7 @@ extern void xt_free_table_info(struct xt_table_info *info);
* necessary for reading the counters.
*/
struct xt_info_lock {
- spinlock_t lock;
+ seqlock_t lock;
unsigned char readers;
};
DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks);
@@ -497,7 +497,7 @@ static inline void xt_info_rdlock_bh(void)
local_bh_disable();
lock = &__get_cpu_var(xt_info_locks);
if (likely(!lock->readers++))
- spin_lock(&lock->lock);
+ write_seqlock(&lock->lock);
}
static inline void xt_info_rdunlock_bh(void)
@@ -505,7 +505,7 @@ static inline void xt_info_rdunlock_bh(void)
struct xt_info_lock *lock = &__get_cpu_var(xt_info_locks);
if (likely(!--lock->readers))
- spin_unlock(&lock->lock);
+ write_sequnlock(&lock->lock);
local_bh_enable();
}
@@ -516,12 +516,12 @@ static inline void xt_info_rdunlock_bh(void)
*/
static inline void xt_info_wrlock(unsigned int cpu)
{
- spin_lock(&per_cpu(xt_info_locks, cpu).lock);
+ write_seqlock(&per_cpu(xt_info_locks, cpu).lock);
}
static inline void xt_info_wrunlock(unsigned int cpu)
{
- spin_unlock(&per_cpu(xt_info_locks, cpu).lock);
+ write_sequnlock(&per_cpu(xt_info_locks, cpu).lock);
}
/*
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 3fac340..e855fff 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -710,42 +710,25 @@ static void get_counters(const struct xt_table_info *t,
struct arpt_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu = get_cpu();
-
- /* Instead of clearing (by a previous call to memset())
- * the counters and using adds, we set the counters
- * with data used by 'current' CPU
- *
- * Bottom half has to be disabled to prevent deadlock
- * if new softirq were to run and call ipt_do_table
- */
- local_bh_disable();
- i = 0;
- xt_entry_foreach(iter, t->entries[curcpu], t->size) {
- SET_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
- ++i;
- }
- local_bh_enable();
- /* Processing counters from other cpus, we can let bottom half enabled,
- * (preemption is disabled)
- */
for_each_possible_cpu(cpu) {
- if (cpu == curcpu)
- continue;
+ seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+
i = 0;
- local_bh_disable();
- xt_info_wrlock(cpu);
xt_entry_foreach(iter, t->entries[cpu], t->size) {
- ADD_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
+ u64 bcnt, pcnt;
+ unsigned int start;
+
+ do {
+ start = read_seqbegin(lock);
+ bcnt = iter->counters.bcnt;
+ pcnt = iter->counters.pcnt;
+ } while (read_seqretry(lock, start));
+
+ ADD_COUNTER(counters[i], bcnt, pcnt);
++i;
}
- xt_info_wrunlock(cpu);
- local_bh_enable();
}
- put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -759,7 +742,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
* about).
*/
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc(countersize);
+ counters = vzalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1007,7 +990,7 @@ static int __do_replace(struct net *net, const char *name,
struct arpt_entry *iter;
ret = 0;
- counters = vmalloc(num_counters * sizeof(struct xt_counters));
+ counters = vzalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index a846d63..652efea 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -884,42 +884,25 @@ get_counters(const struct xt_table_info *t,
struct ipt_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu = get_cpu();
-
- /* Instead of clearing (by a previous call to memset())
- * the counters and using adds, we set the counters
- * with data used by 'current' CPU.
- *
- * Bottom half has to be disabled to prevent deadlock
- * if new softirq were to run and call ipt_do_table
- */
- local_bh_disable();
- i = 0;
- xt_entry_foreach(iter, t->entries[curcpu], t->size) {
- SET_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
- ++i;
- }
- local_bh_enable();
- /* Processing counters from other cpus, we can let bottom half enabled,
- * (preemption is disabled)
- */
for_each_possible_cpu(cpu) {
- if (cpu == curcpu)
- continue;
+ seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+
i = 0;
- local_bh_disable();
- xt_info_wrlock(cpu);
xt_entry_foreach(iter, t->entries[cpu], t->size) {
- ADD_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
+ u64 bcnt, pcnt;
+ unsigned int start;
+
+ do {
+ start = read_seqbegin(lock);
+ bcnt = iter->counters.bcnt;
+ pcnt = iter->counters.pcnt;
+ } while (read_seqretry(lock, start));
+
+ ADD_COUNTER(counters[i], bcnt, pcnt);
++i; /* macro does multi eval of i */
}
- xt_info_wrunlock(cpu);
- local_bh_enable();
}
- put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -932,7 +915,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
(other than comefrom, which userspace doesn't care
about). */
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc(countersize);
+ counters = vzalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1203,7 +1186,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
struct ipt_entry *iter;
ret = 0;
- counters = vmalloc(num_counters * sizeof(struct xt_counters));
+ counters = vzalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 4555823..7d227c6 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -897,42 +897,25 @@ get_counters(const struct xt_table_info *t,
struct ip6t_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu = get_cpu();
-
- /* Instead of clearing (by a previous call to memset())
- * the counters and using adds, we set the counters
- * with data used by 'current' CPU
- *
- * Bottom half has to be disabled to prevent deadlock
- * if new softirq were to run and call ipt_do_table
- */
- local_bh_disable();
- i = 0;
- xt_entry_foreach(iter, t->entries[curcpu], t->size) {
- SET_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
- ++i;
- }
- local_bh_enable();
- /* Processing counters from other cpus, we can let bottom half enabled,
- * (preemption is disabled)
- */
for_each_possible_cpu(cpu) {
- if (cpu == curcpu)
- continue;
+ seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
+
i = 0;
- local_bh_disable();
- xt_info_wrlock(cpu);
xt_entry_foreach(iter, t->entries[cpu], t->size) {
- ADD_COUNTER(counters[i], iter->counters.bcnt,
- iter->counters.pcnt);
+ u64 bcnt, pcnt;
+ unsigned int start;
+
+ do {
+ start = read_seqbegin(lock);
+ bcnt = iter->counters.bcnt;
+ pcnt = iter->counters.pcnt;
+ } while (read_seqretry(lock, start));
+
+ ADD_COUNTER(counters[i], bcnt, pcnt);
++i;
}
- xt_info_wrunlock(cpu);
- local_bh_enable();
}
- put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -945,7 +928,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
(other than comefrom, which userspace doesn't care
about). */
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc(countersize);
+ counters = vzalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1216,7 +1199,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
struct ip6t_entry *iter;
ret = 0;
- counters = vmalloc(num_counters * sizeof(struct xt_counters));
+ counters = vzalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 8046350..c942376 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1325,7 +1325,8 @@ static int __init xt_init(void)
for_each_possible_cpu(i) {
struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
- spin_lock_init(&lock->lock);
+
+ seqlock_init(&lock->lock);
lock->readers = 0;
}
^ permalink raw reply related
* Re: [PATCH V8 12/13] ptp: Added a clock driver for the IXP46x.
From: Krzysztof Halasa @ 2011-01-08 16:25 UTC (permalink / raw)
To: Richard Cochran
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
Alan Cox, Arnd Bergmann, Christoph Lameter, David Miller,
John Stultz, Peter Zijlstra, Rodolfo Giometti, Thomas Gleixner
In-Reply-To: <20110107170752.GB8666-7KxsofuKt4IfAd9E5cN8NEzG7cXyKsk/@public.gmane.org>
Richard Cochran <richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> The time stamp code clones the skb, but the LE version frees the skb
> too early. Perhaps we can move that dev_kfree_skb(skb) in the LE case
> to be the last statement in eth_xmit(). What do you think?
I think so. Or something similar.
> Do you mean, you don't like the constant on the left hand side?
Yes.
> Is that prohibited by CodingStyle or similar?
I don't think so. It's just a personal taste. I think it's based on
things learned in primary school, they teach to write (comparisons)
X = 4 instead of the other way around, and my brain seems to shock
a bit on the opposite.
> I got into the habit of writing it that way to prevent a typo like:
>
> if (irq = NO_IRQ)
I see. Unfortunately it doesn't prevent typos like this when the right
side isn't a constant. Anyway gcc warns about them, even when both sides
are variable.
>> Also I don't like the ixp_read/ixp_write() trivial macros. Why not
>> simply call __raw_readl() and __raw_writel()?
>
> Well, I have had the experience back in 2.4 days of having my drivers
> ruined by the changing IO macros in the kernel. The wrappers are
> supposed to help if that ever happens again. Seeing *two* leading
> underscores in the macro names certainly makes me nervous.
Well, these two underscores mainly mean it's arch-dependent, but so are
the ixp4xx drivers. Using the __raw_read* directly is the preferred
method (or, perhaps, in such case, it's the only way).
Actually, I was thinking about changing the macros some time ago, and it
may eventually happen. But we'll fix all the code using them then.
--
Krzysztof Halasa
^ permalink raw reply
* Re: [PATCH] net_sched: factorize qdisc stats handling
From: Eric Dumazet @ 2011-01-08 15:40 UTC (permalink / raw)
To: Jarek Poplawski
Cc: Stephen Hemminger, Changli Gao, David Miller, Fabio Checconi,
netdev, Luigi Rizzo
In-Reply-To: <4D286823.8050707@gmail.com>
Le samedi 08 janvier 2011 à 14:35 +0100, Jarek Poplawski a écrit :
> I guess you can't use qdisc_pkt_len() without qdisc_enqueue_root().
>
Indeed !
This TCQ_F_CAN_BYPASS thing is truly evil ;)
Hmm, this makes me thing we could add TCQ_F_CAN_BYPASS on SFQ.
Thanks !
^ permalink raw reply
* Re: [PATCH] net_sched: factorize qdisc stats handling
From: Jarek Poplawski @ 2011-01-08 13:35 UTC (permalink / raw)
To: Eric Dumazet
Cc: Stephen Hemminger, Changli Gao, David Miller, Fabio Checconi,
netdev, Luigi Rizzo
In-Reply-To: <1294478789.2709.79.camel@edumazet-laptop>
Eric Dumazet wrote:
...
> -static inline void __qdisc_update_bstats(struct Qdisc *sch, unsigned int len)
> +
> +static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
> + struct sk_buff *skb)
> +{
> + bstats->bytes += qdisc_pkt_len(skb);
> + bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
> +}
> +
> +static inline void qdisc_bstats_update(struct Qdisc *sch, struct sk_buff *skb)
> {
> - sch->bstats.bytes += len;
> - sch->bstats.packets++;
> + bstats_update(&sch->bstats, skb);
> }
>
> static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
> @@ -437,7 +444,7 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
> {
> __skb_queue_tail(list, skb);
> sch->qstats.backlog += qdisc_pkt_len(skb);
> - __qdisc_update_bstats(sch, qdisc_pkt_len(skb));
> + qdisc_bstats_update(sch, skb);
>
> return NET_XMIT_SUCCESS;
> }
> diff --git a/net/core/dev.c b/net/core/dev.c
> index a215269..ab60f58 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2301,7 +2301,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
> */
> if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
> skb_dst_force(skb);
> - __qdisc_update_bstats(q, skb->len);
> + qdisc_bstats_update(q, skb);
> if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
> if (unlikely(contended)) {
> spin_unlock(&q->busylock);
I guess you can't use qdisc_pkt_len() without qdisc_enqueue_root().
Jarek P.
^ permalink raw reply
* [e100] Page allocation failure warning(?) in 2.6.36.3
From: Chris Rankin @ 2011-01-08 12:53 UTC (permalink / raw)
To: e1000-devel; +Cc: netdev
Hi,
I've just booted 2.6.36.3 on my old router box (which contains one single e100 card, and one dual-port e100 card), and have discovered this rather scary message in the dmesg log:
e100: Intel(R) PRO/100 Network Driver, 3.5.24-k2-NAPI
e100: Copyright(c) 1999-2006 Intel Corporation
e100 0000:00:0f.0: PME# disabled
e100 0000:00:0f.0: eth0: addr 0xffbeb000, irq 10, MAC addr 00:90:27:76:d0:ec
e100 0000:01:04.0: PME# disabled
e100 0000:01:04.0: eth1: addr 0xff0fe000, irq 11, MAC addr 00:03:47:3b:29:5c
e100 0000:01:05.0: PME# disabled
e100 0000:01:05.0: eth2: addr 0xff0ff000, irq 10, MAC addr 00:03:47:3b:29:5d
...
device eth1 entered promiscuous mode
ADDRCONF(NETDEV_UP): eth1: link is not ready
e100 0000:01:04.0: eth1: NIC Link is Up 100 Mbps Full Duplex
ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready
device eth2 entered promiscuous mode
ADDRCONF(NETDEV_UP): eth2: link is not ready
br0: port 1(eth1) entering learning state
br0: port 1(eth1) entering learning state
ifconfig: page allocation failure. order:6, mode:0x8020
Pid: 3716, comm: ifconfig Not tainted 2.6.36.3 #1
Call Trace:
[<c104b2a9>] ? __alloc_pages_nodemask+0x477/0x4a6
[<c106177d>] ? __slab_alloc+0x1eb/0x396
[<c1004ca6>] ? dma_generic_alloc_coherent+0x4e/0xac
[<c105fb5c>] ? dma_pool_alloc+0xe5/0x1d9
[<c1004c58>] ? dma_generic_alloc_coherent+0x0/0xac
[<c58f97f3>] ? e100_rx_alloc_skb+0x87/0x122 [e100]
[<c58f9883>] ? e100_rx_alloc_skb+0x117/0x122 [e100]
[<c58f98dc>] ? e100_alloc_cbs+0x4e/0xfa [e100]
[<c58fb370>] ? e100_up+0x1b/0xf1 [e100]
[<c58fb45d>] ? e100_open+0x17/0x3b [e100]
[<c1121630>] ? __dev_open+0x7c/0xa0
[<c11217ed>] ? __dev_change_flags+0x8b/0x100
[<c11218c3>] ? dev_change_flags+0x10/0x3b
[<c1159880>] ? devinet_ioctl+0x25a/0x532
[<c11146d2>] ? sock_ioctl+0x1a8/0x1ca
[<c111452a>] ? sock_ioctl+0x0/0x1ca
[<c106e061>] ? do_vfs_ioctl+0x464/0x4a2
[<c1014ce0>] ? do_page_fault+0x2d2/0x2ea
[<c1014cc8>] ? do_page_fault+0x2ba/0x2ea
[<c10636f6>] ? sys_faccessat+0x144/0x151
[<c106e0cc>] ? sys_ioctl+0x2d/0x49
[<c1177dd5>] ? syscall_call+0x7/0xb
Mem-Info:
DMA per-cpu:
CPU 0: hi: 0, btch: 1 usd: 0
Normal per-cpu:
CPU 0: hi: 6, btch: 1 usd: 0
active_anon:280 inactive_anon:808 isolated_anon:0
active_file:1384 inactive_file:9672 isolated_file:0
unevictable:0 dirty:77 writeback:0 unstable:0
free:753 slab_reclaimable:499 slab_unreclaimable:1393
mapped:375 shmem:643 pagetables:59 bounce:0
DMA free:1492kB min:248kB low:308kB high:372kB active_anon:0kB inactive_anon:12kB active_file:288kB inactive_file:12548kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15864kB mlocked:0kB dirty:48kB writeback:0kB mapped:28kB shmem:0kB slab_reclaimable:312kB slab_unreclaimable:884kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
lowmem_reserve[]: 0 47 47
Normal free:1520kB min:764kB low:952kB high:1144kB active_anon:1120kB inactive_anon:3220kB active_file:5248kB inactive_file:26140kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:48768kB mlocked:0kB dirty:260kB writeback:0kB mapped:1472kB shmem:2572kB slab_reclaimable:1684kB slab_unreclaimable:4688kB kernel_stack:176kB pagetables:236kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
lowmem_reserve[]: 0 0 0
DMA: 51*4kB 23*8kB 3*16kB 3*32kB 7*64kB 4*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1492kB
Normal: 260*4kB 26*8kB 1*16kB 0*32kB 0*64kB 0*128kB 1*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1520kB
11715 total pagecache pages
16 pages in swap cache
Swap cache stats: add 44, delete 28, find 72/72
Free swap = 2179532kB
Total swap = 2179596kB
16383 pages RAM
826 pages reserved
10736 pages shared
5361 pages non-shared
ADDRCONF(NETDEV_UP): eth0: link is not ready
e100 0000:00:0f.0: eth0: NIC Link is Up 100 Mbps Full Duplex
ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
br0: port 1(eth1) entering forwarding state
Should I be concerned, please? All three e100 devices still appear to be working, but something nasty seems to have happened anyway.
The lspci output for these devices is:
00:0f.0 0200: 8086:1229 (rev 08)
Subsystem: 8086:000c
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 72 (2000ns min, 14000ns max), Cache Line Size: 32 bytes
Interrupt: pin A routed to IRQ 10
Region 0: Memory at ffbeb000 (32-bit, non-prefetchable) [size=4K]
Region 1: I/O ports at ef00 [size=64]
Region 2: Memory at fef00000 (32-bit, non-prefetchable) [size=1M]
[virtual] Expansion ROM at 04000000 [disabled] [size=1M]
Capabilities: [dc] Power Management version 2
Flags: PMEClk- DSI+ D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=2 PME-
Kernel driver in use: e100
Kernel modules: e100
01:04.0 0200: 8086:1229 (rev 05)
Subsystem: 8086:10f0
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 72 (2000ns min, 14000ns max), Cache Line Size: 32 bytes
Interrupt: pin A routed to IRQ 11
Region 0: Memory at ff0fe000 (32-bit, prefetchable) [size=4K]
Region 1: I/O ports at fcc0 [size=32]
Region 2: Memory at ff700000 (32-bit, non-prefetchable) [size=1M]
[virtual] Expansion ROM at ff100000 [disabled] [size=1M]
Capabilities: [dc] Power Management version 1
Flags: PMEClk- DSI+ D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: e100
Kernel modules: e100
01:05.0 0200: 8086:1229 (rev 05)
Subsystem: 8086:10f0
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 72 (2000ns min, 14000ns max), Cache Line Size: 32 bytes
Interrupt: pin A routed to IRQ 10
Region 0: Memory at ff0ff000 (32-bit, prefetchable) [size=4K]
Region 1: I/O ports at fce0 [size=32]
Region 2: Memory at ff900000 (32-bit, non-prefetchable) [size=1M]
[virtual] Expansion ROM at ff200000 [disabled] [size=1M]
Capabilities: [dc] Power Management version 1
Flags: PMEClk- DSI+ D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: e100
Kernel modules: e100
Thanks,
Chris
------------------------------------------------------------------------------
Gaining the trust of online customers is vital for the success of any company
that requires sensitive data to be transmitted over the Web. Learn how to
best implement a security strategy that keeps consumers' information secure
and instills the confidence they need to proceed with transactions.
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: [GIT] Networking
From: Francois Romieu @ 2011-01-08 12:17 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ben Hutchings, David Miller, Hayes Wang, David Woodhouse, akpm,
netdev, linux-kernel
In-Reply-To: <20110108000901.GA2133@electric-eye.fr.zoreil.com>
r8169: delay phy init until device opens.
It workarounds the 60s firmware load failure timeout for the
non-modular case.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 27a7c20..dd758cd 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -3069,15 +3069,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8168_driver_start(tp);
}
- rtl8169_init_phy(dev, tp);
-
- /*
- * Pretend we are using VLANs; This bypasses a nasty bug where
- * Interrupts stop flowing on high load on 8110SCd controllers.
- */
- if (tp->mac_version == RTL_GIGA_MAC_VER_05)
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
-
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
if (pci_dev_run_wake(pdev))
@@ -3127,6 +3118,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
static int rtl8169_open(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
int retval = -ENOMEM;
@@ -3162,6 +3154,15 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+ rtl8169_init_phy(dev, tp);
+
+ /*
+ * Pretend we are using VLANs; This bypasses a nasty bug where
+ * Interrupts stop flowing on high load on 8110SCd controllers.
+ */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
+
rtl_pll_power_up(tp);
rtl_hw_start(dev);
@@ -3171,7 +3172,7 @@ static int rtl8169_open(struct net_device *dev)
tp->saved_wolopts = 0;
pm_runtime_put_noidle(&pdev->dev);
- rtl8169_check_link_status(dev, tp, tp->mmio_addr);
+ rtl8169_check_link_status(dev, tp, ioaddr);
out:
return retval;
^ permalink raw reply related
* Re: [PATCH v2] net: ppp: use {get,put}_unaligned_be{16,32}
From: Jarek Poplawski @ 2011-01-08 10:33 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, xiaosuo, paulus, harvey.harrison, linux-ppp, netdev
In-Reply-To: <1294482005.2709.90.camel@edumazet-laptop>
Eric Dumazet wrote:
> Le samedi 08 janvier 2011 à 11:04 +0100, Jarek Poplawski a écrit :
>
>> Just for the record: I agree with Paul that current code is more readable.
>> This code still requires thinking about specific bytes and the patch mixes
>> it only with word access.
>>
>> Jarek P.
>>
>>> @@ -395,16 +396,14 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
>>> */
>>> obuf[0] = PPP_ADDRESS(ibuf);
>>> obuf[1] = PPP_CONTROL(ibuf);
>>> - obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */
>>> - obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */
>>> + put_unaligned_be16(PPP_COMP, obuf + 2);
>>> obuf += PPP_HDRLEN;
>
> Compilers are stupid not generating optimal code, so we should help them
> a bit.
>
> Yes, I agree this is ugly Jarek and makes reading of this code a bit
> more complex, but this is a move we cannot stop. Number of functions,
> macros, etc... is exploding and we must follow the trend ;)
>
> 41 c6 44 24 02 00 movb $0x0,0x2(%r12)
> 41 c6 44 24 03 fd movb $0xfd,0x3(%r12)
>
> After patch :
>
> 66 41 c7 44 24 02 00 fd movw $0xfd00,0x2(%r12)
And that's why Paul wanted more justification, because readability
gain is questionable.
Jarek P.
^ permalink raw reply
* Re: [PATCH v2] net: ppp: use {get,put}_unaligned_be{16,32}
From: Eric Dumazet @ 2011-01-08 10:20 UTC (permalink / raw)
To: Jarek Poplawski
Cc: David Miller, xiaosuo, paulus, harvey.harrison, linux-ppp, netdev
In-Reply-To: <4D2836BB.6000600@gmail.com>
Le samedi 08 janvier 2011 à 11:04 +0100, Jarek Poplawski a écrit :
> Just for the record: I agree with Paul that current code is more readable.
> This code still requires thinking about specific bytes and the patch mixes
> it only with word access.
>
> Jarek P.
>
> > @@ -395,16 +396,14 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
> > */
> > obuf[0] = PPP_ADDRESS(ibuf);
> > obuf[1] = PPP_CONTROL(ibuf);
> > - obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */
> > - obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */
> > + put_unaligned_be16(PPP_COMP, obuf + 2);
> > obuf += PPP_HDRLEN;
Compilers are stupid not generating optimal code, so we should help them
a bit.
Yes, I agree this is ugly Jarek and makes reading of this code a bit
more complex, but this is a move we cannot stop. Number of functions,
macros, etc... is exploding and we must follow the trend ;)
41 c6 44 24 02 00 movb $0x0,0x2(%r12)
41 c6 44 24 03 fd movb $0xfd,0x3(%r12)
After patch :
66 41 c7 44 24 02 00 fd movw $0xfd00,0x2(%r12)
^ permalink raw reply
* Re: [PATCH v2] net: ppp: use {get,put}_unaligned_be{16,32}
From: Jarek Poplawski @ 2011-01-08 10:04 UTC (permalink / raw)
To: David Miller; +Cc: xiaosuo, paulus, harvey.harrison, linux-ppp, netdev
In-Reply-To: <20110107.171534.193718114.davem@davemloft.net>
David Miller wrote:
> From: Changli Gao <xiaosuo@gmail.com>
> Date: Sat, 8 Jan 2011 08:43:01 +0800
>
>> On Fri, Jan 7, 2011 at 11:01 AM, Paul Mackerras <paulus@samba.org> wrote:
>>> On Fri, Jan 07, 2011 at 07:37:36AM +0800, Changli Gao wrote:
>>>
>>>> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
>>>
>>> This patch description is inadequate. It should tell us why you are
>>> making this change. Does it result in smaller and/or faster code, and
>>> if so by how much on what sort of machine? Do you think it makes the
>>> code clearer? (I don't.) Or is there some other motivation for this?
>>>
>>
>> Good designed APIs always make code clearer, smaller and faster. It is
>> obvious enough I think.
>
> I have to say that every time I go read the header parsing code in the
> PPP driver, I absolutely regret it.
>
> And Changli's patch fixes some of the readability problems.
Just for the record: I agree with Paul that current code is more readable.
This code still requires thinking about specific bytes and the patch mixes
it only with word access.
Jarek P.
> @@ -395,16 +396,14 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
> */
> obuf[0] = PPP_ADDRESS(ibuf);
> obuf[1] = PPP_CONTROL(ibuf);
> - obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */
> - obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */
> + put_unaligned_be16(PPP_COMP, obuf + 2);
> obuf += PPP_HDRLEN;
^ permalink raw reply
* [PATCH] net_sched: factorize qdisc stats handling
From: Eric Dumazet @ 2011-01-08 9:26 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Changli Gao, David Miller, Fabio Checconi, netdev, Luigi Rizzo
In-Reply-To: <20110107200234.3f5e7ff8@nehalam>
Le vendredi 07 janvier 2011 à 20:02 -0800, Stephen Hemminger a écrit :
> On Sat, 8 Jan 2011 10:56:33 +0800
> Changli Gao <xiaosuo@gmail.com> wrote:
>
> > > + cl->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
> >
> > Hmm, there is no other packets schedulers which account packets in
> > this way. Which one is better? I am not sure. And in this patch,
> > qstats.drops isn't maintained in the same way. Would these two be
> > consistent.
>
> HTB uses this accounting.
Yes, but we should use generic helpers and avoid duplicating this kind
of magic here and here ;)
[PATCH] net_sched: factorize qdisc stats handling
HTB takes into account skb is segmented in stats updates.
Generalize this to all schedulers.
They should use qdisc_bstats_update() helper instead of manipulating
bstats.bytes and bstats.packets
Add bstats_update() helper too for classes that use
gnet_stats_basic_packed fields.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/net/sch_generic.h | 15 +++++++++++----
net/core/dev.c | 2 +-
net/sched/act_csum.c | 3 +--
net/sched/act_ipt.c | 3 +--
net/sched/act_mirred.c | 3 +--
net/sched/act_nat.c | 3 +--
net/sched/act_pedit.c | 3 +--
net/sched/act_police.c | 3 +--
net/sched/act_simple.c | 3 +--
net/sched/act_skbedit.c | 3 +--
net/sched/sch_atm.c | 6 ++----
net/sched/sch_cbq.c | 6 ++----
net/sched/sch_drr.c | 8 ++------
net/sched/sch_dsmark.c | 3 +--
net/sched/sch_hfsc.c | 6 ++----
net/sched/sch_htb.c | 17 ++++++-----------
net/sched/sch_ingress.c | 3 +--
net/sched/sch_multiq.c | 3 +--
net/sched/sch_netem.c | 6 ++----
net/sched/sch_prio.c | 3 +--
net/sched/sch_red.c | 3 +--
net/sched/sch_sfq.c | 3 +--
net/sched/sch_tbf.c | 3 +--
net/sched/sch_teql.c | 3 +--
24 files changed, 44 insertions(+), 70 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 0af57eb..389bbcb 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -426,10 +426,17 @@ static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch)
return qdisc_enqueue(skb, sch) & NET_XMIT_MASK;
}
-static inline void __qdisc_update_bstats(struct Qdisc *sch, unsigned int len)
+
+static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
+ struct sk_buff *skb)
+{
+ bstats->bytes += qdisc_pkt_len(skb);
+ bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
+}
+
+static inline void qdisc_bstats_update(struct Qdisc *sch, struct sk_buff *skb)
{
- sch->bstats.bytes += len;
- sch->bstats.packets++;
+ bstats_update(&sch->bstats, skb);
}
static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
@@ -437,7 +444,7 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
{
__skb_queue_tail(list, skb);
sch->qstats.backlog += qdisc_pkt_len(skb);
- __qdisc_update_bstats(sch, qdisc_pkt_len(skb));
+ qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index a215269..ab60f58 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2301,7 +2301,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
*/
if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
skb_dst_force(skb);
- __qdisc_update_bstats(q, skb->len);
+ qdisc_bstats_update(q, skb);
if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
if (unlikely(contended)) {
spin_unlock(&q->busylock);
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 67dc7ce..83ddfc0 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -508,8 +508,7 @@ static int tcf_csum(struct sk_buff *skb,
spin_lock(&p->tcf_lock);
p->tcf_tm.lastuse = jiffies;
- p->tcf_bstats.bytes += qdisc_pkt_len(skb);
- p->tcf_bstats.packets++;
+ bstats_update(&p->tcf_bstats, skb);
action = p->tcf_action;
update_flags = p->update_flags;
spin_unlock(&p->tcf_lock);
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 8daef96..c2a7c20 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -209,8 +209,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
spin_lock(&ipt->tcf_lock);
ipt->tcf_tm.lastuse = jiffies;
- ipt->tcf_bstats.bytes += qdisc_pkt_len(skb);
- ipt->tcf_bstats.packets++;
+ bstats_update(&ipt->tcf_bstats, skb);
/* yes, we have to worry about both in and out dev
worry later - danger - this API seems to have changed
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 0c311be..d765067 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -165,8 +165,7 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
spin_lock(&m->tcf_lock);
m->tcf_tm.lastuse = jiffies;
- m->tcf_bstats.bytes += qdisc_pkt_len(skb);
- m->tcf_bstats.packets++;
+ bstats_update(&m->tcf_bstats, skb);
dev = m->tcfm_dev;
if (!dev) {
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 186eb83..178a4bd 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -125,8 +125,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
egress = p->flags & TCA_NAT_FLAG_EGRESS;
action = p->tcf_action;
- p->tcf_bstats.bytes += qdisc_pkt_len(skb);
- p->tcf_bstats.packets++;
+ bstats_update(&p->tcf_bstats, skb);
spin_unlock(&p->tcf_lock);
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index a0593c9..445bef7 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -187,8 +187,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
bad:
p->tcf_qstats.overlimits++;
done:
- p->tcf_bstats.bytes += qdisc_pkt_len(skb);
- p->tcf_bstats.packets++;
+ bstats_update(&p->tcf_bstats, skb);
spin_unlock(&p->tcf_lock);
return p->tcf_action;
}
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 7ebf743..e2f08b1 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -298,8 +298,7 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
spin_lock(&police->tcf_lock);
- police->tcf_bstats.bytes += qdisc_pkt_len(skb);
- police->tcf_bstats.packets++;
+ bstats_update(&police->tcf_bstats, skb);
if (police->tcfp_ewma_rate &&
police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 97e84f3..7287cff 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -42,8 +42,7 @@ static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result
spin_lock(&d->tcf_lock);
d->tcf_tm.lastuse = jiffies;
- d->tcf_bstats.bytes += qdisc_pkt_len(skb);
- d->tcf_bstats.packets++;
+ bstats_update(&d->tcf_bstats, skb);
/* print policy string followed by _ then packet count
* Example if this was the 3rd packet and the string was "hello"
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 66cbf4e..836f5fe 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -46,8 +46,7 @@ static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a,
spin_lock(&d->tcf_lock);
d->tcf_tm.lastuse = jiffies;
- d->tcf_bstats.bytes += qdisc_pkt_len(skb);
- d->tcf_bstats.packets++;
+ bstats_update(&d->tcf_bstats, skb);
if (d->flags & SKBEDIT_F_PRIORITY)
skb->priority = d->priority;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 2825407..943d733 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -422,10 +422,8 @@ drop: __maybe_unused
}
return ret;
}
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
- flow->bstats.bytes += qdisc_pkt_len(skb);
- flow->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
+ bstats_update(&flow->bstats, skb);
/*
* Okay, this may seem weird. We pretend we've dropped the packet if
* it goes via ATM. The reason for this is that the outer qdisc
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index eb76315..c80d1c2 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -390,8 +390,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, cl->q);
if (ret == NET_XMIT_SUCCESS) {
sch->q.qlen++;
- sch->bstats.packets++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
+ qdisc_bstats_update(sch, skb);
cbq_mark_toplevel(q, cl);
if (!cl->next_alive)
cbq_activate_class(cl);
@@ -650,8 +649,7 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
ret = qdisc_enqueue(skb, cl->q);
if (ret == NET_XMIT_SUCCESS) {
sch->q.qlen++;
- sch->bstats.packets++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
+ qdisc_bstats_update(sch, skb);
if (!cl->next_alive)
cbq_activate_class(cl);
return 0;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index aa8b531..de55e64 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -351,7 +351,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct drr_sched *q = qdisc_priv(sch);
struct drr_class *cl;
- unsigned int len;
int err;
cl = drr_classify(skb, sch, &err);
@@ -362,7 +361,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return err;
}
- len = qdisc_pkt_len(skb);
err = qdisc_enqueue(skb, cl->qdisc);
if (unlikely(err != NET_XMIT_SUCCESS)) {
if (net_xmit_drop_count(err)) {
@@ -377,10 +375,8 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
cl->deficit = cl->quantum;
}
- cl->bstats.packets++;
- cl->bstats.bytes += len;
- sch->bstats.packets++;
- sch->bstats.bytes += len;
+ bstats_update(&cl->bstats, skb);
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return err;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 1d295d6..60f4bdd 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -260,8 +260,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return err;
}
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 069c62b..2e45791 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1599,10 +1599,8 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (cl->qdisc->q.qlen == 1)
set_active(cl, qdisc_pkt_len(skb));
- cl->bstats.packets++;
- cl->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
+ bstats_update(&cl->bstats, skb);
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 01b519d..984c1b0 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -569,15 +569,12 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
}
return ret;
} else {
- cl->bstats.packets +=
- skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
- cl->bstats.bytes += qdisc_pkt_len(skb);
+ bstats_update(&cl->bstats, skb);
htb_activate(q, cl);
}
sch->q.qlen++;
- sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
- sch->bstats.bytes += qdisc_pkt_len(skb);
+ qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
@@ -648,12 +645,10 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
htb_add_to_wait_tree(q, cl, diff);
}
- /* update byte stats except for leaves which are already updated */
- if (cl->level) {
- cl->bstats.bytes += bytes;
- cl->bstats.packets += skb_is_gso(skb)?
- skb_shinfo(skb)->gso_segs:1;
- }
+ /* update basic stats except for leaves which are already updated */
+ if (cl->level)
+ bstats_update(&cl->bstats, skb);
+
cl = cl->parent;
}
}
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index f10e34a..bce1665 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -63,8 +63,7 @@ static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch)
result = tc_classify(skb, p->filter_list, &res);
- sch->bstats.packets++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
+ qdisc_bstats_update(sch, skb);
switch (result) {
case TC_ACT_SHOT:
result = TC_ACT_SHOT;
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 32690de..21f13da 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -83,8 +83,7 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, qdisc);
if (ret == NET_XMIT_SUCCESS) {
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
}
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index e5593c0..1c4bce8 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -240,8 +240,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if (likely(ret == NET_XMIT_SUCCESS)) {
sch->q.qlen++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
} else if (net_xmit_drop_count(ret)) {
sch->qstats.drops++;
}
@@ -477,8 +476,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
__skb_queue_after(list, skb, nskb);
sch->qstats.backlog += qdisc_pkt_len(nskb);
- sch->bstats.bytes += qdisc_pkt_len(nskb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, nskb);
return NET_XMIT_SUCCESS;
}
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index b1c95bc..966158d 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -84,8 +84,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
ret = qdisc_enqueue(skb, qdisc);
if (ret == NET_XMIT_SUCCESS) {
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
return NET_XMIT_SUCCESS;
}
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index a67ba3c..a6009c5 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -94,8 +94,7 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
ret = qdisc_enqueue(skb, child);
if (likely(ret == NET_XMIT_SUCCESS)) {
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
sch->q.qlen++;
} else if (net_xmit_drop_count(ret)) {
q->stats.pdrop++;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index d54ac94..239ec53 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -403,8 +403,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
slot->allot = q->scaled_quantum;
}
if (++sch->q.qlen <= q->limit) {
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 641a30d..77565e7 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -134,8 +134,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
}
sch->q.qlen++;
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 106479a..af9360d 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -83,8 +83,7 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
if (q->q.qlen < dev->tx_queue_len) {
__skb_queue_tail(&q->q, skb);
- sch->bstats.bytes += qdisc_pkt_len(skb);
- sch->bstats.packets++;
+ qdisc_bstats_update(sch, skb);
return NET_XMIT_SUCCESS;
}
^ permalink raw reply related
* Re: [PATCH net-next-2.6 v3 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Wolfgang Grandegger @ 2011-01-08 9:09 UTC (permalink / raw)
To: Bhupesh Sharma
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1294135195-9448-1-git-send-email-bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
Hi Bhupesh,
the patch already looks quite good. Just a few more issues...
On 01/04/2011 10:59 AM, Bhupesh Sharma wrote:
> Bosch C_CAN controller is a full-CAN implementation which is compliant
> to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can be
> obtained from:
> http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf
>
> This patch adds the support for this controller.
> The following are the design choices made while writing the controller
> driver:
> 1. Interface Register set IF1 has be used only in the current design.
> 2. Out of the 32 Message objects available, 16 are kept aside for RX
> purposes and the rest for TX purposes.
> 3. NAPI implementation is such that both the TX and RX paths function
> in polling mode.
>
> Changes since V2:
> 1. Seperately implemented a bus independent interface "c_can.c" and
> a bus sensitive driver "c_can_platform.c". The bus sensitive driver
> essentially caters to the details of registers mapping/arch differences
> found on different SoCs.
> 2. Changed RX poll method to allow *in-order packet reception*.
> 3. Implemeneted LEC (last error code) as an enum.
> 4. Implemented CAN_CTRLMODE_BERR_REPORTING.
> 5. Corrected "quota" handling in RX poll routine.
> 6. Implemented and used priv->can.do_get_berr_counter.
> 7. Improved timeout-handling while programming IF command request
> register.
> 8. Corrected register offset typecasting to allow the same to work on
> 64-bit systems.
>
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
> ---
> drivers/net/can/Kconfig | 2 +
> drivers/net/can/Makefile | 1 +
> drivers/net/can/c_can/Kconfig | 15 +
> drivers/net/can/c_can/Makefile | 8 +
> drivers/net/can/c_can/c_can.c | 960 ++++++++++++++++++++++++++++++++
> drivers/net/can/c_can/c_can.h | 235 ++++++++
> drivers/net/can/c_can/c_can_platform.c | 210 +++++++
> 7 files changed, 1431 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/c_can/Kconfig
> create mode 100644 drivers/net/can/c_can/Makefile
> create mode 100644 drivers/net/can/c_can/c_can.c
> create mode 100644 drivers/net/can/c_can/c_can.h
> create mode 100644 drivers/net/can/c_can/c_can_platform.c
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 9d9e453..50549b5 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -86,6 +86,8 @@ source "drivers/net/can/mscan/Kconfig"
>
> source "drivers/net/can/sja1000/Kconfig"
>
> +source "drivers/net/can/c_can/Kconfig"
> +
> source "drivers/net/can/usb/Kconfig"
>
> config CAN_DEBUG_DEVICES
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 0057537..c3efeb3 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -11,6 +11,7 @@ obj-y += usb/
>
> obj-$(CONFIG_CAN_SJA1000) += sja1000/
> obj-$(CONFIG_CAN_MSCAN) += mscan/
> +obj-$(CONFIG_CAN_C_CAN) += c_can/
> obj-$(CONFIG_CAN_AT91) += at91_can.o
> obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
> obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
> diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
> new file mode 100644
> index 0000000..ffb9773
> --- /dev/null
> +++ b/drivers/net/can/c_can/Kconfig
> @@ -0,0 +1,15 @@
> +menuconfig CAN_C_CAN
> + tristate "Bosch C_CAN devices"
> + depends on CAN_DEV && HAS_IOMEM
> +
> +if CAN_C_CAN
> +
> +config CAN_C_CAN_PLATFORM
> + tristate "Generic Platform Bus based C_CAN driver"
> + ---help---
> + This driver adds support for the C_CAN chips connected to
> + the "platform bus" (Linux abstraction for directly to the
> + processor attached devices) which can be found on various
> + boards from ST Microelectronics (http://www.st.com)
> + like the SPEAr1310 and SPEAr320 evaluation boards.
> +endif
> diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
> new file mode 100644
> index 0000000..9273f6d
> --- /dev/null
> +++ b/drivers/net/can/c_can/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for the Bosch C_CAN controller drivers.
> +#
> +
> +obj-$(CONFIG_CAN_C_CAN) += c_can.o
> +obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
> +
> +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
> new file mode 100644
> index 0000000..206e650
> --- /dev/null
> +++ b/drivers/net/can/c_can/c_can.c
> @@ -0,0 +1,960 @@
> +/*
> + * CAN bus driver for Bosch C_CAN controller
> + *
> + * Copyright (C) 2010 ST Microelectronics
> + * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
> + *
> + * Borrowed heavily from the C_CAN driver originally written by:
> + * Copyright (C) 2007
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
> + *
> + * TX and RX NAPI implementation has been borrowed from at91 CAN driver
> + * written by:
> + * Copyright
> + * (C) 2007 by Hans J. Koch <hjk-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
> + * (C) 2008, 2009 by Marc Kleine-Budde <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + *
> + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
> + * Bosch C_CAN user manual can be obtained from:
> + * http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf
Unfortunately, this link is not valid any more.
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_arp.h>
> +#include <linux/if_ether.h>
> +#include <linux/list.h>
> +#include <linux/delay.h>
> +#include <linux/workqueue.h>
Do you need that include?
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
...and the upper two? They are related to platform code.
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#include "c_can.h"
> +
> +static struct can_bittiming_const c_can_bittiming_const = {
> + .name = KBUILD_MODNAME,
> + .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
> + .tseg1_max = 16,
> + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/
> + .brp_inc = 1,
> +};
> +
> +static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
> +{
> + return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
> + C_CAN_MSG_OBJ_TX_FIRST;
> +}
> +
> +static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
> +{
> + return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
> + C_CAN_MSG_OBJ_TX_FIRST;
> +}
> +
> +static u32 c_can_read_reg32(struct c_can_priv *priv, void *reg)
> +{
> + u32 val = priv->read_reg(priv, reg);
> + val |= ((u32) priv->read_reg(priv, reg + 2)) << 16;
> + return val;
> +}
> +
> +void c_can_enable_all_interrupts(struct c_can_priv *priv,
> + int enable)
> +{
> + unsigned int cntrl_save = priv->read_reg(priv,
> + &priv->reg_base->control);
> +
> + if (enable)
> + cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
> + else
> + cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
> +
> + priv->write_reg(priv, &priv->reg_base->control, cntrl_save);
> +}
> +EXPORT_SYMBOL_GPL(c_can_enable_all_interrupts);
Do you really need to export that function? More later.
> +
> +static inline void c_can_object_get(struct net_device *dev,
> + int iface, int objno, int mask)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> + int count = MIN_TIMEOUT_VALUE;
> +
> + /*
> + * As per specs, after writting the message object number in the
> + * IF command request register the transfer b/w interface
> + * register and message RAM must be complete in 6 CAN-CLK
> + * period.
> + */
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_mask,
> + IFX_WRITE_LOW_16BIT(mask));
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_reg,
> + IFX_WRITE_LOW_16BIT(objno + 1));
> +
> + while (count) {
> + if (!(priv->read_reg(priv,
> + &priv->reg_base->ifreg[iface].com_reg) &
> + IF_COMR_BUSY))
> + break;
Could be shortened to:
while (count && priv->read_reg(priv,
&priv->reg_base->ifreg[iface].com_reg) &
IF_COMR_BUSY)
> + count--;
> + udelay(1);
> + }
> +
> + if (!count)
> + dev_err(dev->dev.parent, "timed out in object get\n");
> +}
> +
> +static inline void c_can_object_put(struct net_device *dev,
> + int iface, int objno, int mask)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> + int count = MIN_TIMEOUT_VALUE;
> +
> + /*
> + * As per specs, after writting the message object number in the
> + * IF command request register the transfer b/w interface
> + * register and message RAM must be complete in 6 CAN-CLK
> + * period.
> + */
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_mask,
> + (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_reg,
> + IFX_WRITE_LOW_16BIT(objno + 1));
> +
> + while (count) {
> + if (!(priv->read_reg(priv,
> + &priv->reg_base->ifreg[iface].com_reg) &
> + IF_COMR_BUSY))
> + break;
Ditto. Also this is duplicated code. A (inline) function would make sense.
> +
> + count--;
> + udelay(1);
> + }
> +
> + if (!count)
> + dev_err(dev->dev.parent, "timed out in object put\n");
> +}
> +
> +int c_can_write_msg_object(struct net_device *dev,
> + int iface, struct can_frame *frame, int objno)
> +{
> + int i;
> + u16 flags = 0;
> + unsigned int id;
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + if (frame->can_id & CAN_EFF_FLAG) {
> + id = frame->can_id & CAN_EFF_MASK;
> + flags |= IF_ARB_MSGXTD;
> + } else
> + id = ((frame->can_id & CAN_SFF_MASK) << 18);
> +
> + if (!(frame->can_id & CAN_RTR_FLAG))
> + flags |= IF_ARB_TRANSMIT;
> +
> + flags |= IF_ARB_MSGVAL;
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1,
> + IFX_WRITE_LOW_16BIT(id));
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2, flags |
> + IFX_WRITE_HIGH_16BIT(id));
> +
> + for (i = 0; i < frame->can_dlc; i += 2) {
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].data[i / 2],
> + frame->data[i] | (frame->data[i + 1] << 8));
> + }
> +
> + return frame->can_dlc;
> +}
> +
> +static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
> + int iface, int ctrl_mask,
> + int obj)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl,
> + ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
> +
> + c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
> +
Please remove empty line above.
> +}
> +
> +static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
> + int iface,
> + int ctrl_mask)
> +{
> + int i;
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + for (i = 0; i < C_CAN_MSG_RX_LOW_LAST; i++) {
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl,
> + ctrl_mask & ~(IF_MCONT_MSGLST |
> + IF_MCONT_INTPND | IF_MCONT_NEWDAT));
> + c_can_object_put(dev, iface, i + 1, IF_COMM_CONTROL);
> + }
> +}
> +
> +static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
> + int iface, int ctrl_mask,
> + int obj)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl,
> + ctrl_mask & ~(IF_MCONT_MSGLST |
> + IF_MCONT_INTPND | IF_MCONT_NEWDAT));
> +
> + c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
Ditto.
> +}
> +
> +static void c_can_handle_lost_msg_obj(struct net_device *dev,
> + int iface, int objno)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct sk_buff *skb;
> + struct can_frame *frame;
> +
> + dev_err(dev->dev.parent, "msg lost in buffer %d\n", objno);
> +
> + c_can_object_get(dev, iface, objno, IF_COMM_ALL &
> + ~IF_COMM_TXRQST);
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl,
> + IF_MCONT_CLR_MSGLST);
> +
> + c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
> +
> + /* create an error msg */
> + skb = alloc_can_err_skb(dev, &frame);
> + if (unlikely(!skb))
> + return;
> +
> + frame->can_id |= CAN_ERR_CRTL;
> + frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> + stats->rx_errors++;
> + stats->rx_over_errors++;
> +
> + netif_receive_skb(skb);
> +}
> +
> +static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl,
> + int objno)
> +{
> + u16 flags, data;
> + int i;
> + unsigned int val;
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct sk_buff *skb;
> + struct can_frame *frame;
> +
> + skb = alloc_can_skb(dev, &frame);
> + if (!skb) {
> + stats->rx_dropped++;
> + return -ENOMEM;
> + }
> +
> + frame->can_dlc = get_can_dlc(ctrl & 0x0F);
> +
> + for (i = 0; i < frame->can_dlc; i += 2) {
> + data = priv->read_reg(priv,
> + &priv->reg_base->ifreg[iface].data[i / 2]);
> + frame->data[i] = data;
> + frame->data[i + 1] = data >> 8;
> + }
> +
> + flags = priv->read_reg(priv, &priv->reg_base->ifreg[iface].arb2);
> + val = priv->read_reg(priv, &priv->reg_base->ifreg[iface].arb1) |
> + (flags << 16);
> +
> + if (flags & IF_ARB_MSGXTD)
> + frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
> + else
> + frame->can_id = (val >> 18) & CAN_SFF_MASK;
> +
> + if (flags & IF_ARB_TRANSMIT)
> + frame->can_id |= CAN_RTR_FLAG;
> +
> + netif_receive_skb(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += frame->can_dlc;
> +
> + return 0;
> +}
> +
> +static void c_can_setup_receive_object(struct net_device *dev, int iface,
> + int objno, unsigned int mask,
> + unsigned int id, unsigned int mcont)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].mask1,
> + IFX_WRITE_LOW_16BIT(mask));
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].mask2,
> + IFX_WRITE_HIGH_16BIT(mask));
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1,
> + IFX_WRITE_LOW_16BIT(id));
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2,
> + (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl, mcont);
> + c_can_object_put(dev, iface, objno, IF_COMM_ALL &
> + ~IF_COMM_TXRQST);
Should fit on one line.
> +
> + dev_dbg(dev->dev.parent, "obj no:%d, msgval:0x%08x\n", objno,
> + c_can_read_reg32(priv, &priv->reg_base->msgval1));
Please remove empty line above.
> +}
> +
> +static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1, 0);
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2, 0);
> + priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl, 0);
> +
> + c_can_object_put(dev, iface, objno,
> + IF_COMM_ARB | IF_COMM_CONTROL);
> +
> + dev_dbg(dev->dev.parent, "obj no:%d, msgval:0x%08x\n", objno,
> + c_can_read_reg32(priv, &priv->reg_base->msgval1));
Ditto.
> +}
> +
> +static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
> + struct net_device *dev)
> +{
> + u32 val;
> + u32 msg_obj_no;
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct can_frame *frame = (struct can_frame *)skb->data;
> +
> + if (can_dropped_invalid_skb(dev, skb))
> + return NETDEV_TX_OK;
> +
> + msg_obj_no = get_tx_next_msg_obj(priv);
> +
> + /* prepare message object for transmission */
> + val = c_can_write_msg_object(dev, 0, frame, msg_obj_no);
> +
> + /* enable interrupt for this message object */
> + priv->write_reg(priv, &priv->reg_base->ifreg[0].msg_cntrl,
> + IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
> + (val & 0xf));
> + c_can_object_put(dev, 0, msg_obj_no, IF_COMM_ALL);
> +
> + can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
> +
> + priv->tx_next++;
> + if ((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
> + netif_stop_queue(dev);
> +
> + return NETDEV_TX_OK;
> +}
> +
> +static int c_can_set_bittiming(struct net_device *dev)
> +{
> + unsigned int reg_btr, reg_brpe, ctrl_save;
> + u8 brp, brpe, sjw, tseg1, tseg2;
> + u32 ten_bit_brp;
> + struct c_can_priv *priv = netdev_priv(dev);
> + const struct can_bittiming *bt = &priv->can.bittiming;
> +
> + /* c_can provides a 6-bit brp and 4-bit brpe fields */
> + ten_bit_brp = bt->brp - 1;
> + brp = ten_bit_brp & BTR_BRP_MASK;
> + brpe = ten_bit_brp >> 6;
> +
> + sjw = bt->sjw - 1;
> + tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
> + tseg2 = bt->phase_seg2 - 1;
> +
> + reg_btr = ((brp) | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
> + (tseg2 << BTR_TSEG2_SHIFT));
The outer brackets are not needed.
> + reg_brpe = brpe & BRP_EXT_BRPE_MASK;
> +
> + dev_info(dev->dev.parent,
> + "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
> +
> + ctrl_save = priv->read_reg(priv, &priv->reg_base->control);
> + priv->write_reg(priv, &priv->reg_base->control,
> + ctrl_save | CONTROL_CCE | CONTROL_INIT);
> + priv->write_reg(priv, &priv->reg_base->btr, reg_btr);
> + priv->write_reg(priv, &priv->reg_base->brp_ext, reg_brpe);
> + priv->write_reg(priv, &priv->reg_base->control, ctrl_save);
> +
> + return 0;
> +}
> +
> +/*
> + * Configure C_CAN message objects for Tx and Rx purposes:
> + * C_CAN provides a total of 32 message objects that can be configured
> + * either for Tx or Rx purposes. Here the first 16 message objects are used as
> + * a reception FIFO. The end of reception FIFO is signified by the EoB bit
> + * being SET. The remaining 16 message objects are kept aside for Tx purposes.
> + * See user guide document for further details on configuring message
> + * objects.
> + */
> +static void c_can_configure_msg_objects(struct net_device *dev)
> +{
> + int i;
> +
> + /* first invalidate all message objects */
> + for (i = 0; i <= C_CAN_NO_OF_OBJECTS; i++)
> + c_can_inval_msg_object(dev, 0, i);
> +
> + /* setup receive message objects */
> + for (i = C_CAN_MSG_OBJ_RX_FIRST + 1 ; i < C_CAN_MSG_OBJ_RX_LAST; i++)
> + c_can_setup_receive_object(dev, 0, i, 0, 0,
> + ((IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB));
Ditto.
> + c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
> + IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
> +}
> +
> +/*
> + * Configure C_CAN chip:
> + * - enable/disable auto-retransmission
> + * - set operating mode
> + * - configure message objects
> + */
> +static void c_can_chip_config(struct net_device *dev)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
> + /* disable automatic retransmission */
> + priv->write_reg(priv, &priv->reg_base->control,
> + CONTROL_DISABLE_AR);
> + else
> + /* enable automatic retransmission */
> + priv->write_reg(priv, &priv->reg_base->control,
> + CONTROL_ENABLE_AR);
> +
> + if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY &
> + CAN_CTRLMODE_LOOPBACK)) {
> + /* loopback + silent mode : useful for hot self-test */
> + priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
> + CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
Outer brackets are not needed.
> + priv->write_reg(priv, &priv->reg_base->test,
> + (TEST_LBACK | TEST_SILENT));
> + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
> + /* loopback mode : useful for self-test function */
> + priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
> + CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
Ditto.
> + priv->write_reg(priv, &priv->reg_base->test, TEST_LBACK);
> + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
> + /* silent mode : bus-monitoring mode */
> + priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
> + CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
Ditto.
> + priv->write_reg(priv, &priv->reg_base->test, TEST_SILENT);
> + } else
> + /* normal mode*/
> + priv->write_reg(priv, &priv->reg_base->control,
> + (CONTROL_EIE | CONTROL_SIE | CONTROL_IE));
Ditto.
> + /* configure message objects */
> + c_can_configure_msg_objects(dev);
> +}
> +
> +static void c_can_start(struct net_device *dev)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + /* enable status change, error and module interrupts */
> + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
> +
> + /* basic c_can configuration */
> + c_can_chip_config(dev);
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + /* reset tx helper pointers */
> + priv->tx_next = priv->tx_echo = 0;
> +}
> +
> +static void c_can_stop(struct net_device *dev)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + /* disable all interrupts */
> + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
> +
> + /* set the state as STOPPED */
> + priv->can.state = CAN_STATE_STOPPED;
> +}
> +
> +static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
> +{
> + switch (mode) {
> + case CAN_MODE_START:
> + c_can_start(dev);
> + netif_wake_queue(dev);
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int c_can_get_berr_counter(const struct net_device *dev,
> + struct can_berr_counter *bec)
> +{
> + unsigned int reg_err_counter;
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + reg_err_counter = priv->read_reg(priv, &priv->reg_base->error_counter);
> + bec->rxerr = ((reg_err_counter & ERR_COUNTER_REC_MASK) >>
> + ERR_COUNTER_REC_SHIFT);
You don't need the out brackets.
> + bec->txerr = (reg_err_counter & ERR_COUNTER_TEC_MASK);
Ditto.
> + return 0;
> +}
> +
> +/*
> + * theory of operation:
> + *
> + * priv->tx_echo holds the number of the oldest can_frame put for
> + * transmission into the hardware, but not yet ACKed by the CAN tx
> + * complete IRQ.
> + *
> + * We iterate from priv->tx_echo to priv->tx_next and check if the
> + * packet has been transmitted, echo it back to the CAN framework.
> + * If we discover a not yet transmitted package, stop looking for more.
> + */
> +static void c_can_do_tx(struct net_device *dev)
> +{
> + u32 val;
> + u32 msg_obj_no;
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> +
> + for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
> + msg_obj_no = get_tx_echo_msg_obj(priv);
> + c_can_inval_msg_object(dev, 0, msg_obj_no);
> + val = c_can_read_reg32(priv, &priv->reg_base->txrqst1);
> + if (!(val & (1 << msg_obj_no))) {
> + can_get_echo_skb(dev,
> + msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
> + stats->tx_bytes += priv->read_reg(priv,
> + &priv->reg_base->ifreg[0].msg_cntrl)
> + & IF_MCONT_DLC_MASK;
> + stats->tx_packets++;
> + }
> + }
> +
> + /* restart queue if wrap-up or if queue stalled on last pkt */
> + if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
> + ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
> + netif_wake_queue(dev);
> +}
> +
> +/*
> + * theory of operation:
> + *
> + * c_can core saves a received CAN message into the first free message
> + * object it finds free (starting with the lowest). Bits NEWDAT and
> + * INTPND are set for this message object indicating that a new message
> + * has arrived. To work-around this issue, we keep two groups of message
> + * objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
> + *
> + * To ensure in-order frame reception we use the following
> + * approach while re-activating a message object to receive further
> + * frames:
> + * - if the current message object number is lower than
> + * C_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
> + * the INTPND bit.
> + * - if the current message object number is equal to
> + * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
> + * receive message objects.
> + * - if the current message object number is greater than
> + * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
> + * only this message object.
> + */
> +static int c_can_do_rx_poll(struct net_device *dev, int quota)
> +{
> + u32 num_rx_pkts = 0;
> + unsigned int msg_obj, msg_ctrl_save;
> + struct c_can_priv *priv = netdev_priv(dev);
> + u32 val = c_can_read_reg32(priv, &priv->reg_base->intpnd1);
> +
> + for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
> + msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
> + msg_obj++) {
> + if (val & (1 << msg_obj)) {
> + c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
> + ~IF_COMM_TXRQST);
> + msg_ctrl_save = priv->read_reg(priv,
> + &priv->reg_base->ifreg[0].msg_cntrl);
> +
> + if (msg_ctrl_save & IF_MCONT_EOB)
> + return num_rx_pkts;
> +
> + if (msg_ctrl_save & IF_MCONT_MSGLST) {
> + c_can_handle_lost_msg_obj(dev, 0, msg_obj);
> + num_rx_pkts++;
> + quota--;
> + continue;
> + }
> +
> + if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
> + continue;
> +
> + /* read the data from the message object */
> + c_can_read_msg_object(dev, 0, msg_ctrl_save, msg_obj);
> +
> + if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
> + c_can_mark_rx_msg_obj(dev, 0,
> + msg_ctrl_save, msg_obj);
> + else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
> + /* activate this msg obj */
> + c_can_activate_rx_msg_obj(dev, 0,
> + msg_ctrl_save, msg_obj);
> + else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
> + /* activate all lower message objects */
> + c_can_activate_all_lower_rx_msg_obj(dev,
> + 0, msg_ctrl_save);
> +
> + num_rx_pkts++;
> + quota--;
> + }
> + val = c_can_read_reg32(priv, &priv->reg_base->intpnd1);
> + }
> +
> + return num_rx_pkts;
> +}
> +
> +static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
> +{
> + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
> + (priv->current_status & STATUS_LEC_MASK);
> +}
> +
> +static int c_can_err(struct net_device *dev,
> + enum c_can_bus_error_types error_type,
> + enum c_can_lec_type lec_type)
> +{
> + unsigned int reg_err_counter;
> + unsigned int rx_err_passive;
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + struct can_berr_counter bec;
> +
> + /* propogate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(dev, &cf);
> + if (unlikely(!skb))
> + return 0;
> +
> + c_can_get_berr_counter(dev, &bec);
> + reg_err_counter = priv->read_reg(priv, &priv->reg_base->error_counter);
> + rx_err_passive = ((reg_err_counter & ERR_COUNTER_RP_MASK) >>
> + ERR_COUNTER_RP_SHIFT);
Outer brackset?
> + if (error_type & C_CAN_ERROR_WARNING) {
> + /* error warning state */
> + priv->can.can_stats.error_warning++;
> + priv->can.state = CAN_STATE_ERROR_WARNING;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (bec.rxerr > 96)
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + if (bec.txerr > 96)
> + cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
> + }
> + if (error_type & C_CAN_ERROR_PASSIVE) {
> + /* error passive state */
> + priv->can.can_stats.error_passive++;
> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (rx_err_passive)
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + if (bec.txerr > 127)
> + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> + }
> + if (error_type & C_CAN_BUS_OFF) {
> + /* bus-off state */
> + priv->can.state = CAN_STATE_BUS_OFF;
> + cf->can_id |= CAN_ERR_BUSOFF;
> + /* disable all interrupts in bus-off mode to ensure that
> + * the CPU is not hogged down
> + */
Please use the following style:
/*
* Comment
*/
> + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
> + can_bus_off(dev);
> + }
> +
> + /*
> + * check for 'last error code' which tells us the
> + * type of the last error to occur on the CAN bus
> + */
> + switch (lec_type) {
> + /* common for all type of bus errors */
> + priv->can.can_stats.bus_error++;
> + stats->rx_errors++;
> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> + cf->data[2] |= CAN_ERR_PROT_UNSPEC;
Are you sure that this part is ever executed? I wonder why the compile does
not complain.
> + case LEC_STUFF_ERROR:
> + dev_dbg(dev->dev.parent, "stuff error\n");
> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> + break;
> +
> + case LEC_FORM_ERROR:
> + dev_dbg(dev->dev.parent, "form error\n");
> + cf->data[2] |= CAN_ERR_PROT_FORM;
> + break;
> +
> + case LEC_ACK_ERROR:
> + dev_dbg(dev->dev.parent, "ack error\n");
> + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
> + CAN_ERR_PROT_LOC_ACK_DEL);
> + break;
> +
> + case LEC_BIT1_ERROR:
> + dev_dbg(dev->dev.parent, "bit1 error\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> + break;
> +
> + case LEC_BIT0_ERROR:
> + dev_dbg(dev->dev.parent, "bit0 error\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> + break;
> +
> + case LEC_CRC_ERROR:
> + dev_dbg(dev->dev.parent, "CRC error\n");
> + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> + CAN_ERR_PROT_LOC_CRC_DEL);
> + break;
> + }
> +
> + netif_receive_skb(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +
> + return 1;
> +}
> +
> +static int c_can_poll(struct napi_struct *napi, int quota)
> +{
> + u16 irqstatus;
> + int lec_type = 0;
> + int work_done = 0;
> + struct net_device *dev = napi->dev;
> + struct c_can_priv *priv = netdev_priv(dev);
> + enum c_can_bus_error_types error_type = C_CAN_NO_ERROR;
> +
> + irqstatus = priv->read_reg(priv, &priv->reg_base->ir);
> +
> + /* status events have the highest priority */
> + if (irqstatus == STATUS_INTERRUPT) {
> + priv->current_status = priv->read_reg(priv,
> + &priv->reg_base->status);
> +
> + /* handle Tx/Rx events */
> + if (priv->current_status & STATUS_TXOK)
> + priv->write_reg(priv, &priv->reg_base->status,
> + (priv->current_status & ~STATUS_TXOK));
Outer bracket are not needed. Here and in similar expressions below.
> +
> + if (priv->current_status & STATUS_RXOK)
> + priv->write_reg(priv, &priv->reg_base->status,
> + (priv->current_status & ~STATUS_RXOK));
> +
> + /* handle bus error events */
> + if (priv->current_status & STATUS_EWARN) {
> + dev_dbg(dev->dev.parent,
> + "entered error warning state\n");
> + error_type = C_CAN_ERROR_WARNING;
> + }
> + if ((priv->current_status & STATUS_EPASS) &&
> + (!(priv->last_status & STATUS_EPASS))) {
> + dev_dbg(dev->dev.parent,
> + "entered error passive state\n");
> + error_type = C_CAN_ERROR_PASSIVE;
> + }
> + if ((priv->current_status & STATUS_BOFF) &&
> + (!(priv->last_status & STATUS_BOFF))) {
> + dev_dbg(dev->dev.parent,
> + "entered bus off state\n");
> + error_type = C_CAN_BUS_OFF;
> + }
> +
> + /* handle bus recovery events */
> + if ((!(priv->current_status & STATUS_EPASS)) &&
> + (priv->last_status & STATUS_EPASS)) {
> + dev_dbg(dev->dev.parent,
> + "left error passive state\n");
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> + if ((!(priv->current_status & STATUS_BOFF)) &&
> + (priv->last_status & STATUS_BOFF)) {
> + dev_dbg(dev->dev.parent,
> + "left bus off state\n");
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> +
> + priv->last_status = priv->current_status;
> +
> + /* handle error on the bus */
> + lec_type = c_can_has_and_handle_berr(priv);
> + if (lec_type && (error_type != C_CAN_NO_ERROR))
> + work_done += c_can_err(dev, error_type, lec_type);
> + } else if ((irqstatus > C_CAN_MSG_OBJ_RX_FIRST) &&
> + (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
> + /* handle events corresponding to receive message objects */
> + work_done += c_can_do_rx_poll(dev, (quota - work_done));
> + } else if ((irqstatus > C_CAN_MSG_OBJ_TX_FIRST) &&
> + (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
> + /* handle events corresponding to transmit message objects */
> + c_can_do_tx(dev);
> + }
> +
> + if (work_done < quota) {
> + napi_complete(napi);
> + /* enable all IRQs */
> + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
> + }
> +
> + return work_done;
> +}
> +
> +static irqreturn_t c_can_isr(int irq, void *dev_id)
> +{
> + struct net_device *dev = (struct net_device *)dev_id;
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + /* disable all interrupts and schedule the NAPI */
> + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
> + napi_schedule(&priv->napi);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int c_can_open(struct net_device *dev)
> +{
> + int err;
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + /* open the can device */
> + err = open_candev(dev);
> + if (err) {
> + dev_err(dev->dev.parent, "failed to open can device\n");
> + return err;
> + }
> +
> + /* register interrupt handler */
> + err = request_irq(dev->irq, &c_can_isr, priv->irq_flags, dev->name,
> + dev);
> + if (err < 0) {
> + dev_err(dev->dev.parent, "failed to attach interrupt\n");
s/attach/request/ ?
> + goto exit_irq_fail;
> + }
> +
> + /* start the c_can controller */
> + c_can_start(dev);
> +
> + napi_enable(&priv->napi);
> + netif_start_queue(dev);
> +
> + return 0;
> +
> +exit_irq_fail:
> + close_candev(dev);
> + return err;
> +}
> +
> +static int c_can_close(struct net_device *dev)
> +{
> + struct c_can_priv *priv = netdev_priv(dev);
> +
> + netif_stop_queue(dev);
> + napi_disable(&priv->napi);
> + c_can_stop(dev);
> + free_irq(dev->irq, dev);
> + close_candev(dev);
> +
> + return 0;
> +}
> +
> +struct net_device *alloc_c_can_dev(void)
> +{
> + struct net_device *dev;
> + struct c_can_priv *priv;
> +
> + dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
> + if (!dev)
> + return NULL;
> +
> + priv = netdev_priv(dev);
> + netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
> +
> + priv->dev = dev;
> + priv->can.bittiming_const = &c_can_bittiming_const;
> + priv->can.do_set_bittiming = c_can_set_bittiming;
> + priv->can.do_set_mode = c_can_set_mode;
> + priv->can.do_get_berr_counter = c_can_get_berr_counter;
> + priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT |
> + CAN_CTRLMODE_LOOPBACK |
> + CAN_CTRLMODE_LISTENONLY |
> + CAN_CTRLMODE_BERR_REPORTING;
> +
> + return dev;
> +}
> +EXPORT_SYMBOL_GPL(alloc_c_can_dev);
> +
> +void free_c_can_dev(struct net_device *dev)
> +{
> + free_candev(dev);
> +}
> +EXPORT_SYMBOL_GPL(free_c_can_dev);
> +
> +static const struct net_device_ops c_can_netdev_ops = {
> + .ndo_open = c_can_open,
> + .ndo_stop = c_can_close,
> + .ndo_start_xmit = c_can_start_xmit,
> +};
> +
> +int register_c_can_dev(struct net_device *dev)
> +{
> + dev->flags |= IFF_ECHO; /* we support local echo */
> + dev->netdev_ops = &c_can_netdev_ops;
> +
> + return register_candev(dev);
> +}
> +EXPORT_SYMBOL_GPL(register_c_can_dev);
> +
> +void unregister_c_can_dev(struct net_device *dev)
> +{
> + unregister_candev(dev);
> +}
> +EXPORT_SYMBOL_GPL(unregister_c_can_dev);
> +
> +MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
> diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
> new file mode 100644
> index 0000000..fafc5e6
> --- /dev/null
> +++ b/drivers/net/can/c_can/c_can.h
> @@ -0,0 +1,235 @@
> +/*
> + * CAN bus driver for Bosch C_CAN controller
> + *
> + * Copyright (C) 2010 ST Microelectronics
> + * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
> + *
> + * Borrowed heavily from the C_CAN driver originally written by:
> + * Copyright (C) 2007
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
> + *
> + * TX and RX NAPI implementation has been borrowed from at91 CAN driver
> + * written by:
> + * Copyright
> + * (C) 2007 by Hans J. Koch <hjk-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
> + * (C) 2008, 2009 by Marc Kleine-Budde <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + *
> + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
> + * Bosch C_CAN user manual can be obtained from:
> + * http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef C_CAN_H
> +#define C_CAN_H
> +
> +/* control register */
> +#define CONTROL_TEST BIT(7)
> +#define CONTROL_CCE BIT(6)
> +#define CONTROL_DISABLE_AR BIT(5)
> +#define CONTROL_ENABLE_AR (0 << 5)
> +#define CONTROL_EIE BIT(3)
> +#define CONTROL_SIE BIT(2)
> +#define CONTROL_IE BIT(1)
> +#define CONTROL_INIT BIT(0)
> +
> +/* test register */
> +#define TEST_RX BIT(7)
> +#define TEST_TX1 BIT(6)
> +#define TEST_TX2 BIT(5)
> +#define TEST_LBACK BIT(4)
> +#define TEST_SILENT BIT(3)
> +#define TEST_BASIC BIT(2)
> +
> +/* status register */
> +#define STATUS_BOFF BIT(7)
> +#define STATUS_EWARN BIT(6)
> +#define STATUS_EPASS BIT(5)
> +#define STATUS_RXOK BIT(4)
> +#define STATUS_TXOK BIT(3)
> +#define STATUS_LEC_MASK 0x07
> +
> +/* error counter register */
> +#define ERR_COUNTER_TEC_MASK 0xff
> +#define ERR_COUNTER_TEC_SHIFT 0
> +#define ERR_COUNTER_REC_SHIFT 8
> +#define ERR_COUNTER_REC_MASK (0x7f << ERR_COUNTER_REC_SHIFT)
> +#define ERR_COUNTER_RP_SHIFT 15
> +#define ERR_COUNTER_RP_MASK (0x1 << ERR_COUNTER_RP_SHIFT)
> +
> +/* bit-timing register */
> +#define BTR_BRP_MASK 0x3f
> +#define BTR_BRP_SHIFT 0
> +#define BTR_SJW_SHIFT 6
> +#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT)
> +#define BTR_TSEG1_SHIFT 8
> +#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT)
> +#define BTR_TSEG2_SHIFT 12
> +#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
> +
> +/* brp extension register */
> +#define BRP_EXT_BRPE_MASK 0x0f
> +#define BRP_EXT_BRPE_SHIFT 0
> +
> +/* IFx command request */
> +#define IF_COMR_BUSY BIT(15)
> +
> +/* IFx command mask */
> +#define IF_COMM_WR BIT(7)
> +#define IF_COMM_MASK BIT(6)
> +#define IF_COMM_ARB BIT(5)
> +#define IF_COMM_CONTROL BIT(4)
> +#define IF_COMM_CLR_INT_PND BIT(3)
> +#define IF_COMM_TXRQST BIT(2)
> +#define IF_COMM_DATAA BIT(1)
> +#define IF_COMM_DATAB BIT(0)
> +#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
> + IF_COMM_CONTROL | IF_COMM_TXRQST | \
> + IF_COMM_DATAA | IF_COMM_DATAB)
> +
> +/* IFx arbitration */
> +#define IF_ARB_MSGVAL BIT(15)
> +#define IF_ARB_MSGXTD BIT(14)
> +#define IF_ARB_TRANSMIT BIT(13)
> +
> +/* IFx message control */
> +#define IF_MCONT_NEWDAT BIT(15)
> +#define IF_MCONT_MSGLST BIT(14)
> +#define IF_MCONT_CLR_MSGLST (0 << 14)
> +#define IF_MCONT_INTPND BIT(13)
> +#define IF_MCONT_UMASK BIT(12)
> +#define IF_MCONT_TXIE BIT(11)
> +#define IF_MCONT_RXIE BIT(10)
> +#define IF_MCONT_RMTEN BIT(9)
> +#define IF_MCONT_TXRQST BIT(8)
> +#define IF_MCONT_EOB BIT(7)
> +#define IF_MCONT_DLC_MASK 0xf
> +
> +/*
> + * IFx register masks:
> + * allow easy operation on 16-bit registers when the
> + * argument is 32-bit instead
> + */
> +#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
> +#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
> +
> +/* message object split */
> +#define C_CAN_NO_OF_OBJECTS 31
> +#define C_CAN_MSG_OBJ_RX_NUM 16
> +#define C_CAN_MSG_OBJ_TX_NUM 16
> +
> +#define C_CAN_MSG_OBJ_RX_FIRST 0
> +#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
> + C_CAN_MSG_OBJ_RX_NUM - 1)
> +
> +#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
> +#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
> + C_CAN_MSG_OBJ_TX_NUM - 1)
> +
> +#define C_CAN_MSG_OBJ_RX_SPLIT 8
> +#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
> +
> +#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
> +#define RECEIVE_OBJECT_BITS 0x0000ffff
> +
> +/* status interrupt */
> +#define STATUS_INTERRUPT 0x8000
> +
> +/* global interrupt masks */
> +#define ENABLE_ALL_INTERRUPTS 1
> +#define DISABLE_ALL_INTERRUPTS 0
> +
> +/* minimum timeout for checking BUSY status */
> +#define MIN_TIMEOUT_VALUE 6
> +
> +/* napi related */
> +#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
> +
> +/* c_can IF registers */
> +struct c_can_if_regs {
> + u16 com_reg;
> + u16 com_mask;
> + u16 mask1;
> + u16 mask2;
> + u16 arb1;
> + u16 arb2;
> + u16 msg_cntrl;
> + u16 data[4];
> + u16 _reserved[13];
> +};
> +
> +/* c_can hardware registers */
> +struct c_can_regs {
> + u16 control;
> + u16 status;
> + u16 error_counter;
> + u16 btr;
> + u16 ir;
> + u16 test;
> + u16 brp_ext;
> + u16 _reserved1;
> + struct c_can_if_regs ifreg[2]; /* [0] = IF1 and [1] = IF2 */
Why not just "if" instead of "ifreg"? That would also nicely shorten
many log expressions.
> + u16 _reserved2[8];
> + u16 txrqst1;
> + u16 txrqst2;
> + u16 _reserved3[6];
> + u16 newdat1;
> + u16 newdat2;
> + u16 _reserved4[6];
> + u16 intpnd1;
> + u16 intpnd2;
> + u16 _reserved5[6];
> + u16 msgval1;
> + u16 msgval2;
> + u16 _reserved6[6];
> +};
Above you use both, rather long and heavily abbreviated names, e.g.
"error_counter" vs. "ir". Something in between would be nice.
> +/* c_can lec values */
> +enum c_can_lec_type {
> + LEC_STUFF_ERROR = 1,
> + LEC_FORM_ERROR,
> + LEC_ACK_ERROR,
> + LEC_BIT1_ERROR,
> + LEC_BIT0_ERROR,
> + LEC_CRC_ERROR,
> +};
> +
> +/*
> + * c_can error types:
> + * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
> + */
> +enum c_can_bus_error_types {
> + C_CAN_NO_ERROR = 0,
> + C_CAN_BUS_OFF,
> + C_CAN_ERROR_WARNING,
> + C_CAN_ERROR_PASSIVE,
> +};
> +
> +/* c_can private data structure */
> +struct c_can_priv {
> + struct can_priv can; /* must be the first member */
> + struct napi_struct napi;
> + struct net_device *dev;
> + int tx_object;
> + int current_status;
> + int last_status;
> + u16 (*read_reg) (struct c_can_priv *priv, void *reg);
> + void (*write_reg) (struct c_can_priv *priv, void *reg, u16 val);
> + struct c_can_regs __iomem *reg_base;
s/reg_base/regs/ seems more logical to me. reg_base sounds like a "void *"
member.
> + unsigned long irq_flags; /* for request_irq() */
> + unsigned int tx_next;
> + unsigned int tx_echo;
> + struct clk *clk;
clk is a platform specific variable, e.g. a PCI based drive will not need it.
Therefore a member "priv" would make sense. Also it would nicely shorten
many log expressions.
> +};
> +
> +void c_can_enable_all_interrupts(struct c_can_priv *priv, int enable);
> +struct net_device *alloc_c_can_dev(void);
> +void free_c_can_dev(struct net_device *dev);
> +int register_c_can_dev(struct net_device *dev);
> +void unregister_c_can_dev(struct net_device *dev);
> +
> +#endif /* C_CAN_H */
> diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
> new file mode 100644
> index 0000000..482a57e
> --- /dev/null
> +++ b/drivers/net/can/c_can/c_can_platform.c
> @@ -0,0 +1,210 @@
> +/*
> + * Platform CAN bus driver for Bosch C_CAN controller
> + *
> + * Copyright (C) 2010 ST Microelectronics
> + * Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>
> + *
> + * Borrowed heavily from the C_CAN driver originally written by:
> + * Copyright (C) 2007
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + * - Simon Kallweit, intefo AG <simon.kallweit-+G9qxTFKJT/tRgLqZ5aouw@public.gmane.org>
> + *
> + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
> + * Bosch C_CAN user manual can be obtained from:
> + * http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_arp.h>
> +#include <linux/if_ether.h>
> +#include <linux/list.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +
> +#include <linux/can/dev.h>
> +
> +#include "c_can.h"
> +
> +/*
> + * 16-bit c_can registers can be arranged differently in the memory
> + * architecture of different implementations. For example: 16-bit
> + * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
> + * Handle the same by providing a common read/write interface.
> + */
> +static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
> + void *reg)
> +{
> + return readw(reg);
> +}
> +
> +static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
> + void *reg, u16 val)
> +{
> + writew(val, reg);
> +}
> +
> +static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
> + void *reg)
> +{
> + return readw(reg + (long)reg - (long)priv->reg_base);
> +}
> +
> +static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
> + void *reg, u16 val)
> +{
> + writew(val, reg + (long)reg - (long)priv->reg_base);
> +}
> +
> +static int __devinit c_can_plat_probe(struct platform_device *pdev)
> +{
> + int ret;
> + void __iomem *addr;
> + struct net_device *dev;
> + struct c_can_priv *priv;
> + struct resource *mem, *irq;
> + struct clk *clk;
> +
> + /* get the appropriate clk */
> + clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(clk)) {
> + dev_err(&pdev->dev, "no clock defined\n");
> + ret = -ENODEV;
> + goto exit;
> + }
> +
> + /* get the platform data */
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!mem || (irq <= 0)) {
> + ret = -ENODEV;
> + goto exit_free_clk;
> + }
> +
> + if (!request_mem_region(mem->start, resource_size(mem),
> + KBUILD_MODNAME)) {
> + dev_err(&pdev->dev, "resource unavailable\n");
> + ret = -ENODEV;
> + goto exit_free_clk;
> + }
> +
> + addr = ioremap(mem->start, resource_size(mem));
> + if (!addr) {
> + dev_err(&pdev->dev, "failed to map can port\n");
> + ret = -ENOMEM;
> + goto exit_release_mem;
> + }
> +
> + /* allocate the c_can device */
> + dev = alloc_c_can_dev();
> + if (!dev) {
> + ret = -ENOMEM;
> + goto exit_iounmap;
> + }
> +
> + priv = netdev_priv(dev);
> +
> + dev->irq = irq->start;
> + priv->irq_flags = irq->flags;
> + priv->reg_base = addr;
> + priv->can.clock.freq = clk_get_rate(clk);
> + priv->clk = clk;
> +
> + switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
> + case IORESOURCE_MEM_32BIT:
> + priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
> + priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
> + break;
> + case IORESOURCE_MEM_16BIT:
> + default:
> + priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
> + priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
> + break;
> + }
> +
> + platform_set_drvdata(pdev, dev);
> + SET_NETDEV_DEV(dev, &pdev->dev);
> +
> + ret = register_c_can_dev(dev);
> + if (ret) {
> + dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
> + KBUILD_MODNAME, ret);
> + goto exit_free_device;
> + }
> +
> + dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
> + KBUILD_MODNAME, priv->reg_base, dev->irq);
> + return 0;
> +
> +exit_free_device:
> + platform_set_drvdata(pdev, NULL);
> + free_c_can_dev(dev);
> +exit_iounmap:
> + iounmap(addr);
> +exit_release_mem:
> + release_mem_region(mem->start, resource_size(mem));
> +exit_free_clk:
> + clk_put(clk);
> +exit:
> + dev_err(&pdev->dev, "probe failed\n");
> +
> + return ret;
> +}
> +
> +static int __devexit c_can_plat_remove(struct platform_device *pdev)
> +{
> + struct net_device *dev = platform_get_drvdata(pdev);
> + struct c_can_priv *priv = netdev_priv(dev);
> + struct resource *mem;
> +
> + /* disable all interrupts */
> + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
To avoid exportign that function, couldn't it be done at the beginning of
unregister_c_can_dev()?
> +
> + unregister_c_can_dev(dev);
> + platform_set_drvdata(pdev, NULL);
> +
> + free_c_can_dev(dev);
> + iounmap(priv->reg_base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + release_mem_region(mem->start, resource_size(mem));
> +
> + clk_put(priv->clk);
> +
> + return 0;
> +}
> +
> +static struct platform_driver c_can_plat_driver = {
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .owner = THIS_MODULE,
> + },
> + .probe = c_can_plat_probe,
> + .remove = __devexit_p(c_can_plat_remove),
> +};
> +
> +static int __init c_can_plat_init(void)
> +{
> + return platform_driver_register(&c_can_plat_driver);
> +}
> +module_init(c_can_plat_init);
> +
> +static void __exit c_can_plat_exit(void)
> +{
> + platform_driver_unregister(&c_can_plat_driver);
> +}
> +module_exit(c_can_plat_exit);
> +
> +MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma-qxv4g6HH51o@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
Thanks for your contribution.
Wolfgang.
^ permalink raw reply
* [RFC v3 PATCH] m68knommu: added dm9000 support
From: Angelo Dureghello @ 2011-01-08 9:08 UTC (permalink / raw)
To: linux-kernel, netdev, linux-m68k
This patch allows to use the dm9000 network chip with a m68knommu
big-endian cpu. From the data bus circuit-wiring point of view,
the cpu data bus connected to the dm9000 chip should be hardware-byte-swapped,
crossing the bytes wires (D0:7 to D24:31, etc.).
In anyway, has been also added an option to swap the bytes in the driver,
if some cpu has been wired straight D0:D31 to dm9000.
Signed-off-by: Angelo Dureghello <angelo70@gmail.com>
---
--- linux/drivers/net/Kconfig.orig 2011-01-05 17:11:37.992376124 +0100
+++ linux/drivers/net/Kconfig 2011-01-08 09:53:48.231300064 +0100
@@ -960,7 +960,7 @@ config TI_DAVINCI_EMAC
config DM9000
tristate "DM9000 support"
- depends on ARM || BLACKFIN || MIPS
+ depends on COLDFIRE || ARM || BLACKFIN || MIPS
select CRC32
select MII
---help---
@@ -986,6 +986,14 @@ config DM9000_FORCE_SIMPLE_PHY_POLL
costly MII PHY reads. Note, this will not work if the chip is
operating with an external PHY.
+config DM9000_32BIT_SW_SWAP
+ bool "Software byte swap for 32 bit data bus"
+ depends on DM9000 && COLDFIRE
+ ---help---
+ This configuration allows to swap data bytes from the dm9000
+ driver itself, when the big endian cpu is wired straight to
+ the dm9000 32 bit data bus.
+
config ENC28J60
tristate "ENC28J60 support"
depends on EXPERIMENTAL && SPI && NET_ETHERNET
--- linux/drivers/net/dm9000.c.orig 2010-12-30 23:19:39.747836070 +0100
+++ linux/drivers/net/dm9000.c 2011-01-08 09:54:28.543551323 +0100
@@ -158,9 +158,17 @@ dm9000_reset(board_info_t * db)
dev_dbg(db->dev, "resetting device\n");
/* RESET device */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(DM9000_NCR, db->io_addr);
+#else
writeb(DM9000_NCR, db->io_addr);
+#endif
udelay(200);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(NCR_RST, db->io_data);
+#else
writeb(NCR_RST, db->io_data);
+#endif
udelay(200);
}
@@ -170,8 +178,13 @@ dm9000_reset(board_info_t * db)
static u8
ior(board_info_t * db, int reg)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg, db->io_addr);
+ return (u8)readl(db->io_data);
+#else
writeb(reg, db->io_addr);
return readb(db->io_data);
+#endif
}
/*
@@ -181,43 +194,72 @@ ior(board_info_t * db, int reg)
static void
iow(board_info_t * db, int reg, int value)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg, db->io_addr);
+ writel(value, db->io_data);
+#else
writeb(reg, db->io_addr);
writeb(value, db->io_data);
+#endif
}
/* routines for sending block to chip */
static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writesbsw(reg, data, count);
+#else
writesb(reg, data, count);
+#endif
}
static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writeswsw(reg, data, (count+1) >> 1);
+#else
writesw(reg, data, (count+1) >> 1);
+#endif
}
static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writeslsw(reg, data, (count+3) >> 2);
+#else
writesl(reg, data, (count+3) >> 2);
+#endif
}
/* input block from chip to memory */
static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ readsbsw(reg, data, count);
+#else
readsb(reg, data, count);
+#endif
}
static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ readswsw(reg, data, (count+1) >> 1);
+#else
readsw(reg, data, (count+1) >> 1);
+#endif
}
static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count)
{
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ readslsw(reg, data, (count+3) >> 2);
+#else
readsl(reg, data, (count+3) >> 2);
+#endif
}
/* dump block from chip to null */
@@ -863,8 +905,12 @@ static void dm9000_timeout(struct net_de
netif_wake_queue(dev);
/* Restore previous register address */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg_save, db->io_addr);
+#else
writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock, flags);
+#endif
+ spin_unlock_irqrestore(&db->lock,flags);
}
static void dm9000_send_packet(struct net_device *dev,
@@ -908,7 +954,11 @@ dm9000_start_xmit(struct sk_buff *skb, s
spin_lock_irqsave(&db->lock, flags);
/* Move data to DM9000 TX RAM */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(DM9000_MWCMD, db->io_addr);
+#else
writeb(DM9000_MWCMD, db->io_addr);
+#endif
(db->outblk)(db->io_data, skb->data, skb->len);
dev->stats.tx_bytes += skb->len;
@@ -981,7 +1031,11 @@ dm9000_rx(struct net_device *dev)
ior(db, DM9000_MRCMDX); /* Dummy read */
/* Get most updated data */
- rxbyte = readb(db->io_data);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ rxbyte = (u8)readl(db->io_data);
+#else
+ rxbyte = readb(db->io_data);
+#endif
/* Status check: this byte must be 0 or 1 */
if (rxbyte & DM9000_PKT_ERR) {
@@ -996,7 +1050,12 @@ dm9000_rx(struct net_device *dev)
/* A packet ready now & Get status/length */
GoodPacket = true;
+
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(DM9000_MRCMD, db->io_addr);
+#else
writeb(DM9000_MRCMD, db->io_addr);
+#endif
(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
@@ -1085,7 +1144,11 @@ static irqreturn_t dm9000_interrupt(int
spin_lock_irqsave(&db->lock, flags);
/* Save previous register address */
- reg_save = readb(db->io_addr);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ reg_save = (u8)readl(db->io_addr);
+#else
+ reg_save = readb(db->io_addr);
+#endif
/* Disable all interrupts */
iow(db, DM9000_IMR, IMR_PAR);
@@ -1116,7 +1179,11 @@ static irqreturn_t dm9000_interrupt(int
iow(db, DM9000_IMR, db->imr_all);
/* Restore previous register address */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg_save, db->io_addr);
+#else
writeb(reg_save, db->io_addr);
+#endif
spin_unlock_irqrestore(&db->lock, flags);
@@ -1237,7 +1304,11 @@ dm9000_phy_read(struct net_device *dev,
spin_lock_irqsave(&db->lock,flags);
/* Save previous register address */
- reg_save = readb(db->io_addr);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ reg_save = (u8)readl(db->io_addr);
+#else
+ reg_save = readb(db->io_addr);
+#endif
/* Fill the phyxcer register into REG_0C */
iow(db, DM9000_EPAR, DM9000_PHY | reg);
@@ -1250,7 +1321,11 @@ dm9000_phy_read(struct net_device *dev,
dm9000_msleep(db, 1); /* Wait read complete */
spin_lock_irqsave(&db->lock,flags);
- reg_save = readb(db->io_addr);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ reg_save = (u8)readl(db->io_addr);
+#else
+ reg_save = readb(db->io_addr);
+#endif
iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
@@ -1258,7 +1333,11 @@ dm9000_phy_read(struct net_device *dev,
ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
/* restore the previous address */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg_save, db->io_addr);
+#else
writeb(reg_save, db->io_addr);
+#endif
spin_unlock_irqrestore(&db->lock,flags);
mutex_unlock(&db->addr_lock);
@@ -1284,7 +1363,11 @@ dm9000_phy_write(struct net_device *dev,
spin_lock_irqsave(&db->lock,flags);
/* Save previous register address */
- reg_save = readb(db->io_addr);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ reg_save = (u8)readl(db->io_addr);
+#else
+ reg_save = readb(db->io_addr);
+#endif
/* Fill the phyxcer register into REG_0C */
iow(db, DM9000_EPAR, DM9000_PHY | reg);
@@ -1295,18 +1378,30 @@ dm9000_phy_write(struct net_device *dev,
iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); /* Issue phyxcer write command */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg_save, db->io_addr);
+#else
writeb(reg_save, db->io_addr);
+#endif
spin_unlock_irqrestore(&db->lock, flags);
dm9000_msleep(db, 1); /* Wait write complete */
spin_lock_irqsave(&db->lock,flags);
- reg_save = readb(db->io_addr);
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ reg_save = (u8)readl(db->io_addr);
+#else
+ reg_save = readb(db->io_addr);
+#endif
iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */
/* restore the previous address */
+#ifdef CONFIG_DM9000_32BIT_SW_SWAP
+ writel(reg_save, db->io_addr);
+#else
writeb(reg_save, db->io_addr);
+#endif
spin_unlock_irqrestore(&db->lock, flags);
mutex_unlock(&db->addr_lock);
--- linux/arch/m68k/include/asm/io_no.h.orig 2011-01-08 09:53:16.835301417 +0100
+++ linux/arch/m68k/include/asm/io_no.h 2011-01-08 09:53:18.523299757 +0100
@@ -47,6 +47,90 @@ static inline unsigned int _swapl(volati
#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
+static inline void writesb (void __iomem *reg, void *data, int count)
+{
+ unsigned char *p = (unsigned char*) data;
+
+ while (count--) writeb(*p++, reg);
+}
+
+static inline void writesbsw (void __iomem *reg, void *data, int count)
+{
+ unsigned char *p = (unsigned char *) data;
+
+ while (count--) writel((int)(*p++), reg);
+}
+
+static inline void writesw (void __iomem *reg, void *data, int count)
+{
+ unsigned short *p = (unsigned short*) data;
+
+ while (count--) writew(*p++, reg);
+}
+
+static inline void writeswsw (void __iomem *reg, void *data, int count)
+{
+ unsigned short *p = (unsigned short *) data;
+
+ while (count--) writel((int)(_swapw(*p++)), reg);
+}
+
+static inline void writesl (void __iomem *reg, void *data, int count)
+{
+ unsigned long *p = (unsigned long*) data;
+
+ while (count--) writel(*p++, reg);
+}
+
+static inline void writeslsw (void __iomem *reg, void *data, int count)
+{
+ unsigned long *p = (unsigned long *) data;
+
+ while (count--) writel((int)(_swapl(*p++)), reg);
+}
+
+static inline void readsb (void __iomem *reg, void *data, int count)
+{
+ unsigned char *p = (unsigned char *) data;
+
+ while (count--) *p++ = readb(reg);
+}
+
+static inline void readsbsw (void __iomem *reg, void *data, int count)
+{
+ unsigned char *p = (unsigned char *) data;
+
+ while (count--) *p++ = (unsigned char)readl(reg);
+}
+
+static inline void readsw (void __iomem *reg, void *data, int count)
+{
+ unsigned short *p = (unsigned short *) data;
+
+ while (count--) *p++ = readb(reg);
+}
+
+static inline void readswsw (void __iomem *reg, void *data, int count)
+{
+ unsigned short *p = (unsigned short *) data;
+
+ while (count--) *p++ = _swapw((unsigned short)readw(reg));
+}
+
+static inline void readsl (void __iomem *reg, void *data, int count)
+{
+ unsigned long *p = (unsigned long *) data;
+
+ while (count--) *p++ = readb(reg);
+}
+
+static inline void readslsw (void __iomem *reg, void *data, int count)
+{
+ unsigned long *p = (unsigned long *) data;
+
+ while (count--) *p++ = _swapl(readl(reg));
+}
+
#define __raw_readb readb
#define __raw_readw readw
#define __raw_readl readl
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox