netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 1/1 V4] net: Add Aeroflex Gaisler 10/100/1G Ethernet MAC driver
From: Stephen Hemminger @ 2010-01-25 16:31 UTC (permalink / raw)
  To: Kristoffer Glembo; +Cc: netdev, davem, Kristoffer Glembo
In-Reply-To: <1264417272-3800-2-git-send-email-kristoffer@gaisler.com>

On Mon, 25 Jan 2010 12:01:12 +0100
Kristoffer Glembo <kristoffer@gaisler.com> wrote:

> +/* Accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
> +static int macaddr[6];
> +module_param_array(macaddr, int, NULL, 0);
> +MODULE_PARM_DESC(macaddr, "GRETH Ethernet MAC address");

Don't you want an array of uchar here not int?

-- 

^ permalink raw reply

* Re: [PATCH] tcp_probe: avoid modulus operation and wrap fix
From: Stephen Hemminger @ 2010-01-25 16:30 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20100124.224122.13742906.davem@davemloft.net>

On Sun, 24 Jan 2010 22:41:22 -0800 (PST)
David Miller <davem@davemloft.net> wrote:

> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Sun, 24 Jan 2010 21:50:01 -0800
> 
> > @@ -75,12 +75,12 @@ static struct {
> >  
> >  static inline int tcp_probe_used(void)
> >  {
> > -	return (tcp_probe.head - tcp_probe.tail) % bufsize;
> > +	return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
> >  }
> >  
> >  static inline int tcp_probe_avail(void)
> >  {
> > -	return bufsize - tcp_probe_used();
> > +	return bufsize - tcp_probe_used() - 1;
> >  }
> >  
> >  /*
> 
> Hmmm...  When the ring is full head==tail, which means
> tcp_probe_used() returns 0.  Which would now make tcp_probe_avail()
> return "bufsize - 0 - 1".
> 
> Is that right?

Yes. in this ring; empty is head == tail, and full needs to
be tail == head - 1.

-- 

^ permalink raw reply

* [PATCH] qlge: Only free resources if they were allocated
From: leitao @ 2010-01-25 16:17 UTC (permalink / raw)
  To: ron.mercer; +Cc: netdev, Breno Leitao

Currently qlge tries to release regions even if they were not allocated.
This causes messages like the following in the kernel log

Trying to free nonexistent resource <00000000006af400-00000000006af4ff>
Trying to free nonexistent resource <00003c04ff9f4000-00003c04ff9f7fff>
Trying to free nonexistent resource <00003c04ffc00000-00003c04ffcfffff>

This patch fixes the goto logic in order to not release the resources
if they were not allocated.

Signed-off-by: Breno Leitao <leitao@linux.vnet.ibm.com>
---
 drivers/net/qlge/qlge_main.c |   15 ++++++++-------
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 707b391..894a7c8 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4119,7 +4119,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	err = pcie_set_readrq(pdev, 4096);
 	if (err) {
 		dev_err(&pdev->dev, "Set readrq failed.\n");
-		goto err_out;
+		goto err_out1;
 	}
 
 	err = pci_request_regions(pdev, DRV_NAME);
@@ -4140,7 +4140,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 
 	if (err) {
 		dev_err(&pdev->dev, "No usable DMA configuration.\n");
-		goto err_out;
+		goto err_out2;
 	}
 
 	/* Set PCIe reset type for EEH to fundamental. */
@@ -4152,7 +4152,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	if (!qdev->reg_base) {
 		dev_err(&pdev->dev, "Register mapping failed.\n");
 		err = -ENOMEM;
-		goto err_out;
+		goto err_out2;
 	}
 
 	qdev->doorbell_area_size = pci_resource_len(pdev, 3);
@@ -4162,14 +4162,14 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	if (!qdev->doorbell_area) {
 		dev_err(&pdev->dev, "Doorbell register mapping failed.\n");
 		err = -ENOMEM;
-		goto err_out;
+		goto err_out2;
 	}
 
 	err = ql_get_board_info(qdev);
 	if (err) {
 		dev_err(&pdev->dev, "Register access failed.\n");
 		err = -EIO;
-		goto err_out;
+		goto err_out2;
 	}
 	qdev->msg_enable = netif_msg_init(debug, default_msg);
 	spin_lock_init(&qdev->hw_lock);
@@ -4179,7 +4179,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	err = qdev->nic_ops->get_flash(qdev);
 	if (err) {
 		dev_err(&pdev->dev, "Invalid FLASH.\n");
-		goto err_out;
+		goto err_out2;
 	}
 
 	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
@@ -4212,8 +4212,9 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 			 DRV_NAME, DRV_VERSION);
 	}
 	return 0;
-err_out:
+err_out2:
 	ql_release_all(pdev);
+err_out1:
 	pci_disable_device(pdev);
 	return err;
 }
-- 
1.6.0.2


^ permalink raw reply related

* Re: [PATCH 8/8] percpu: add __percpu sparse annotations to what's left
From: Borislav Petkov @ 2010-01-25 15:54 UTC (permalink / raw)
  To: Tejun Heo
  Cc: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch, viro, davem, netdev, x86, mingo,
	fweisbec, dan.j.williams, ying.huang, lenb, neilb, cl
In-Reply-To: <1264432935-10453-9-git-send-email-tj@kernel.org>

On Tue, Jan 26, 2010 at 12:22:15AM +0900, Tejun Heo wrote:
> Add __percpu sparse annotations to places which didn't make it in one
> of the previous patches.  All converions are trivial.
> 
> These annotations are to make sparse consider percpu variables to be
> in a different address space and warn if accessed without going
> through percpu accessors.  This patch doesn't affect normal builds.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: Borislav Petkov <borislav.petkov@amd.com>
> Cc: Huang Ying <ying.huang@intel.com>
> Cc: Len Brown <lenb@kernel.org>
> Cc: Neil Brown <neilb@suse.de>
> ---
>  crypto/cryptd.c                  |    2 +-
>  drivers/acpi/processor_perflib.c |    2 +-
>  drivers/dma/dmaengine.c          |    2 +-
>  drivers/edac/amd64_edac.c        |    2 +-

For the edac bits:

Acked-by: Borislav Petkov <borislav.petkov@amd.com>

-- 
Regards/Gruss,
Boris.

--
Advanced Micro Devices, Inc.
Operating Systems Research Center

^ permalink raw reply

* Re: Bug#565404: linux-image-2.6.26-2-amd64: atl1e: TSO is broken
From: Anders Boström @ 2010-01-25 15:36 UTC (permalink / raw)
  To: Jie.Yang; +Cc: ben, netdev, 565404, Xiong.Huang
In-Reply-To: <CDAFEDABF718A54BABD0DA5476695307475CCD42@SHEXMB-01.global.atheros.com>

>>>>> "JY" == Jie Yang <Jie.Yang@Atheros.com> writes:

 JY> Anders Boström <anders@netinsight.net> wrote:
 >> Cc: ben@decadent.org.uk; netdev@vger.kernel.org;
 >> 565404@bugs.debian.org; Xiong Huang
 >> Subject: Re: Bug#565404: linux-image-2.6.26-2-amd64: atl1e:
 >> TSO is broken

 >> One strange observation is that I can only reproduce this
 >> problem when transmitting data from a NFS-server using TCP
 >> with Atheros AR8121/AR8113/AR8114.
 >> 
 >> I've tried to reproduce the problem using test-programs, like
 >> nttcp and netpipe, without any success. One observation is
 >> that the test-programs *only* generates 1500 bytes
 >> IP-packets. When the NFS-server sends data, a sequence of
 >> 1500 bytes IP-packets are generated, ending with a shorter
 >> packet. And this last packet in the sequence has 1500 in the
 >> IP-header length field, but is shorter.
 >> 
 JY> following is my test cese,

 JY> a nfs server server with ar8131chip, device id 1063. export /tmp/ dir as the nfs share directory,
 JY> the client, mount the server_ip:/tmp to local dir /mnt/nfs, ust a python script to write and read data on the
 JY> /mnt/nfs/testnfs.log. it works fine.

OK, the device-ID in our NFS-server is 1026, rev. b0. So it is
possible that the problem is specific to that chip/version.

 JY> Can you give me some advice on how to reproduce this bug??

The only suggestion I have is to try to find a board with a 1026-chip
on it.

My test-case is just copy of a 1 Gbyte file from the
NFS-server to /dev/null , after making sure that the file isn't cached
on the client by reading huge amounts of other data.

/ Anders

^ permalink raw reply

* Re: [PATCH 6/8] percpu: add __percpu sparse annotations to trace
From: Steven Rostedt @ 2010-01-25 15:35 UTC (permalink / raw)
  To: Tejun Heo
  Cc: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch, viro, davem, netdev, x86, mingo,
	fweisbec, dan.j.williams, borislav.petkov, ying.huang, lenb,
	neilb, cl
In-Reply-To: <1264432935-10453-7-git-send-email-tj@kernel.org>

On Tue, 2010-01-26 at 00:22 +0900, Tejun Heo wrote:
> Add __percpu sparse annotations to trace.
> 
> These annotations are to make sparse consider percpu variables to be
> in a different address space and warn if accessed without going
> through percpu accessors.  This patch doesn't affect normal builds.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>

Acked-by: Steven Rostedt <rostedt@goodmis.org>

-- Steve

> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> ---
>  include/linux/ftrace_event.h         |    4 ++--
>  include/trace/ftrace.h               |    4 ++--
>  kernel/trace/trace_event_profile.c   |   16 ++++++++--------
>  kernel/trace/trace_functions_graph.c |    2 +-
>  kernel/trace/trace_kprobe.c          |    4 ++--
>  kernel/trace/trace_ksym.c            |   10 +++++-----
>  kernel/trace/trace_syscalls.c        |    4 ++--
>  7 files changed, 22 insertions(+), 22 deletions(-)
> 



^ permalink raw reply

* [PATCH 3/8] percpu: add __percpu sparse annotations to net
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo, Patrick McHardy, Arnaldo Carvalho de Melo,
	Vlad Yasevich
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to net.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

The macro and type tricks around snmp stats make things a bit
interesting.  DEFINE/DECLARE_SNMP_STAT() macros mark the target field
as __percpu and SNMP_UPD_PO_STATS() macro is updated accordingly.  All
snmp_mib_*() users which used to cast the argument to (void **) are
updated to cast it to (void __percpu **).

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Vlad Yasevich <vladislav.yasevich@hp.com>
Cc: netdev@vger.kernel.org
---
 include/net/ip.h              |    6 ++--
 include/net/ipcomp.h          |    2 +-
 include/net/neighbour.h       |    2 +-
 include/net/netns/conntrack.h |    2 +-
 include/net/netns/core.h      |    2 +-
 include/net/route.h           |    2 +-
 include/net/snmp.h            |   12 +++++++---
 include/net/tcp.h             |    2 +-
 net/8021q/vlan.h              |    2 +-
 net/dccp/proto.c              |    5 ++-
 net/ipv4/af_inet.c            |   46 ++++++++++++++++++++--------------------
 net/ipv4/proc.c               |   28 ++++++++++++------------
 net/ipv4/route.c              |    2 +-
 net/ipv4/tcp.c                |   21 ++++++++++--------
 net/ipv6/addrconf.c           |   24 ++++++++++----------
 net/ipv6/af_inet6.c           |   28 ++++++++++++------------
 net/ipv6/proc.c               |   24 ++++++++++++---------
 net/sctp/proc.c               |    2 +-
 net/sctp/protocol.c           |    5 ++-
 net/xfrm/xfrm_ipcomp.c        |   16 +++++++-------
 net/xfrm/xfrm_policy.c        |    6 ++--
 net/xfrm/xfrm_proc.c          |    3 +-
 22 files changed, 128 insertions(+), 114 deletions(-)

diff --git a/include/net/ip.h b/include/net/ip.h
index fb63371..667a55b 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -174,9 +174,9 @@ extern struct ipv4_config ipv4_config;
 #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd)
 #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
 
-extern unsigned long snmp_fold_field(void *mib[], int offt);
-extern int snmp_mib_init(void *ptr[2], size_t mibsize);
-extern void snmp_mib_free(void *ptr[2]);
+extern unsigned long snmp_fold_field(void __percpu *mib[], int offt);
+extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize);
+extern void snmp_mib_free(void __percpu *ptr[2]);
 
 extern struct local_ports {
 	seqlock_t	lock;
diff --git a/include/net/ipcomp.h b/include/net/ipcomp.h
index 2a1092a..cc4f30c 100644
--- a/include/net/ipcomp.h
+++ b/include/net/ipcomp.h
@@ -9,7 +9,7 @@ struct crypto_comp;
 
 struct ipcomp_data {
 	u16 threshold;
-	struct crypto_comp **tfms;
+	struct crypto_comp * __percpu *tfms;
 };
 
 struct ip_comp_hdr;
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index b017320..daf935b 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -164,7 +164,7 @@ struct neigh_table {
 	rwlock_t		lock;
 	unsigned long		last_rand;
 	struct kmem_cache		*kmem_cachep;
-	struct neigh_statistics	*stats;
+	struct neigh_statistics	__percpu *stats;
 	struct neighbour	**hash_buckets;
 	unsigned int		hash_mask;
 	__u32			hash_rnd;
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index ba1ba0c..1531c07 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -15,7 +15,7 @@ struct netns_ct {
 	struct hlist_head	*expect_hash;
 	struct hlist_nulls_head	unconfirmed;
 	struct hlist_nulls_head	dying;
-	struct ip_conntrack_stat *stat;
+	struct ip_conntrack_stat __percpu *stat;
 	int			sysctl_events;
 	unsigned int		sysctl_events_retry_timeout;
 	int			sysctl_acct;
diff --git a/include/net/netns/core.h b/include/net/netns/core.h
index 24d4be7..78eb1ff 100644
--- a/include/net/netns/core.h
+++ b/include/net/netns/core.h
@@ -10,7 +10,7 @@ struct netns_core {
 
 	int	sysctl_somaxconn;
 
-	struct prot_inuse	*inuse;
+	struct prot_inuse __percpu *inuse;
 };
 
 #endif
diff --git a/include/net/route.h b/include/net/route.h
index bce6dd6..2c9fba7 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -101,7 +101,7 @@ struct rt_cache_stat {
         unsigned int out_hlist_search;
 };
 
-extern struct ip_rt_acct *ip_rt_acct;
+extern struct ip_rt_acct __percpu *ip_rt_acct;
 
 struct in_device;
 extern int		ip_rt_init(void);
diff --git a/include/net/snmp.h b/include/net/snmp.h
index f0d756f..d065976 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -129,9 +129,9 @@ struct linux_xfrm_mib {
  * nonlocked_atomic_inc() primitives -AK
  */ 
 #define DEFINE_SNMP_STAT(type, name)	\
-	__typeof__(type) *name[2]
+	__typeof__(type) __percpu *name[2]
 #define DECLARE_SNMP_STAT(type, name)	\
-	extern __typeof__(type) *name[2]
+	extern __typeof__(type) __percpu *name[2]
 
 #define SNMP_STAT_BHPTR(name)	(name[0])
 #define SNMP_STAT_USRPTR(name)	(name[1])
@@ -148,9 +148,13 @@ struct linux_xfrm_mib {
 			__this_cpu_add(mib[0]->mibs[field], addend)
 #define SNMP_ADD_STATS_USER(mib, field, addend)	\
 			this_cpu_add(mib[1]->mibs[field], addend)
+/*
+ * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr"
+ * to make @ptr a non-percpu pointer.
+ */
 #define SNMP_UPD_PO_STATS(mib, basefield, addend)	\
 	do { \
-		__typeof__(mib[0]) ptr; \
+		__typeof__(*mib[0]) *ptr; \
 		preempt_disable(); \
 		ptr = this_cpu_ptr((mib)[!in_softirq()]); \
 		ptr->mibs[basefield##PKTS]++; \
@@ -159,7 +163,7 @@ struct linux_xfrm_mib {
 	} while (0)
 #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)	\
 	do { \
-		__typeof__(mib[0]) ptr = \
+		__typeof__(*mib[0]) *ptr = \
 			__this_cpu_ptr((mib)[!in_softirq()]); \
 		ptr->mibs[basefield##PKTS]++; \
 		ptr->mibs[basefield##OCTETS] += addend;\
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 34f5cc2..0511317 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1193,7 +1193,7 @@ extern int			tcp_v4_md5_do_del(struct sock *sk,
 #define tcp_twsk_md5_key(twsk)	NULL
 #endif
 
-extern struct tcp_md5sig_pool	**tcp_alloc_md5sig_pool(struct sock *);
+extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *);
 extern void			tcp_free_md5sig_pool(void);
 
 extern struct tcp_md5sig_pool	*__tcp_get_md5sig_pool(int cpu);
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 5685296..6abdcac 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -61,7 +61,7 @@ struct vlan_dev_info {
 	struct proc_dir_entry			*dent;
 	unsigned long				cnt_inc_headroom_on_tx;
 	unsigned long				cnt_encap_on_xmit;
-	struct vlan_rx_stats			*vlan_rx_stats;
+	struct vlan_rx_stats __percpu		*vlan_rx_stats;
 };
 
 static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 671cd14..fb3b9f8 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1003,12 +1003,13 @@ EXPORT_SYMBOL_GPL(dccp_shutdown);
 
 static inline int dccp_mib_init(void)
 {
-	return snmp_mib_init((void**)dccp_statistics, sizeof(struct dccp_mib));
+	return snmp_mib_init((void __percpu **)dccp_statistics,
+			     sizeof(struct dccp_mib));
 }
 
 static inline void dccp_mib_exit(void)
 {
-	snmp_mib_free((void**)dccp_statistics);
+	snmp_mib_free((void __percpu **)dccp_statistics);
 }
 
 static int thash_entries;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 7d12c6a..33b7dff 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1385,7 +1385,7 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family,
 }
 EXPORT_SYMBOL_GPL(inet_ctl_sock_create);
 
-unsigned long snmp_fold_field(void *mib[], int offt)
+unsigned long snmp_fold_field(void __percpu *mib[], int offt)
 {
 	unsigned long res = 0;
 	int i;
@@ -1398,7 +1398,7 @@ unsigned long snmp_fold_field(void *mib[], int offt)
 }
 EXPORT_SYMBOL_GPL(snmp_fold_field);
 
-int snmp_mib_init(void *ptr[2], size_t mibsize)
+int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
 {
 	BUG_ON(ptr == NULL);
 	ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
@@ -1416,7 +1416,7 @@ err0:
 }
 EXPORT_SYMBOL_GPL(snmp_mib_init);
 
-void snmp_mib_free(void *ptr[2])
+void snmp_mib_free(void __percpu *ptr[2])
 {
 	BUG_ON(ptr == NULL);
 	free_percpu(ptr[0]);
@@ -1460,25 +1460,25 @@ static const struct net_protocol icmp_protocol = {
 
 static __net_init int ipv4_mib_init_net(struct net *net)
 {
-	if (snmp_mib_init((void **)net->mib.tcp_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
 			  sizeof(struct tcp_mib)) < 0)
 		goto err_tcp_mib;
-	if (snmp_mib_init((void **)net->mib.ip_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.ip_statistics,
 			  sizeof(struct ipstats_mib)) < 0)
 		goto err_ip_mib;
-	if (snmp_mib_init((void **)net->mib.net_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.net_statistics,
 			  sizeof(struct linux_mib)) < 0)
 		goto err_net_mib;
-	if (snmp_mib_init((void **)net->mib.udp_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.udp_statistics,
 			  sizeof(struct udp_mib)) < 0)
 		goto err_udp_mib;
-	if (snmp_mib_init((void **)net->mib.udplite_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics,
 			  sizeof(struct udp_mib)) < 0)
 		goto err_udplite_mib;
-	if (snmp_mib_init((void **)net->mib.icmp_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics,
 			  sizeof(struct icmp_mib)) < 0)
 		goto err_icmp_mib;
-	if (snmp_mib_init((void **)net->mib.icmpmsg_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
 			  sizeof(struct icmpmsg_mib)) < 0)
 		goto err_icmpmsg_mib;
 
@@ -1486,30 +1486,30 @@ static __net_init int ipv4_mib_init_net(struct net *net)
 	return 0;
 
 err_icmpmsg_mib:
-	snmp_mib_free((void **)net->mib.icmp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
 err_icmp_mib:
-	snmp_mib_free((void **)net->mib.udplite_statistics);
+	snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
 err_udplite_mib:
-	snmp_mib_free((void **)net->mib.udp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.udp_statistics);
 err_udp_mib:
-	snmp_mib_free((void **)net->mib.net_statistics);
+	snmp_mib_free((void __percpu **)net->mib.net_statistics);
 err_net_mib:
-	snmp_mib_free((void **)net->mib.ip_statistics);
+	snmp_mib_free((void __percpu **)net->mib.ip_statistics);
 err_ip_mib:
-	snmp_mib_free((void **)net->mib.tcp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.tcp_statistics);
 err_tcp_mib:
 	return -ENOMEM;
 }
 
 static __net_exit void ipv4_mib_exit_net(struct net *net)
 {
-	snmp_mib_free((void **)net->mib.icmpmsg_statistics);
-	snmp_mib_free((void **)net->mib.icmp_statistics);
-	snmp_mib_free((void **)net->mib.udplite_statistics);
-	snmp_mib_free((void **)net->mib.udp_statistics);
-	snmp_mib_free((void **)net->mib.net_statistics);
-	snmp_mib_free((void **)net->mib.ip_statistics);
-	snmp_mib_free((void **)net->mib.tcp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmpmsg_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
+	snmp_mib_free((void __percpu **)net->mib.udp_statistics);
+	snmp_mib_free((void __percpu **)net->mib.net_statistics);
+	snmp_mib_free((void __percpu **)net->mib.ip_statistics);
+	snmp_mib_free((void __percpu **)net->mib.tcp_statistics);
 }
 
 static __net_initdata struct pernet_operations ipv4_mib_ops = {
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index f25542c..1561eb6 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -280,7 +280,7 @@ static void icmpmsg_put(struct seq_file *seq)
 
 	count = 0;
 	for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
-		val = snmp_fold_field((void **) net->mib.icmpmsg_statistics, i);
+		val = snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics, i);
 		if (val) {
 			type[count] = i;
 			vals[count++] = val;
@@ -307,18 +307,18 @@ static void icmp_put(struct seq_file *seq)
 	for (i=0; icmpmibmap[i].name != NULL; i++)
 		seq_printf(seq, " Out%s", icmpmibmap[i].name);
 	seq_printf(seq, "\nIcmp: %lu %lu",
-		snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_INMSGS),
-		snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
+		snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INMSGS),
+		snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
 	for (i=0; icmpmibmap[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			snmp_fold_field((void **) net->mib.icmpmsg_statistics,
+			snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
 				icmpmibmap[i].index));
 	seq_printf(seq, " %lu %lu",
-		snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
-		snmp_fold_field((void **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS));
+		snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
+		snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS));
 	for (i=0; icmpmibmap[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			snmp_fold_field((void **) net->mib.icmpmsg_statistics,
+			snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
 				icmpmibmap[i].index | 0x100));
 }
 
@@ -341,7 +341,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 
 	for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)net->mib.ip_statistics,
+			   snmp_fold_field((void __percpu **)net->mib.ip_statistics,
 					   snmp4_ipstats_list[i].entry));
 
 	icmp_put(seq);	/* RFC 2011 compatibility */
@@ -356,11 +356,11 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 		/* MaxConn field is signed, RFC 2012 */
 		if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN)
 			seq_printf(seq, " %ld",
-				   snmp_fold_field((void **)net->mib.tcp_statistics,
+				   snmp_fold_field((void __percpu **)net->mib.tcp_statistics,
 						   snmp4_tcp_list[i].entry));
 		else
 			seq_printf(seq, " %lu",
-				   snmp_fold_field((void **)net->mib.tcp_statistics,
+				   snmp_fold_field((void __percpu **)net->mib.tcp_statistics,
 						   snmp4_tcp_list[i].entry));
 	}
 
@@ -371,7 +371,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 	seq_puts(seq, "\nUdp:");
 	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)net->mib.udp_statistics,
+			   snmp_fold_field((void __percpu **)net->mib.udp_statistics,
 					   snmp4_udp_list[i].entry));
 
 	/* the UDP and UDP-Lite MIBs are the same */
@@ -382,7 +382,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 	seq_puts(seq, "\nUdpLite:");
 	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)net->mib.udplite_statistics,
+			   snmp_fold_field((void __percpu **)net->mib.udplite_statistics,
 					   snmp4_udp_list[i].entry));
 
 	seq_putc(seq, '\n');
@@ -419,7 +419,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
 	seq_puts(seq, "\nTcpExt:");
 	for (i = 0; snmp4_net_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)net->mib.net_statistics,
+			   snmp_fold_field((void __percpu **)net->mib.net_statistics,
 					   snmp4_net_list[i].entry));
 
 	seq_puts(seq, "\nIpExt:");
@@ -429,7 +429,7 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
 	seq_puts(seq, "\nIpExt:");
 	for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   snmp_fold_field((void **)net->mib.ip_statistics,
+			   snmp_fold_field((void __percpu **)net->mib.ip_statistics,
 					   snmp4_ipextstats_list[i].entry));
 
 	seq_putc(seq, '\n');
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e446496..515d906 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3327,7 +3327,7 @@ static __net_initdata struct pernet_operations rt_secret_timer_ops = {
 
 
 #ifdef CONFIG_NET_CLS_ROUTE
-struct ip_rt_acct *ip_rt_acct __read_mostly;
+struct ip_rt_acct __percpu *ip_rt_acct __read_mostly;
 #endif /* CONFIG_NET_CLS_ROUTE */
 
 static __initdata unsigned long rhash_entries;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b0a26bb..bc04e66 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2788,10 +2788,10 @@ EXPORT_SYMBOL(tcp_gro_complete);
 
 #ifdef CONFIG_TCP_MD5SIG
 static unsigned long tcp_md5sig_users;
-static struct tcp_md5sig_pool **tcp_md5sig_pool;
+static struct tcp_md5sig_pool * __percpu *tcp_md5sig_pool;
 static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
 
-static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
+static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool * __percpu *pool)
 {
 	int cpu;
 	for_each_possible_cpu(cpu) {
@@ -2808,7 +2808,7 @@ static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
 
 void tcp_free_md5sig_pool(void)
 {
-	struct tcp_md5sig_pool **pool = NULL;
+	struct tcp_md5sig_pool * __percpu *pool = NULL;
 
 	spin_lock_bh(&tcp_md5sig_pool_lock);
 	if (--tcp_md5sig_users == 0) {
@@ -2822,10 +2822,11 @@ void tcp_free_md5sig_pool(void)
 
 EXPORT_SYMBOL(tcp_free_md5sig_pool);
 
-static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(struct sock *sk)
+static struct tcp_md5sig_pool * __percpu *
+__tcp_alloc_md5sig_pool(struct sock *sk)
 {
 	int cpu;
-	struct tcp_md5sig_pool **pool;
+	struct tcp_md5sig_pool * __percpu *pool;
 
 	pool = alloc_percpu(struct tcp_md5sig_pool *);
 	if (!pool)
@@ -2852,9 +2853,9 @@ out_free:
 	return NULL;
 }
 
-struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(struct sock *sk)
+struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *sk)
 {
-	struct tcp_md5sig_pool **pool;
+	struct tcp_md5sig_pool * __percpu *pool;
 	int alloc = 0;
 
 retry:
@@ -2873,7 +2874,9 @@ retry:
 
 	if (alloc) {
 		/* we cannot hold spinlock here because this may sleep. */
-		struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(sk);
+		struct tcp_md5sig_pool * __percpu *p;
+
+		p = __tcp_alloc_md5sig_pool(sk);
 		spin_lock_bh(&tcp_md5sig_pool_lock);
 		if (!p) {
 			tcp_md5sig_users--;
@@ -2897,7 +2900,7 @@ EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
 
 struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu)
 {
-	struct tcp_md5sig_pool **p;
+	struct tcp_md5sig_pool * __percpu *p;
 	spin_lock_bh(&tcp_md5sig_pool_lock);
 	p = tcp_md5sig_pool;
 	if (p)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index de7a194..1b5f2ed 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -278,31 +278,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
 
 static int snmp6_alloc_dev(struct inet6_dev *idev)
 {
-	if (snmp_mib_init((void **)idev->stats.ipv6,
+	if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
 			  sizeof(struct ipstats_mib)) < 0)
 		goto err_ip;
-	if (snmp_mib_init((void **)idev->stats.icmpv6,
+	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
 			  sizeof(struct icmpv6_mib)) < 0)
 		goto err_icmp;
-	if (snmp_mib_init((void **)idev->stats.icmpv6msg,
+	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
 			  sizeof(struct icmpv6msg_mib)) < 0)
 		goto err_icmpmsg;
 
 	return 0;
 
 err_icmpmsg:
-	snmp_mib_free((void **)idev->stats.icmpv6);
+	snmp_mib_free((void __percpu **)idev->stats.icmpv6);
 err_icmp:
-	snmp_mib_free((void **)idev->stats.ipv6);
+	snmp_mib_free((void __percpu **)idev->stats.ipv6);
 err_ip:
 	return -ENOMEM;
 }
 
 static void snmp6_free_dev(struct inet6_dev *idev)
 {
-	snmp_mib_free((void **)idev->stats.icmpv6msg);
-	snmp_mib_free((void **)idev->stats.icmpv6);
-	snmp_mib_free((void **)idev->stats.ipv6);
+	snmp_mib_free((void __percpu **)idev->stats.icmpv6msg);
+	snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+	snmp_mib_free((void __percpu **)idev->stats.ipv6);
 }
 
 /* Nobody refers to this device, we may destroy it. */
@@ -3752,8 +3752,8 @@ static inline size_t inet6_if_nlmsg_size(void)
 		 );
 }
 
-static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items,
-				      int bytes)
+static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
+				      int items, int bytes)
 {
 	int i;
 	int pad = bytes - sizeof(u64) * items;
@@ -3772,10 +3772,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
 {
 	switch(attrtype) {
 	case IFLA_INET6_STATS:
-		__snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
 		break;
 	case IFLA_INET6_ICMP6STATS:
-		__snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
 		break;
 	}
 }
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 12e69d3..36b42af 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -971,41 +971,41 @@ static void ipv6_packet_cleanup(void)
 
 static int __net_init ipv6_init_mibs(struct net *net)
 {
-	if (snmp_mib_init((void **)net->mib.udp_stats_in6,
+	if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6,
 			  sizeof (struct udp_mib)) < 0)
 		return -ENOMEM;
-	if (snmp_mib_init((void **)net->mib.udplite_stats_in6,
+	if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6,
 			  sizeof (struct udp_mib)) < 0)
 		goto err_udplite_mib;
-	if (snmp_mib_init((void **)net->mib.ipv6_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics,
 			  sizeof(struct ipstats_mib)) < 0)
 		goto err_ip_mib;
-	if (snmp_mib_init((void **)net->mib.icmpv6_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics,
 			  sizeof(struct icmpv6_mib)) < 0)
 		goto err_icmp_mib;
-	if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
 			  sizeof(struct icmpv6msg_mib)) < 0)
 		goto err_icmpmsg_mib;
 	return 0;
 
 err_icmpmsg_mib:
-	snmp_mib_free((void **)net->mib.icmpv6_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
 err_icmp_mib:
-	snmp_mib_free((void **)net->mib.ipv6_statistics);
+	snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
 err_ip_mib:
-	snmp_mib_free((void **)net->mib.udplite_stats_in6);
+	snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
 err_udplite_mib:
-	snmp_mib_free((void **)net->mib.udp_stats_in6);
+	snmp_mib_free((void __percpu **)net->mib.udp_stats_in6);
 	return -ENOMEM;
 }
 
 static void __net_exit ipv6_cleanup_mibs(struct net *net)
 {
-	snmp_mib_free((void **)net->mib.udp_stats_in6);
-	snmp_mib_free((void **)net->mib.udplite_stats_in6);
-	snmp_mib_free((void **)net->mib.ipv6_statistics);
-	snmp_mib_free((void **)net->mib.icmpv6_statistics);
-	snmp_mib_free((void **)net->mib.icmpv6msg_statistics);
+	snmp_mib_free((void __percpu **)net->mib.udp_stats_in6);
+	snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
+	snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
+	snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics);
 }
 
 static int __net_init inet6_net_init(struct net *net)
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index c9605c3..e3744d1 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -136,7 +136,7 @@ static struct snmp_mib snmp6_udplite6_list[] = {
 	SNMP_MIB_SENTINEL
 };
 
-static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib)
+static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib)
 {
 	char name[32];
 	int i;
@@ -171,7 +171,8 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib)
 }
 
 static inline void
-snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist)
+snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
+		    struct snmp_mib *itemlist)
 {
 	int i;
 	for (i=0; itemlist[i].name; i++)
@@ -183,14 +184,15 @@ static int snmp6_seq_show(struct seq_file *seq, void *v)
 {
 	struct net *net = (struct net *)seq->private;
 
-	snmp6_seq_show_item(seq, (void **)net->mib.ipv6_statistics,
+	snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics,
 			    snmp6_ipstats_list);
-	snmp6_seq_show_item(seq, (void **)net->mib.icmpv6_statistics,
+	snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
 			    snmp6_icmp6_list);
-	snmp6_seq_show_icmpv6msg(seq, (void **)net->mib.icmpv6msg_statistics);
-	snmp6_seq_show_item(seq, (void **)net->mib.udp_stats_in6,
+	snmp6_seq_show_icmpv6msg(seq,
+			    (void __percpu **)net->mib.icmpv6msg_statistics);
+	snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6,
 			    snmp6_udp6_list);
-	snmp6_seq_show_item(seq, (void **)net->mib.udplite_stats_in6,
+	snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6,
 			    snmp6_udplite6_list);
 	return 0;
 }
@@ -213,9 +215,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
 	struct inet6_dev *idev = (struct inet6_dev *)seq->private;
 
 	seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
-	snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list);
-	snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list);
-	snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg);
+	snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6,
+			    snmp6_ipstats_list);
+	snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6,
+			    snmp6_icmp6_list);
+	snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg);
 	return 0;
 }
 
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index d093cbf..e1e04c6 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -83,7 +83,7 @@ static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
 
 	for (i = 0; sctp_snmp_list[i].name != NULL; i++)
 		seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
-			   snmp_fold_field((void **)sctp_statistics,
+			   snmp_fold_field((void __percpu **)sctp_statistics,
 				      sctp_snmp_list[i].entry));
 
 	return 0;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index a3c8988..9687177 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -996,12 +996,13 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
 
 static inline int init_sctp_mibs(void)
 {
-	return snmp_mib_init((void**)sctp_statistics, sizeof(struct sctp_mib));
+	return snmp_mib_init((void __percpu **)sctp_statistics,
+			     sizeof(struct sctp_mib));
 }
 
 static inline void cleanup_sctp_mibs(void)
 {
-	snmp_mib_free((void**)sctp_statistics);
+	snmp_mib_free((void __percpu **)sctp_statistics);
 }
 
 static void sctp_v4_pf_init(void)
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index 42cd183..0fc5ff6 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -30,12 +30,12 @@
 
 struct ipcomp_tfms {
 	struct list_head list;
-	struct crypto_comp **tfms;
+	struct crypto_comp * __percpu *tfms;
 	int users;
 };
 
 static DEFINE_MUTEX(ipcomp_resource_mutex);
-static void **ipcomp_scratches;
+static void * __percpu *ipcomp_scratches;
 static int ipcomp_scratch_users;
 static LIST_HEAD(ipcomp_tfms_list);
 
@@ -200,7 +200,7 @@ EXPORT_SYMBOL_GPL(ipcomp_output);
 static void ipcomp_free_scratches(void)
 {
 	int i;
-	void **scratches;
+	void * __percpu *scratches;
 
 	if (--ipcomp_scratch_users)
 		return;
@@ -215,10 +215,10 @@ static void ipcomp_free_scratches(void)
 	free_percpu(scratches);
 }
 
-static void **ipcomp_alloc_scratches(void)
+static void * __percpu *ipcomp_alloc_scratches(void)
 {
 	int i;
-	void **scratches;
+	void * __percpu *scratches;
 
 	if (ipcomp_scratch_users++)
 		return ipcomp_scratches;
@@ -239,7 +239,7 @@ static void **ipcomp_alloc_scratches(void)
 	return scratches;
 }
 
-static void ipcomp_free_tfms(struct crypto_comp **tfms)
+static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms)
 {
 	struct ipcomp_tfms *pos;
 	int cpu;
@@ -267,10 +267,10 @@ static void ipcomp_free_tfms(struct crypto_comp **tfms)
 	free_percpu(tfms);
 }
 
-static struct crypto_comp **ipcomp_alloc_tfms(const char *alg_name)
+static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name)
 {
 	struct ipcomp_tfms *pos;
-	struct crypto_comp **tfms;
+	struct crypto_comp * __percpu *tfms;
 	int cpu;
 
 	/* This can be any valid CPU ID so we don't need locking. */
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 4725a54..a8c3ced 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2369,19 +2369,19 @@ static int __net_init xfrm_statistics_init(struct net *net)
 {
 	int rv;
 
-	if (snmp_mib_init((void **)net->mib.xfrm_statistics,
+	if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
 			  sizeof(struct linux_xfrm_mib)) < 0)
 		return -ENOMEM;
 	rv = xfrm_proc_init(net);
 	if (rv < 0)
-		snmp_mib_free((void **)net->mib.xfrm_statistics);
+		snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
 	return rv;
 }
 
 static void xfrm_statistics_fini(struct net *net)
 {
 	xfrm_proc_fini(net);
-	snmp_mib_free((void **)net->mib.xfrm_statistics);
+	snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
 }
 #else
 static int __net_init xfrm_statistics_init(struct net *net)
diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c
index fef8db5..54ad2a8 100644
--- a/net/xfrm/xfrm_proc.c
+++ b/net/xfrm/xfrm_proc.c
@@ -50,7 +50,8 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v)
 	int i;
 	for (i=0; xfrm_mib_list[i].name; i++)
 		seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name,
-			   snmp_fold_field((void **)net->mib.xfrm_statistics,
+			   snmp_fold_field((void __percpu **)
+					   net->mib.xfrm_statistics,
 					   xfrm_mib_list[i].entry));
 	return 0;
 }
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 7/8] percpu: add __percpu sparse annotations to hw_breakpoint
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to hw_breakpoint.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

per_cpu(nr_task_bp_pinned, cpu) is replaced with
&per_cpu(nr_task_bp_pinned[0], cpu).  This is the same to the compiler
but allows per_cpu() macro to correctly drop __percpu designation for
the returned pointer.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
---
 include/linux/hw_breakpoint.h           |    8 ++++----
 kernel/hw_breakpoint.c                  |   14 +++++++-------
 samples/hw_breakpoint/data_breakpoint.c |    6 +++---
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h
index 41235c9..f462d3d 100644
--- a/include/linux/hw_breakpoint.h
+++ b/include/linux/hw_breakpoint.h
@@ -66,14 +66,14 @@ register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
 				perf_overflow_handler_t	triggered,
 				int cpu);
 
-extern struct perf_event **
+extern struct perf_event * __percpu *
 register_wide_hw_breakpoint(struct perf_event_attr *attr,
 			    perf_overflow_handler_t triggered);
 
 extern int register_perf_hw_breakpoint(struct perf_event *bp);
 extern int __register_perf_hw_breakpoint(struct perf_event *bp);
 extern void unregister_hw_breakpoint(struct perf_event *bp);
-extern void unregister_wide_hw_breakpoint(struct perf_event **cpu_events);
+extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events);
 
 extern int reserve_bp_slot(struct perf_event *bp);
 extern void release_bp_slot(struct perf_event *bp);
@@ -98,7 +98,7 @@ static inline struct perf_event *
 register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
 				perf_overflow_handler_t	 triggered,
 				int cpu)		{ return NULL; }
-static inline struct perf_event **
+static inline struct perf_event * __percpu *
 register_wide_hw_breakpoint(struct perf_event_attr *attr,
 			    perf_overflow_handler_t triggered)	{ return NULL; }
 static inline int
@@ -107,7 +107,7 @@ static inline int
 __register_perf_hw_breakpoint(struct perf_event *bp) 	{ return -ENOSYS; }
 static inline void unregister_hw_breakpoint(struct perf_event *bp)	{ }
 static inline void
-unregister_wide_hw_breakpoint(struct perf_event **cpu_events)		{ }
+unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events)	{ }
 static inline int
 reserve_bp_slot(struct perf_event *bp)			{return -ENOSYS; }
 static inline void release_bp_slot(struct perf_event *bp) 		{ }
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index 50dbd59..11dae6d 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -74,7 +74,7 @@ static DEFINE_MUTEX(nr_bp_mutex);
 static unsigned int max_task_bp_pinned(int cpu)
 {
 	int i;
-	unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned, cpu);
+	unsigned int *tsk_pinned = &per_cpu(nr_task_bp_pinned[0], cpu);
 
 	for (i = HBP_NUM -1; i >= 0; i--) {
 		if (tsk_pinned[i] > 0)
@@ -163,7 +163,7 @@ static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable)
 
 	count = task_bp_pinned(tsk);
 
-	tsk_pinned = per_cpu(nr_task_bp_pinned, cpu);
+	tsk_pinned = &per_cpu(nr_task_bp_pinned[0], cpu);
 	if (enable) {
 		tsk_pinned[count]++;
 		if (count > 0)
@@ -377,17 +377,17 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
  *
  * @return a set of per_cpu pointers to perf events
  */
-struct perf_event **
+struct perf_event * __percpu *
 register_wide_hw_breakpoint(struct perf_event_attr *attr,
 			    perf_overflow_handler_t triggered)
 {
-	struct perf_event **cpu_events, **pevent, *bp;
+	struct perf_event * __percpu *cpu_events, **pevent, *bp;
 	long err;
 	int cpu;
 
 	cpu_events = alloc_percpu(typeof(*cpu_events));
 	if (!cpu_events)
-		return ERR_PTR(-ENOMEM);
+		return (void __percpu __force *)ERR_PTR(-ENOMEM);
 
 	get_online_cpus();
 	for_each_online_cpu(cpu) {
@@ -415,7 +415,7 @@ fail:
 	put_online_cpus();
 
 	free_percpu(cpu_events);
-	return ERR_PTR(err);
+	return (void __percpu __force *)ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
 
@@ -423,7 +423,7 @@ EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
  * unregister_wide_hw_breakpoint - unregister a wide breakpoint in the kernel
  * @cpu_events: the per cpu set of events to unregister
  */
-void unregister_wide_hw_breakpoint(struct perf_event **cpu_events)
+void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events)
 {
 	int cpu;
 	struct perf_event **pevent;
diff --git a/samples/hw_breakpoint/data_breakpoint.c b/samples/hw_breakpoint/data_breakpoint.c
index c69cbe9..bd0f337 100644
--- a/samples/hw_breakpoint/data_breakpoint.c
+++ b/samples/hw_breakpoint/data_breakpoint.c
@@ -34,7 +34,7 @@
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
 
-struct perf_event **sample_hbp;
+struct perf_event * __percpu *sample_hbp;
 
 static char ksym_name[KSYM_NAME_LEN] = "pid_max";
 module_param_string(ksym, ksym_name, KSYM_NAME_LEN, S_IRUGO);
@@ -61,8 +61,8 @@ static int __init hw_break_module_init(void)
 	attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
 
 	sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler);
-	if (IS_ERR(sample_hbp)) {
-		ret = PTR_ERR(sample_hbp);
+	if (IS_ERR((void __force *)sample_hbp)) {
+		ret = PTR_ERR((void __force *)sample_hbp);
 		goto fail;
 	}
 
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 8/8] percpu: add __percpu sparse annotations to what's left
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to places which didn't make it in one
of the previous patches.  All converions are trivial.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Borislav Petkov <borislav.petkov@amd.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Neil Brown <neilb@suse.de>
---
 crypto/cryptd.c                  |    2 +-
 drivers/acpi/processor_perflib.c |    2 +-
 drivers/dma/dmaengine.c          |    2 +-
 drivers/edac/amd64_edac.c        |    2 +-
 drivers/md/raid5.c               |    2 +-
 drivers/md/raid5.h               |    2 +-
 include/acpi/processor.h         |    2 +-
 include/linux/dmaengine.h        |    2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 704c141..ef71318 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -31,7 +31,7 @@ struct cryptd_cpu_queue {
 };
 
 struct cryptd_queue {
-	struct cryptd_cpu_queue *cpu_queue;
+	struct cryptd_cpu_queue __percpu *cpu_queue;
 };
 
 struct cryptd_instance_ctx {
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 2cabadc..8c6a649 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -557,7 +557,7 @@ end:
 }
 
 int acpi_processor_preregister_performance(
-		struct acpi_processor_performance *performance)
+		struct acpi_processor_performance __percpu *performance)
 {
 	int count, count_target;
 	int retval = 0;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6f51a0a..4eadd98 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -284,7 +284,7 @@ struct dma_chan_tbl_ent {
 /**
  * channel_table - percpu lookup table for memory-to-memory offload providers
  */
-static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END];
+static struct dma_chan_tbl_ent __percpu *channel_table[DMA_TX_TYPE_END];
 
 static int __init dma_channel_table_init(void)
 {
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 000dc67..7b36c88 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -13,7 +13,7 @@ module_param(report_gart_errors, int, 0644);
 static int ecc_enable_override;
 module_param(ecc_enable_override, int, 0644);
 
-static struct msr *msrs;
+static struct msr __percpu *msrs;
 
 /* Lookup table for all possible MC control instances */
 struct amd64_pvt;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e84204e..77cb3ab 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -4680,7 +4680,7 @@ static int raid5_alloc_percpu(raid5_conf_t *conf)
 {
 	unsigned long cpu;
 	struct page *spare_page;
-	struct raid5_percpu *allcpus;
+	struct raid5_percpu __percpu *allcpus;
 	void *scribble;
 	int err;
 
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index dd70835..0f86f5e 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -405,7 +405,7 @@ struct raid5_private_data {
 					      * lists and performing address
 					      * conversions
 					      */
-	} *percpu;
+	} __percpu *percpu;
 	size_t			scribble_len; /* size of scribble region must be
 					       * associated with conf to handle
 					       * cpu hotplug while reshaping
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 0ea5ef4..477544f 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -238,7 +238,7 @@ struct acpi_processor_errata {
 
 extern int acpi_processor_preregister_performance(struct
 						  acpi_processor_performance
-						  *performance);
+						  __percpu *performance);
 
 extern int acpi_processor_register_performance(struct acpi_processor_performance
 					       *performance, unsigned int cpu);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 7878498..21fd9b7 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -162,7 +162,7 @@ struct dma_chan {
 	struct dma_chan_dev *dev;
 
 	struct list_head device_node;
-	struct dma_chan_percpu *local;
+	struct dma_chan_percpu __percpu *local;
 	int client_count;
 	int table_count;
 	void *private;
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 6/8] percpu: add __percpu sparse annotations to trace
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo, Steven Rostedt
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to trace.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
---
 include/linux/ftrace_event.h         |    4 ++--
 include/trace/ftrace.h               |    4 ++--
 kernel/trace/trace_event_profile.c   |   16 ++++++++--------
 kernel/trace/trace_functions_graph.c |    2 +-
 kernel/trace/trace_kprobe.c          |    4 ++--
 kernel/trace/trace_ksym.c            |   10 +++++-----
 kernel/trace/trace_syscalls.c        |    4 ++--
 7 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 2233c98..72fccdd 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -138,8 +138,8 @@ struct ftrace_event_call {
 
 #define FTRACE_MAX_PROFILE_SIZE	2048
 
-extern char *perf_trace_buf;
-extern char *perf_trace_buf_nmi;
+extern char __percpu *perf_trace_buf;
+extern char __percpu *perf_trace_buf_nmi;
 
 #define MAX_FILTER_PRED		32
 #define MAX_FILTER_STR_VAL	256	/* Should handle KSYM_SYMBOL_LEN */
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index c6fe03e..210d421 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -773,7 +773,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {		\
  *	struct ftrace_event_call *event_call = &event_<call>;
  *	extern void perf_tp_event(int, u64, u64, void *, int);
  *	struct ftrace_raw_##call *entry;
- *	struct perf_trace_buf *trace_buf;
+ *	struct perf_trace_buf __percpu *trace_buf;
  *	u64 __addr = 0, __count = 1;
  *	unsigned long irq_flags;
  *	struct trace_entry *ent;
@@ -859,7 +859,7 @@ ftrace_profile_templ_##call(struct ftrace_event_call *event_call,	\
 	struct trace_entry *ent;					\
 	int __entry_size;						\
 	int __data_size;						\
-	char *trace_buf;						\
+	char __percpu *trace_buf;					\
 	char *raw_data;							\
 	int __cpu;							\
 	int rctx;							\
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c
index 9e25573..4b16312 100644
--- a/kernel/trace/trace_event_profile.c
+++ b/kernel/trace/trace_event_profile.c
@@ -9,11 +9,11 @@
 #include "trace.h"
 
 
-char *perf_trace_buf;
-EXPORT_SYMBOL_GPL(perf_trace_buf);
+char __percpu *perf_trace_buf;
+EXPORT_PER_CPU_SYMBOL_GPL(perf_trace_buf);
 
-char *perf_trace_buf_nmi;
-EXPORT_SYMBOL_GPL(perf_trace_buf_nmi);
+char __percpu *perf_trace_buf_nmi;
+EXPORT_PER_CPU_SYMBOL_GPL(perf_trace_buf_nmi);
 
 typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ;
 
@@ -22,20 +22,20 @@ static int	total_profile_count;
 
 static int ftrace_profile_enable_event(struct ftrace_event_call *event)
 {
-	char *buf;
+	char __percpu *buf;
 	int ret = -ENOMEM;
 
 	if (event->profile_count++ > 0)
 		return 0;
 
 	if (!total_profile_count) {
-		buf = (char *)alloc_percpu(perf_trace_t);
+		buf = (char __percpu *)alloc_percpu(perf_trace_t);
 		if (!buf)
 			goto fail_buf;
 
 		rcu_assign_pointer(perf_trace_buf, buf);
 
-		buf = (char *)alloc_percpu(perf_trace_t);
+		buf = (char __percpu *)alloc_percpu(perf_trace_t);
 		if (!buf)
 			goto fail_buf_nmi;
 
@@ -81,7 +81,7 @@ int ftrace_profile_enable(int event_id)
 
 static void ftrace_profile_disable_event(struct ftrace_event_call *event)
 {
-	char *buf, *nmi_buf;
+	char __percpu *buf, *nmi_buf;
 
 	if (--event->profile_count > 0)
 		return;
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 9d976f3..2144178 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -21,7 +21,7 @@ struct fgraph_cpu_data {
 };
 
 struct fgraph_data {
-	struct fgraph_cpu_data		*cpu_data;
+	struct fgraph_cpu_data __percpu *cpu_data;
 
 	/* Place to preserve last processed entry. */
 	struct ftrace_graph_ent_entry	ent;
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 6ea90c0..4567950 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1262,7 +1262,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
 	struct trace_entry *ent;
 	int size, __size, i, pc, __cpu;
 	unsigned long irq_flags;
-	char *trace_buf;
+	char __percpu *trace_buf;
 	char *raw_data;
 	int rctx;
 
@@ -1327,7 +1327,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
 	struct trace_entry *ent;
 	int size, __size, i, pc, __cpu;
 	unsigned long irq_flags;
-	char *trace_buf;
+	char __percpu *trace_buf;
 	char *raw_data;
 	int rctx;
 
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c
index 94103cd..7e5c483 100644
--- a/kernel/trace/trace_ksym.c
+++ b/kernel/trace/trace_ksym.c
@@ -42,7 +42,7 @@
 #define KSYM_TRACER_OP_LEN 3 /* rw- */
 
 struct trace_ksym {
-	struct perf_event	**ksym_hbp;
+	struct perf_event	* __percpu *ksym_hbp;
 	struct perf_event_attr	attr;
 #ifdef CONFIG_PROFILE_KSYM_TRACER
 	atomic64_t		counter;
@@ -200,8 +200,8 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
 	entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr,
 					ksym_hbp_handler);
 
-	if (IS_ERR(entry->ksym_hbp)) {
-		ret = PTR_ERR(entry->ksym_hbp);
+	if (IS_ERR((void __force *)entry->ksym_hbp)) {
+		ret = PTR_ERR((void __force *)entry->ksym_hbp);
 		printk(KERN_INFO "ksym_tracer request failed. Try again"
 					" later!!\n");
 		goto err;
@@ -331,8 +331,8 @@ static ssize_t ksym_trace_filter_write(struct file *file,
 			entry->ksym_hbp =
 				register_wide_hw_breakpoint(&entry->attr,
 					ksym_hbp_handler);
-			if (IS_ERR(entry->ksym_hbp))
-				ret = PTR_ERR(entry->ksym_hbp);
+			if (IS_ERR((void __force *)entry->ksym_hbp))
+				ret = PTR_ERR((void __force *)entry->ksym_hbp);
 			else
 				goto out_unlock;
 		}
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 75289f3..9f7de51 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -433,7 +433,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
 	struct syscall_metadata *sys_data;
 	struct syscall_trace_enter *rec;
 	unsigned long flags;
-	char *trace_buf;
+	char __percpu *trace_buf;
 	char *raw_data;
 	int syscall_nr;
 	int rctx;
@@ -531,7 +531,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
 	struct syscall_trace_exit *rec;
 	unsigned long flags;
 	int syscall_nr;
-	char *trace_buf;
+	char __percpu *trace_buf;
 	char *raw_data;
 	int rctx;
 	int size;
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 4/8] percpu: add __percpu sparse annotations to net drivers
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo, Eric Dumazet, Arnd Bergmann
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to net drivers.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Arnd Bergmann <arnd@arndb.de>
---
 drivers/net/chelsio/sge.c |    2 +-
 drivers/net/loopback.c    |   16 +++++++++-------
 drivers/net/macvlan.c     |    2 +-
 drivers/net/veth.c        |    4 ++--
 4 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 109d278..8e12505 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -267,7 +267,7 @@ struct sge {
 	struct sk_buff	*espibug_skb[MAX_NPORTS];
 	u32		sge_control;	/* shadow value of sge control reg */
 	struct sge_intr_counts stats;
-	struct sge_port_stats *port_stats[MAX_NPORTS];
+	struct sge_port_stats __percpu *port_stats[MAX_NPORTS];
 	struct sched	*tx_sched;
 	struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp;
 };
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b9fcc98..72b7949 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -72,7 +72,8 @@ struct pcpu_lstats {
 static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 				 struct net_device *dev)
 {
-	struct pcpu_lstats *pcpu_lstats, *lb_stats;
+	struct pcpu_lstats __percpu *pcpu_lstats;
+	struct pcpu_lstats *lb_stats;
 	int len;
 
 	skb_orphan(skb);
@@ -80,7 +81,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 	skb->protocol = eth_type_trans(skb, dev);
 
 	/* it's OK to use per_cpu_ptr() because BHs are off */
-	pcpu_lstats = dev->ml_priv;
+	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
 	lb_stats = this_cpu_ptr(pcpu_lstats);
 
 	len = skb->len;
@@ -95,14 +96,14 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 
 static struct net_device_stats *loopback_get_stats(struct net_device *dev)
 {
-	const struct pcpu_lstats *pcpu_lstats;
+	const struct pcpu_lstats __percpu *pcpu_lstats;
 	struct net_device_stats *stats = &dev->stats;
 	unsigned long bytes = 0;
 	unsigned long packets = 0;
 	unsigned long drops = 0;
 	int i;
 
-	pcpu_lstats = dev->ml_priv;
+	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
 	for_each_possible_cpu(i) {
 		const struct pcpu_lstats *lb_stats;
 
@@ -135,19 +136,20 @@ static const struct ethtool_ops loopback_ethtool_ops = {
 
 static int loopback_dev_init(struct net_device *dev)
 {
-	struct pcpu_lstats *lstats;
+	struct pcpu_lstats __percpu *lstats;
 
 	lstats = alloc_percpu(struct pcpu_lstats);
 	if (!lstats)
 		return -ENOMEM;
 
-	dev->ml_priv = lstats;
+	dev->ml_priv = (void __force *)lstats;
 	return 0;
 }
 
 static void loopback_dev_free(struct net_device *dev)
 {
-	struct pcpu_lstats *lstats = dev->ml_priv;
+	struct pcpu_lstats __percpu *lstats =
+		(void __percpu __force *)dev->ml_priv;
 
 	free_percpu(lstats);
 	free_netdev(dev);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 21a9c9a..4d2040c 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -59,7 +59,7 @@ struct macvlan_dev {
 	struct hlist_node	hlist;
 	struct macvlan_port	*port;
 	struct net_device	*lowerdev;
-	struct macvlan_rx_stats *rx_stats;
+	struct macvlan_rx_stats __percpu *rx_stats;
 	enum macvlan_mode	mode;
 };
 
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3a15de5..35609e6 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -34,7 +34,7 @@ struct veth_net_stats {
 
 struct veth_priv {
 	struct net_device *peer;
-	struct veth_net_stats *stats;
+	struct veth_net_stats __percpu *stats;
 	unsigned ip_summed;
 };
 
@@ -263,7 +263,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
 
 static int veth_dev_init(struct net_device *dev)
 {
-	struct veth_net_stats *stats;
+	struct veth_net_stats __percpu *stats;
 	struct veth_priv *priv;
 
 	stats = alloc_percpu(struct veth_net_stats);
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 1/8] percpu: add __percpu sparse annotations to core kernel subsystems
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo, linux-mm, Dipankar Sarma, Paul E. McKenney,
	Peter Zijlstra
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to core subsystems.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: linux-mm@kvack.org
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Dipankar Sarma <dipankar@in.ibm.com>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Eric Biederman <ebiederm@xmission.com>
---
 include/linux/blktrace_api.h   |    4 ++--
 include/linux/genhd.h          |    2 +-
 include/linux/kexec.h          |    2 +-
 include/linux/mmzone.h         |    2 +-
 include/linux/module.h         |    2 +-
 include/linux/percpu_counter.h |    2 +-
 include/linux/srcu.h           |    2 +-
 kernel/kexec.c                 |    2 +-
 kernel/sched.c                 |    4 ++--
 kernel/stop_machine.c          |    2 +-
 mm/percpu.c                    |   18 ++++++++++--------
 11 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 3b73b99..416bf62 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -150,8 +150,8 @@ struct blk_user_trace_setup {
 struct blk_trace {
 	int trace_state;
 	struct rchan *rchan;
-	unsigned long *sequence;
-	unsigned char *msg_data;
+	unsigned long __percpu *sequence;
+	unsigned char __percpu *msg_data;
 	u16 act_mask;
 	u64 start_lba;
 	u64 end_lba;
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 9717081..56b5051 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -101,7 +101,7 @@ struct hd_struct {
 	unsigned long stamp;
 	int in_flight[2];
 #ifdef	CONFIG_SMP
-	struct disk_stats *dkstats;
+	struct disk_stats __percpu *dkstats;
 #else
 	struct disk_stats dkstats;
 #endif
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index c356b69..03e8e8d 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -199,7 +199,7 @@ extern struct kimage *kexec_crash_image;
  */
 extern struct resource crashk_res;
 typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4];
-extern note_buf_t *crash_notes;
+extern note_buf_t __percpu *crash_notes;
 extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
 extern size_t vmcoreinfo_size;
 extern size_t vmcoreinfo_max_size;
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7874201..41acd4b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -301,7 +301,7 @@ struct zone {
 	unsigned long		min_unmapped_pages;
 	unsigned long		min_slab_pages;
 #endif
-	struct per_cpu_pageset	*pageset;
+	struct per_cpu_pageset __percpu *pageset;
 	/*
 	 * free areas of different sizes
 	 */
diff --git a/include/linux/module.h b/include/linux/module.h
index 7e74ae0..dd618eb 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -365,7 +365,7 @@ struct module
 
 	struct module_ref {
 		int count;
-	} *refptr;
+	} __percpu *refptr;
 #endif
 
 #ifdef CONFIG_CONSTRUCTORS
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index a7684a5..9bd103c 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -21,7 +21,7 @@ struct percpu_counter {
 #ifdef CONFIG_HOTPLUG_CPU
 	struct list_head list;	/* All percpu_counters are on a list */
 #endif
-	s32 *counters;
+	s32 __percpu *counters;
 };
 
 extern int percpu_counter_batch;
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 4765d97..41eedcc 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -33,7 +33,7 @@ struct srcu_struct_array {
 
 struct srcu_struct {
 	int completed;
-	struct srcu_struct_array *per_cpu_ref;
+	struct srcu_struct_array __percpu *per_cpu_ref;
 	struct mutex mutex;
 };
 
diff --git a/kernel/kexec.c b/kernel/kexec.c
index a9a93d9..c769613 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -40,7 +40,7 @@
 #include <asm/sections.h>
 
 /* Per cpu memory for storing cpu states in case of system crash. */
-note_buf_t* crash_notes;
+note_buf_t __percpu *crash_notes;
 
 /* vmcoreinfo stuff */
 static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
diff --git a/kernel/sched.c b/kernel/sched.c
index 4508fe7..512b10f 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1566,7 +1566,7 @@ static unsigned long cpu_avg_load_per_task(int cpu)
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
-static __read_mostly unsigned long *update_shares_data;
+static __read_mostly unsigned long __percpu *update_shares_data;
 
 static void __set_se_shares(struct sched_entity *se, unsigned long shares);
 
@@ -10668,7 +10668,7 @@ struct cgroup_subsys cpu_cgroup_subsys = {
 struct cpuacct {
 	struct cgroup_subsys_state css;
 	/* cpuusage holds pointer to a u64-type object on every cpu */
-	u64 *cpuusage;
+	u64 __percpu *cpuusage;
 	struct percpu_counter cpustat[CPUACCT_STAT_NSTATS];
 	struct cpuacct *parent;
 };
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 912823e..9bb9fb1 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -45,7 +45,7 @@ static int refcount;
 static struct workqueue_struct *stop_machine_wq;
 static struct stop_machine_data active, idle;
 static const struct cpumask *active_cpus;
-static void *stop_machine_work;
+static void __percpu *stop_machine_work;
 
 static void set_state(enum stopmachine_state newstate)
 {
diff --git a/mm/percpu.c b/mm/percpu.c
index b336638..768419d 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -80,13 +80,15 @@
 /* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */
 #ifndef __addr_to_pcpu_ptr
 #define __addr_to_pcpu_ptr(addr)					\
-	(void *)((unsigned long)(addr) - (unsigned long)pcpu_base_addr	\
-		 + (unsigned long)__per_cpu_start)
+	(void __percpu *)((unsigned long)(addr) -			\
+			  (unsigned long)pcpu_base_addr	+		\
+			  (unsigned long)__per_cpu_start)
 #endif
 #ifndef __pcpu_ptr_to_addr
 #define __pcpu_ptr_to_addr(ptr)						\
-	(void *)((unsigned long)(ptr) + (unsigned long)pcpu_base_addr	\
-		 - (unsigned long)__per_cpu_start)
+	(void __force *)((unsigned long)(ptr) +				\
+			 (unsigned long)pcpu_base_addr -		\
+			 (unsigned long)__per_cpu_start)
 #endif
 
 struct pcpu_chunk {
@@ -1065,7 +1067,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
  * RETURNS:
  * Percpu pointer to the allocated area on success, NULL on failure.
  */
-static void *pcpu_alloc(size_t size, size_t align, bool reserved)
+static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
 {
 	static int warn_limit = 10;
 	struct pcpu_chunk *chunk;
@@ -1194,7 +1196,7 @@ fail_unlock_mutex:
  * RETURNS:
  * Percpu pointer to the allocated area on success, NULL on failure.
  */
-void *__alloc_percpu(size_t size, size_t align)
+void __percpu *__alloc_percpu(size_t size, size_t align)
 {
 	return pcpu_alloc(size, align, false);
 }
@@ -1215,7 +1217,7 @@ EXPORT_SYMBOL_GPL(__alloc_percpu);
  * RETURNS:
  * Percpu pointer to the allocated area on success, NULL on failure.
  */
-void *__alloc_reserved_percpu(size_t size, size_t align)
+void __percpu *__alloc_reserved_percpu(size_t size, size_t align)
 {
 	return pcpu_alloc(size, align, true);
 }
@@ -1267,7 +1269,7 @@ static void pcpu_reclaim(struct work_struct *work)
  * CONTEXT:
  * Can be called from atomic context.
  */
-void free_percpu(void *ptr)
+void free_percpu(void __percpu *ptr)
 {
 	void *addr;
 	struct pcpu_chunk *chunk;
-- 
1.6.4.2


^ permalink raw reply related

* [PATCHSET] percpu: add __percpu sparse annotations
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@

This patchset adds __percpu sparse annotations to all percpu users
covered by x86_64 allmodconfig.  __percpu annotation teaches sparse
that percpu variables live in a separate address space and can't be
accessed directly without going through percpu accessors.  This allows
detection of most percpu access mistakes involving both static and
dyanmic percpu variables.

This patchset contains the following eight patches.

 0001-percpu-add-__percpu-sparse-annotations-to-core-kerne.patch
 0002-percpu-add-__percpu-sparse-annotations-to-fs.patch
 0003-percpu-add-__percpu-sparse-annotations-to-net.patch
 0004-percpu-add-__percpu-sparse-annotations-to-net-driver.patch
 0005-percpu-add-__percpu-sparse-annotations-to-x86.patch
 0006-percpu-add-__percpu-sparse-annotations-to-trace.patch
 0007-percpu-add-__percpu-sparse-annotations-to-hw_breakpo.patch
 0008-percpu-add-__percpu-sparse-annotations-to-what-s-lef.patch

As these annotations are for sparse, none of the above patches affects
normal kernel build and most of the conversions are straight-forward
and trivial.  There are a few places where the conversion isn't
completely straight-forward (but still fairly trivial).  Those are
mentioned in each patch description.

I can route the patch through percpu and conflict resolution, if
necessary, wouldn't be difficult at all for these changes.  If anyone
wants to route one of these patches through a different tree, please
let me know.  All that's necessary would be adding dummy __percpu
definition to the patch.

If nobody objects, I'll push these into percpu tree in three or four
days.

Thanks.

 arch/x86/include/asm/msr.h                 |   12 ++++---
 arch/x86/kernel/acpi/cstate.c              |    2 -
 arch/x86/kernel/cpu/common.c               |    2 -
 arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c |    2 -
 arch/x86/lib/msr-smp.c                     |    8 +++--
 arch/x86/lib/msr.c                         |    6 +--
 crypto/cryptd.c                            |    2 -
 drivers/acpi/processor_perflib.c           |    2 -
 drivers/dma/dmaengine.c                    |    2 -
 drivers/edac/amd64_edac.c                  |    2 -
 drivers/md/raid5.c                         |    2 -
 drivers/md/raid5.h                         |    2 -
 drivers/net/chelsio/sge.c                  |    2 -
 drivers/net/loopback.c                     |   16 +++++-----
 drivers/net/macvlan.c                      |    2 -
 drivers/net/veth.c                         |    4 +-
 fs/ext4/ext4.h                             |    2 -
 fs/nfs/iostat.h                            |    4 +-
 fs/xfs/xfs_mount.h                         |    2 -
 include/acpi/processor.h                   |    2 -
 include/linux/blktrace_api.h               |    4 +-
 include/linux/dmaengine.h                  |    2 -
 include/linux/ftrace_event.h               |    4 +-
 include/linux/genhd.h                      |    2 -
 include/linux/hw_breakpoint.h              |    8 ++---
 include/linux/kexec.h                      |    2 -
 include/linux/mmzone.h                     |    2 -
 include/linux/module.h                     |    2 -
 include/linux/mount.h                      |    2 -
 include/linux/nfs_fs_sb.h                  |    2 -
 include/linux/percpu_counter.h             |    2 -
 include/linux/srcu.h                       |    2 -
 include/net/ip.h                           |    6 +--
 include/net/ipcomp.h                       |    2 -
 include/net/neighbour.h                    |    2 -
 include/net/netns/conntrack.h              |    2 -
 include/net/netns/core.h                   |    2 -
 include/net/route.h                        |    2 -
 include/net/snmp.h                         |   12 +++++--
 include/net/tcp.h                          |    2 -
 include/trace/ftrace.h                     |    4 +-
 kernel/hw_breakpoint.c                     |   14 ++++----
 kernel/kexec.c                             |    2 -
 kernel/sched.c                             |    4 +-
 kernel/stop_machine.c                      |    2 -
 kernel/trace/trace_event_profile.c         |   16 +++++-----
 kernel/trace/trace_functions_graph.c       |    2 -
 kernel/trace/trace_kprobe.c                |    4 +-
 kernel/trace/trace_ksym.c                  |   10 +++---
 kernel/trace/trace_syscalls.c              |    4 +-
 mm/percpu.c                                |   18 ++++++-----
 net/8021q/vlan.h                           |    2 -
 net/dccp/proto.c                           |    5 +--
 net/ipv4/af_inet.c                         |   46 ++++++++++++++---------------
 net/ipv4/proc.c                            |   28 ++++++++---------
 net/ipv4/route.c                           |    2 -
 net/ipv4/tcp.c                             |   21 +++++++------
 net/ipv6/addrconf.c                        |   24 +++++++--------
 net/ipv6/af_inet6.c                        |   28 ++++++++---------
 net/ipv6/proc.c                            |   24 ++++++++-------
 net/sctp/proc.c                            |    2 -
 net/sctp/protocol.c                        |    5 +--
 net/xfrm/xfrm_ipcomp.c                     |   16 +++++-----
 net/xfrm/xfrm_policy.c                     |    6 +--
 net/xfrm/xfrm_proc.c                       |    3 +
 samples/hw_breakpoint/data_breakpoint.c    |    6 +--
 66 files changed, 231 insertions(+), 209 deletions(-)

--
tejun

^ permalink raw reply

* [PATCH 2/8] percpu: add __percpu sparse annotations to fs
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to fs.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Alex Elder <aelder@sgi.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
---
 fs/ext4/ext4.h            |    2 +-
 fs/nfs/iostat.h           |    4 ++--
 fs/xfs/xfs_mount.h        |    2 +-
 include/linux/mount.h     |    2 +-
 include/linux/nfs_fs_sb.h |    2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index af7b626..eeb1e36 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1017,7 +1017,7 @@ struct ext4_sb_info {
 	atomic_t s_lock_busy;
 
 	/* locality groups */
-	struct ext4_locality_group *s_locality_groups;
+	struct ext4_locality_group __percpu *s_locality_groups;
 
 	/* for write statistics */
 	unsigned long s_sectors_written_start;
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h
index 46d779a..1d8d5c8 100644
--- a/fs/nfs/iostat.h
+++ b/fs/nfs/iostat.h
@@ -57,12 +57,12 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
 }
 #endif
 
-static inline struct nfs_iostats *nfs_alloc_iostats(void)
+static inline struct nfs_iostats __percpu *nfs_alloc_iostats(void)
 {
 	return alloc_percpu(struct nfs_iostats);
 }
 
-static inline void nfs_free_iostats(struct nfs_iostats *stats)
+static inline void nfs_free_iostats(struct nfs_iostats __percpu *stats)
 {
 	if (stats != NULL)
 		free_percpu(stats);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 1df7e45..24c8887 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -243,7 +243,7 @@ typedef struct xfs_mount {
 	struct xfs_qmops	*m_qm_ops;	/* vector of XQM ops */
 	atomic_t		m_active_trans;	/* number trans frozen */
 #ifdef HAVE_PERCPU_SB
-	xfs_icsb_cnts_t		*m_sb_cnts;	/* per-cpu superblock counters */
+	xfs_icsb_cnts_t __percpu *m_sb_cnts;	/* per-cpu superblock counters */
 	unsigned long		m_icsb_counters; /* disabled per-cpu counters */
 	struct notifier_block	m_icsb_notifier; /* hotplug cpu notifier */
 	struct mutex		m_icsb_mutex;	/* balancer sync lock */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 5d52753..b5f43a3 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -66,7 +66,7 @@ struct vfsmount {
 	int mnt_pinned;
 	int mnt_ghosts;
 #ifdef CONFIG_SMP
-	int *mnt_writers;
+	int __percpu *mnt_writers;
 #else
 	int mnt_writers;
 #endif
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 34fc6be..6a2e44f 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -105,7 +105,7 @@ struct nfs_server {
 	struct rpc_clnt *	client;		/* RPC client handle */
 	struct rpc_clnt *	client_acl;	/* ACL RPC client handle */
 	struct nlm_host		*nlm_host;	/* NLM client handle */
-	struct nfs_iostats *	io_stats;	/* I/O statistics */
+	struct nfs_iostats __percpu *io_stats;	/* I/O statistics */
 	struct backing_dev_info	backing_dev_info;
 	atomic_long_t		writeback;	/* number of writeback pages */
 	int			flags;		/* various flags */
-- 
1.6.4.2


^ permalink raw reply related

* [PATCH 5/8] percpu: add __percpu sparse annotations to x86
From: Tejun Heo @ 2010-01-25 15:22 UTC (permalink / raw)
  To: linux-kernel, axboe, rusty, akpm, ebiederm, tytso,
	Trond.Myklebust, aelder, hch@
  Cc: Tejun Heo, Thomas Gleixner, H. Peter Anvin
In-Reply-To: <1264432935-10453-1-git-send-email-tj@kernel.org>

Add __percpu sparse annotations to x86.

These annotations are to make sparse consider percpu variables to be
in a different address space and warn if accessed without going
through percpu accessors.  This patch doesn't affect normal builds.

In arch/x86/kernel/cpu/common.c, per_cpu(exception_stacks, cpu) is
replaced with &per_cpu(exception_stacks[0], cpu) which is equivalent
except that it allows per_cpu() macro to correctly drop percpu
designation during sparse pass.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
---
 arch/x86/include/asm/msr.h                 |   12 +++++++-----
 arch/x86/kernel/acpi/cstate.c              |    2 +-
 arch/x86/kernel/cpu/common.c               |    2 +-
 arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c |    2 +-
 arch/x86/lib/msr-smp.c                     |    8 +++++---
 arch/x86/lib/msr.c                         |    6 +++---
 6 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index c5bc4c2..74882a5 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -30,7 +30,7 @@ struct msr {
 struct msr_info {
 	u32 msr_no;
 	struct msr reg;
-	struct msr *msrs;
+	struct msr __percpu *msrs;
 	int err;
 };
 
@@ -256,14 +256,16 @@ do {                                                            \
 
 #define write_rdtscp_aux(val) wrmsr(MSR_TSC_AUX, (val), 0)
 
-struct msr *msrs_alloc(void);
-void msrs_free(struct msr *msrs);
+struct msr __percpu *msrs_alloc(void);
+void msrs_free(struct msr __percpu *msrs);
 
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+		   struct msr __percpu *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+		   struct msr __percpu *msrs);
 int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index 2e837f5..62b0693 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -61,7 +61,7 @@ struct cstate_entry {
 		unsigned int ecx;
 	} states[ACPI_PROCESSOR_MAX_POWER];
 };
-static struct cstate_entry *cpu_cstate_entry;	/* per CPU ptr */
+static struct cstate_entry __percpu *cpu_cstate_entry;	/* per CPU ptr */
 
 static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
 
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4868e4a..486cb06 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1146,7 +1146,7 @@ void __cpuinit cpu_init(void)
 	 * set up and load the per-CPU TSS
 	 */
 	if (!oist->ist[0]) {
-		char *estacks = per_cpu(exception_stacks, cpu);
+		char *estacks = &per_cpu(exception_stacks[0], cpu);
 
 		for (v = 0; v < N_EXCEPTION_STACKS; v++) {
 			estacks += exception_stack_sizes[v];
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 1b1920f..61cfd75 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -73,7 +73,7 @@ static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
 static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf);
 
 /* acpi_perf_data is a pointer to percpu data. */
-static struct acpi_processor_performance *acpi_perf_data;
+static struct acpi_processor_performance __percpu *acpi_perf_data;
 
 static struct cpufreq_driver acpi_cpufreq_driver;
 
diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c
index a6b1b86..b6a355f 100644
--- a/arch/x86/lib/msr-smp.c
+++ b/arch/x86/lib/msr-smp.c
@@ -64,7 +64,7 @@ int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
 EXPORT_SYMBOL(wrmsr_on_cpu);
 
 static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
-			    struct msr *msrs,
+			    struct msr __percpu *msrs,
 			    void (*msr_func) (void *info))
 {
 	struct msr_info rv;
@@ -91,7 +91,8 @@ static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
  * @msrs:       array of MSR values
  *
  */
-void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+		   struct msr __percpu *msrs)
 {
 	__rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
 }
@@ -105,7 +106,8 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
  * @msrs:       array of MSR values
  *
  */
-void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+		   struct msr __percpu *msrs)
 {
 	__rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
 }
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 8f8eebd..42c994c 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -2,9 +2,9 @@
 #include <linux/preempt.h>
 #include <asm/msr.h>
 
-struct msr *msrs_alloc(void)
+struct msr __percpu *msrs_alloc(void)
 {
-	struct msr *msrs = NULL;
+	struct msr __percpu *msrs = NULL;
 
 	msrs = alloc_percpu(struct msr);
 	if (!msrs) {
@@ -16,7 +16,7 @@ struct msr *msrs_alloc(void)
 }
 EXPORT_SYMBOL(msrs_alloc);
 
-void msrs_free(struct msr *msrs)
+void msrs_free(struct msr __percpu *msrs)
 {
 	free_percpu(msrs);
 }
-- 
1.6.4.2


^ permalink raw reply related

* Re: [PATCH] tcp: fix ICMP-RTO war
From: Damian Lukowski @ 2010-01-25 15:07 UTC (permalink / raw)
  To: Denys Fedoryshchenko; +Cc: Ilpo Järvinen, Netdev, David Miller
In-Reply-To: <201001240045.52846.denys@visp.net.lb>

Denys Fedoryshchenko schrieb:
>> Cool, thanks for testing.
>>
>> Dave, please send into stable too (besides net-2.6). If we want less strict
>> state check we can continue playing with that in net-next, IMHO.
>>
> Maybe better to wait. Sad news, got messages after while (before they was 
> appearing  almost immediately on such load).
> 
> [ ... ]

Hi Denys,
could you test the following patch, please?

Damian


diff --git a/include/net/tcp.h b/include/net/tcp.h
index 34f5cc2..ec2fc91 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -530,7 +530,11 @@ static inline void tcp_bound_rto(const struct sock *sk)
 
 static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
 {
-	return (tp->srtt >> 3) + tp->rttvar;
+	u32 rto = (tp->srtt >> 3) + tp->rttvar;
+	if (unlikely(rto < TCP_RTO_MIN))
+		return TCP_RTO_MIN;
+	else
+		return rto;
 }
 
 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)

^ permalink raw reply related

* Re: [RFC PATCH] extend RTM_GETNEIGH to allow getting more precise information
From: Patrick McHardy @ 2010-01-25 13:51 UTC (permalink / raw)
  To: David Miller; +Cc: cratiu, netdev, ixlk-cr, pchakrabarti
In-Reply-To: <20100123.021233.122638456.davem@davemloft.net>

David Miller wrote:
> From: Cosmin Ratiu <cratiu@ixiacom.com>
> Date: Fri, 15 Jan 2010 18:42:59 +0200
> 
>> Please have a look at this patch which tries to solve a problem we 
>> encountered.
>>
>> The background is that RTM_GETNEIGH netlink message is used to get a complete 
>> dump of a neighbor table. Sometimes, that's too much (especially when you have 
>> a lot of neighbors). This patch allows one to specify the IPv4/6 address of a 
>> neighbor and the device index through which it is accessible in order to 
>> obtain only that entry.
>>
>> If you have other suggestions on how to accomplish this task, please let us 
>> know.
> 
> Please add a netlink attribute to specify lookup keys.
> 
> Adding specifiers to the end of the existing request message
> error prone and creates trouble in the future if someone gets
> the idea to add something more.

It should also use a seperate callback for looking up individual
entries instead of the NLM_F_DUMP callback.

^ permalink raw reply

* Re: Lockdep warning and kernel panic with e1000e on 2.6.33-rc4
From: Joerg Roedel @ 2010-01-25 13:46 UTC (permalink / raw)
  To: Joerg Roedel
  Cc: Jeff Kirsher, Jesse Brandeburg, Bruce Allan, PJ Waskiewicz,
	John Ronciak, e1000-devel, netdev, linux-kernel
In-Reply-To: <20100122132432.GI8665@amd.com>

Okay, it turned out that this was a regression in the AMD IOMMU driver :-(
I fixed it and now the issue disappeared. Sorry for the noise.

	Joerg

On Fri, Jan 22, 2010 at 02:24:32PM +0100, Joerg Roedel wrote:
> Hi,
> 
> I just tried to unbind a device from the e1000e driver and got the following
> output from lockdep and the kernel panic from a NULL pointer dereference. The
> kernel running on the machine is 2.6.33-rc4 + kvm patches (which shouldn't
> matter):
> 
> [  157.282671] =============================================
> [  157.283400] [ INFO: possible recursive locking detected ]
> [  157.283400] 2.6.33-rc4 #76
> [  157.283400] ---------------------------------------------
> [  157.283400] bash/3686 is trying to acquire lock:
> [  157.283400]  (s_active){++++.+}, at: [<ffffffff811543f8>] sysfs_hash_and_remove+0x53/0x6a
> [  157.283400] 
> [  157.283400] but task is already holding lock:
> [  157.283400]  (s_active){++++.+}, at: [<ffffffff811563fd>] sysfs_get_active_two+0x24/0x4b
> [  157.283400] 
> [  157.283400] other info that might help us debug this:
> [  157.283400] 3 locks held by bash/3686:
> [  157.283400]  #0:  (&buffer->mutex){+.+.+.}, at: [<ffffffff81154d4d>] sysfs_write_file+0x3e/0x12b
> [  157.283400]  #1:  (s_active){++++.+}, at: [<ffffffff811563fd>] sysfs_get_active_two+0x24/0x4b
> [  157.283400]  #2:  (s_active){++++.+}, at: [<ffffffff8115640a>] sysfs_get_active_two+0x31/0x4b
> [  157.283400] 
> [  157.283400] stack backtrace:
> [  157.283400] Pid: 3686, comm: bash Not tainted 2.6.33-rc4 #76
> [  157.283400] Call Trace:
> [  157.283400]  [<ffffffff81071576>] __lock_acquire+0xcf1/0xd86
> [  157.283400]  [<ffffffff8106ff39>] ? debug_check_no_locks_freed+0x120/0x12f
> [  157.283400]  [<ffffffff8106faff>] ? trace_hardirqs_on_caller+0x11f/0x14a
> [  157.283400]  [<ffffffff810716cf>] lock_acquire+0xc4/0xe1
> [  157.283400]  [<ffffffff811543f8>] ? sysfs_hash_and_remove+0x53/0x6a
> [  157.283400]  [<ffffffff8115612a>] sysfs_addrm_finish+0xcd/0x135
> [  157.283400]  [<ffffffff811543f8>] ? sysfs_hash_and_remove+0x53/0x6a
> [  157.283400]  [<ffffffff8165ec51>] ? __mutex_lock_common+0x324/0x335
> [  157.283400]  [<ffffffff8165ed20>] ? mutex_lock_nested+0x3c/0x41
> [  157.283400]  [<ffffffff811543f8>] sysfs_hash_and_remove+0x53/0x6a
> [  157.283400]  [<ffffffff811565eb>] sysfs_remove_link+0x21/0x23
> [  157.283400]  [<ffffffff8135209f>] __device_release_driver+0x2d/0xce
> [  157.283400]  [<ffffffff81352215>] device_release_driver+0x23/0x30
> [  157.283400]  [<ffffffff81351a7e>] driver_unbind+0x5c/0x9e
> [  157.283400]  [<ffffffff81350f36>] drv_attr_store+0x2c/0x2e
> [  157.283400]  [<ffffffff81154e05>] sysfs_write_file+0xf6/0x12b
> [  157.283400]  [<ffffffff810fe635>] vfs_write+0xb0/0x10a
> [  157.283400]  [<ffffffff810fe75d>] sys_write+0x4c/0x75
> [  157.283400]  [<ffffffff81002c1b>] system_call_fastpath+0x16/0x1b
> [  157.506592] e1000e 0000:02:00.0: PCI INT A disabled
> [  157.511796] BUG: unable to handle kernel NULL pointer dereference at 0000000000000024
> [  157.512464] IP: [<ffffffff81212b7c>] do_raw_spin_unlock+0xc/0x8b
> [  157.512464] PGD 835651067 PUD 835a98067 PMD 0 
> [  157.512464] Oops: 0000 [#1] SMP 
> [  157.512464] last sysfs file: /sys/bus/pci/drivers/e1000e/unbind
> [  157.512464] CPU 19 
> [  157.512464] Pid: 3686, comm: bash Not tainted 2.6.33-rc4 #76 Dinar/Dinar
> [  157.512464] RIP: 0010:[<ffffffff81212b7c>]  [<ffffffff81212b7c>] do_raw_spin_unlock+0xc/0x8b
> [  157.512464] RSP: 0018:ffff88043675dcf8  EFLAGS: 00010092
> [  157.512464] RAX: ffff880435116540 RBX: 0000000000000020 RCX: 0000000000000000
> [  157.512464] RDX: ffffffff81023c47 RSI: 0000000000000001 RDI: 0000000000000020
> [  157.512464] RBP: ffff88043675dd08 R08: 0000000000000086 R09: 0000000000000000
> [  157.512464] R10: ffff88043675ddc8 R11: ffff88043675dd08 R12: 0000000000000082
> [  157.512464] R13: 0000000000000082 R14: 0000000000000282 R15: 0000000000000005
> [  157.512464] FS:  00007f5ddd27f6f0(0000) GS:ffff88063f440000(0000) knlGS:0000000000000000
> [  157.512464] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  157.512464] CR2: 0000000000000024 CR3: 0000000835601000 CR4: 00000000000006e0
> [  157.512464] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  157.512464] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> [  157.512464] Process bash (pid: 3686, threadinfo ffff88043675c000, task ffff880435116540)
> [  157.512464] Stack:
> [  157.512464]  0000000000000282 0000000000000020 ffff88043675dd28 ffffffff816600ab
> [  157.512464] <0> ffff880c35829600 ffff8808365dd088 ffff88043675dd58 ffffffff81023c47
> [  157.512464] <0> 0000000000000005 ffff8808365dd088 0000000000000200 ffff880c359e75c0
> [  157.512464] Call Trace:
> [  157.512464]  [<ffffffff816600ab>] _raw_spin_unlock_irqrestore+0x2c/0x4c
> [  157.512464]  [<ffffffff81023c47>] detach_device+0x90/0xc7
> [  157.512464]  [<ffffffff81025687>] device_change_notifier+0x8e/0x127
> [  157.512464]  [<ffffffff81662dda>] notifier_call_chain+0x38/0x60
> [  157.512464]  [<ffffffff81063aba>] __blocking_notifier_call_chain+0x52/0x6f
> [  157.512464]  [<ffffffff81063aeb>] blocking_notifier_call_chain+0x14/0x16
> [  157.512464]  [<ffffffff8135213b>] __device_release_driver+0xc9/0xce
> [  157.512464]  [<ffffffff81352215>] device_release_driver+0x23/0x30
> [  157.512464]  [<ffffffff81351a7e>] driver_unbind+0x5c/0x9e
> [  157.512464]  [<ffffffff81350f36>] drv_attr_store+0x2c/0x2e
> [  157.512464]  [<ffffffff81154e05>] sysfs_write_file+0xf6/0x12b
> [  157.512464]  [<ffffffff810fe635>] vfs_write+0xb0/0x10a
> [  157.512464]  [<ffffffff810fe75d>] sys_write+0x4c/0x75
> [  157.512464]  [<ffffffff81002c1b>] system_call_fastpath+0x16/0x1b
> [  157.512464] Code: c0 4c 89 e6 48 c7 c7 9e 2a ac 81 31 c0 e8 c8 a7 44 00 e8 d8 a5 44 00 5f 5b 41 5c 41 5d c9 c3 55 48 89 e5 53 48 89 fb 48 83 ec 08 <81> 7f 04 ad 4e ad de 74 0c 48 c7 c6 4a 2a ac 81 e8 35 ff ff ff 
> [  157.512464] RIP  [<ffffffff81212b7c>] do_raw_spin_unlock+0xc/0x8b
> [  157.512464]  RSP <ffff88043675dcf8>
> [  157.512464] CR2: 0000000000000024
> [  157.512464] ---[ end trace a773b332cbda2d29 ]---
> 
> lspci of the affected card looks as follows:
> 
> evelt:~# lspci -n -vv -s 02:00.0
> 02:00.0 0200: 8086:10d3
>         Subsystem: 8086:a01f
>         Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
>         Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
>         Latency: 0, Cache Line Size: 64 bytes
>         Interrupt: pin A routed to IRQ 32
>         Region 0: Memory at ce020000 (32-bit, non-prefetchable) [size=128K]
>         Region 1: Memory at ce080000 (32-bit, non-prefetchable) [size=512K]
>         Region 2: I/O ports at 3000 [size=32]
>         Region 3: Memory at ce000000 (32-bit, non-prefetchable) [size=16K]
>         [virtual] Expansion ROM at c8200000 [disabled] [size=256K]
>         Capabilities: [c8] Power Management version 2
>                 Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
>                 Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
>         Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+
>                 Address: 0000000000000000  Data: 0000
>         Capabilities: [e0] Express (v1) Endpoint, MSI 00
>                 DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s <512ns, L1 <64us
>                         ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
>                 DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal+ Unsupported+
>                         RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
>                         MaxPayload 128 bytes, MaxReadReq 512 bytes
>                 DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr+ TransPend-
>                 LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <128ns, L1 <64us
>                         ClockPM- Surprise- LLActRep- BwNot-
>                 LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk+
>                         ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
>                 LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
>         Capabilities: [a0] MSI-X: Enable+ Count=5 Masked-
>                 Vector table: BAR=3 offset=00000000
>                 PBA: BAR=3 offset=00002000
>         Capabilities: [100] Advanced Error Reporting
>                 UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                 UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                 UESvrt: DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
>                 CESta:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
>                 CEMsk:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
>                 AERCap: First Error Pointer: 00, GenCap- CGenEn- ChkCap- ChkEn-
>         Capabilities: [140] Device Serial Number 00-1b-21-ff-ff-46-60-4a
>         Kernel driver in use: e1000e
> 
> Please let me know if you need more information.
> 
> 	Joerg
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH net-next-2.6] net: use helpers to access uc list
From: Jiri Pirko @ 2010-01-25 12:14 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20100125.020628.124583614.davem@davemloft.net>

Mon, Jan 25, 2010 at 11:06:28AM CET, davem@davemloft.net wrote:
>From: Jiri Pirko <jpirko@redhat.com>
>Date: Mon, 25 Jan 2010 09:34:52 +0100
>
>> Well I use "unsigned char *" as iterator because it would allow
>> smooth thansition to list_head in case of mc_list. Currently "struct
>> dev_addr_list" is used to store address in the list but in the end
>> "struct netdev_hw_addr *" will be used.  To use "struct list_head *"
>> or "struct netdev_hw_addr *" as an iterator it would be needed to
>> convert all drivers at once and that's not doable. Therefore I see
>> "unsigned char *" cursor as the best option.
>
>But it's not what you want to use in the end, at all.
>
>If you're going to use a very ugly and opaque iterator type merely to
>ease transition, that's not a good reason.

I definitelly see your concerns. I'll think of a better way. Thanks for the
review!

Redards.

Jirka

^ permalink raw reply

* Re: [PATCH] tcp: fix ICMP-RTO war
From: Damian Lukowski @ 2010-01-25 12:12 UTC (permalink / raw)
  To: Ilpo Järvinen; +Cc: Denys Fedoryshchenko, Netdev, David Miller
In-Reply-To: <alpine.DEB.2.00.1001240007530.16552@melkinpaasi.cs.helsinki.fi>

Hi,
considering Denys' latest tests, I think we should bound
at TCP_RTO_MIN inside __tcp_set_rto().
Look at the following piece:
> [  604.193389] rto: 200 (0 >> 3 + 0, 32) time: 304193 sent: 304091 pen: 1 307291 rem: 98                                                                                         
> [  604.193518] lower bound violation: 0 code 1 sk_state 1                                                                                                                        
> [  604.193589] rto: 200 (0 >> 3 + 0, 31) time: 304193 sent: 304091 pen: 1 304291 rem: 98                                                                                         
> [  604.193706] lower bound violation: 0 code 1 sk_state 1                                                                                                                        
> [  604.193776] rto: 200 (0 >> 3 + 0, 30) time: 304193 sent: 304091 pen: 1 304291 rem: 98                                                                                         
> [  607.341327] lower bound violation: 0 code 1 sk_state 1                                                                                                                        
> [  607.341412] rto: 200 (0 >> 3 + 0, 33) time: 307341 sent: 307091 pen: 1 310291 rem: 0  

We have a burst of three incoming ICMPs, not triggering retransmissions because
of rem > 0. Nevertheless, there is an increase of icsk_backoff by four
within 3100ms, with no ICMPs in between.
For me, this is explainable by the broken mdev/rtt issue together with
bursty ICMP replies.

- At t=0, RTT is at 0.2 seconds when connectivity breaks
- At t=3, TCP has emitted 4 eponentially backed-off retransmits,
  and icsk_rto is at 3.2s.
- At t=3+eps, three of four ICMPs arrive in one burst.
- Due to broken mdev, rto is reset to 0.2s inside tcp_v4_err(),
  independent of icsk_backoff.

Damian

> Restored Damian cc, please keep them.
> 
> On Sat, 23 Jan 2010, Denys Fedoryshchenko wrote:
>> On Tuesday 19 January 2010 13:17:51 you wrote:
>>> On Tue, 19 Jan 2010, Denys Fedoryshchenko wrote:
>>>> On Tuesday 19 January 2010 11:10:12 you wrote:
>>>>> Hi,
>>>>> thank you for testing. So srtt and rttvar is zero in any of those
>>>>> cases. Ilpo, it is a bug in tcp_rtt_estimator then, I suppose?
>>>>>
>>>>> There is also a code comment in tcp_input.c, saying:
>>>>>> * NOTE: clamping at TCP_RTO_MIN is not required, current algo
>>>>>> * guarantees that rto is higher.
>>>>> So we either fix tcp_rtt_estimator or simply clamp at TCP_RTO_MIN?
>>>>>
>>>>> Damian
>>>>>
>>>>>> On Monday 11 January 2010 15:02:34 you wrote:
>>>>>>> On Sat, 26 Dec 2009, Denys Fedoryshchenko wrote:
>>>>>>>> Few more dumps. I notice:
>>>>>>>> 1)Ack always equal 1
>>>>>>>> 2)It is usually first segment of data sent (?)
>>>>>>>>
>>>>>>>> Maybe some value not initialised properly?
>>>>>>> Can you see if the RTO lower bound is violated (I added some
>>>>>>> printing of vars there too already now if it turns out to be
>>>>>>> something):
>>>>>>>
>>>>>>> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
>>>>>>> index 65b8ebf..d84469f 100644
>>>>>>> --- a/net/ipv4/tcp_ipv4.c
>>>>>>> +++ b/net/ipv4/tcp_ipv4.c
>>>> As i see in code it is rounding RTO to minimum value.
>>>> It fixes my problem seems.
>>>>
>>>> Btw just a bit about my environment - wireless networks (sometimes
>>>> lossy!) with low speed (128-512Kbps) customers working over pppoe. Maybe
>>>> it will give a tip why rtt value is too low.
>>> What I find most strange in it is the fact that when it triggers for the
>>> first time, the srtt and mdev are zero, not some value in between 0 and
>>> 200ms. Therefore I suspect that this case might be something that we've
>>> overlooked where srtt/mdev are not valid at all.
>>>
>>> Maybe the patch below helps...
>>>
>> Seems after this patch (and debug patch with warnings) my dmesg is clean.
> 
> Cool, thanks for testing.
> 
> Dave, please send into stable too (besides net-2.6). If we want less strict 
> state check we can continue playing with that in net-next, IMHO.
> 


^ permalink raw reply

* Re: [PATCH 3/4] fec: add support for Freescale i.MX25 PDK (3DS)
From: Baruch Siach @ 2010-01-25 11:21 UTC (permalink / raw)
  To: Greg Ungerer; +Cc: netdev, Sascha Hauer, linux-arm-kernel
In-Reply-To: <20091216063402.GA13160@jasper.tkos.co.il>

Hi Greg, netdev,

On Wed, Dec 16, 2009 at 08:34:06AM +0200, Baruch Siach wrote:
> On Wed, Dec 16, 2009 at 10:13:56AM +1000, Greg Ungerer wrote:
> > Baruch Siach wrote:
> > >On Tue, Dec 15, 2009 at 09:52:24PM +1000, Greg Ungerer wrote:
> > >>On 12/15/2009 06:31 PM, Baruch Siach wrote:
> > >>>+#ifndef CONFIG_M5272
> > >>I would suggest making this conditional on FEC_MIIGSK_ENR.
> > >>Although the CONFIG_M5272 is the only case here currently,
> > >>that may change over the years. And using this here may not
> > >>be obvious to the causual code reader, since the register
> > >>offset definitions don't explicitly key on CONFIG_M5272.
> > >
> > >OK, I'll change this conditional.
> > >
> > >Can I take this as an Ack from you?
> > 
> > With that conditional check changed, sure:
> > 
> > Acked-by:  Greg Ungerer <gerg@uclinux.org>
> 
> Thanks. The updated patch below.

I'm really sorry to bug on this again, but since the platform code is already 
upstream the i.MX25 code doesn't build without this patch (include/linux/fec.h 
missing). So, someone please pick up this patch, preferably prior to .33.

baruch

> From 2d0751f868519978603b16baa197bfb9f9ec9e2e Mon Sep 17 00:00:00 2001
> Message-Id: <2d0751f868519978603b16baa197bfb9f9ec9e2e.1260945080.git.baruch@tkos.co.il>
> From: Baruch Siach <baruch@tkos.co.il>
> Date: Mon, 14 Dec 2009 10:36:50 +0200
> Subject: [PATCH] fec: add support for PHY interface platform data
> 
> The i.MX25 PDK uses RMII to communicate with its PHY. This patch adds the
> ability to configure RMII, based on platform data.
> 
> Signed-off-by: Baruch Siach <baruch@tkos.co.il>
> Acked-by:  Greg Ungerer <gerg@uclinux.org>
> ---
>  drivers/net/fec.c   |   22 ++++++++++++++++++++++
>  drivers/net/fec.h   |    2 ++
>  include/linux/fec.h |   21 +++++++++++++++++++++
>  3 files changed, 45 insertions(+), 0 deletions(-)
>  create mode 100644 include/linux/fec.h
> 
> diff --git a/drivers/net/fec.c b/drivers/net/fec.c
> index 16a1d58..a7cfe0d 100644
> --- a/drivers/net/fec.c
> +++ b/drivers/net/fec.c
> @@ -40,6 +40,7 @@
>  #include <linux/irq.h>
>  #include <linux/clk.h>
>  #include <linux/platform_device.h>
> +#include <linux/fec.h>
>  
>  #include <asm/cacheflush.h>
>  
> @@ -198,6 +199,7 @@ struct fec_enet_private {
>  	uint	phy_speed;
>  	phy_info_t const	*phy;
>  	struct work_struct phy_task;
> +	phy_interface_t	phy_interface;
>  
>  	uint	sequence_done;
>  	uint	mii_phy_task_queued;
> @@ -1810,6 +1812,21 @@ fec_restart(struct net_device *dev, int duplex)
>  	/* Set MII speed */
>  	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
>  
> +#ifdef FEC_MIIGSK_ENR
> +	if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
> +		/* disable the gasket and wait */
> +		writel(0, fep->hwp + FEC_MIIGSK_ENR);
> +		while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
> +			udelay(1);
> +
> +		/* configure the gasket: RMII, 50 MHz, no loopback, no echo */
> +		writel(1, fep->hwp + FEC_MIIGSK_CFGR);
> +
> +		/* re-enable the gasket */
> +		writel(2, fep->hwp + FEC_MIIGSK_ENR);
> +	}
> +#endif
> +
>  	/* And last, enable the transmit and receive processing */
>  	writel(2, fep->hwp + FEC_ECNTRL);
>  	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
> @@ -1847,6 +1864,7 @@ static int __devinit
>  fec_probe(struct platform_device *pdev)
>  {
>  	struct fec_enet_private *fep;
> +	struct fec_platform_data *pdata;
>  	struct net_device *ndev;
>  	int i, irq, ret = 0;
>  	struct resource *r;
> @@ -1879,6 +1897,10 @@ fec_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, ndev);
>  
> +	pdata = pdev->dev.platform_data;
> +	if (pdata)
> +		fep->phy_interface = pdata->phy;
> +
>  	/* This device has up to three irqs on some platforms */
>  	for (i = 0; i < 3; i++) {
>  		irq = platform_get_irq(pdev, i);
> diff --git a/drivers/net/fec.h b/drivers/net/fec.h
> index cc47f3f..2c48b25 100644
> --- a/drivers/net/fec.h
> +++ b/drivers/net/fec.h
> @@ -43,6 +43,8 @@
>  #define FEC_R_DES_START		0x180 /* Receive descriptor ring */
>  #define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
>  #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
> +#define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
> +#define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
>  
>  #else
>  
> diff --git a/include/linux/fec.h b/include/linux/fec.h
> new file mode 100644
> index 0000000..5d3523d
> --- /dev/null
> +++ b/include/linux/fec.h
> @@ -0,0 +1,21 @@
> +/* include/linux/fec.h
> + *
> + * Copyright (c) 2009 Orex Computed Radiography
> + *   Baruch Siach <baruch@tkos.co.il>
> + *
> + * Header file for the FEC platform data
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __LINUX_FEC_H__
> +#define __LINUX_FEC_H__
> +
> +#include <linux/phy.h>
> +
> +struct fec_platform_data {
> +	phy_interface_t phy;
> +};
> +
> +#endif
> -- 
> 1.6.5
> 
> 
> -- 
>                                                      ~. .~   Tk Open Systems
> =}------------------------------------------------ooO--U--Ooo------------{=
>    - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

^ permalink raw reply

* [PATCH 1/1 V4] net: Add Aeroflex Gaisler 10/100/1G Ethernet MAC driver
From: Kristoffer Glembo @ 2010-01-25 11:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, Kristoffer Glembo
In-Reply-To: <1264417272-3800-1-git-send-email-kristoffer@gaisler.com>

Adds device driver for Aeroflex Gaisler 10/100 and 10/100/1G Ethernet MAC IP cores.

Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com>
---
 MAINTAINERS          |    6 +
 drivers/net/Kconfig  |    9 +
 drivers/net/Makefile |    1 +
 drivers/net/greth.c  | 1573 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/greth.h  |  149 +++++
 5 files changed, 1738 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/greth.c
 create mode 100644 drivers/net/greth.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 745643b..45c047c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2372,6 +2372,12 @@ F:	Documentation/isdn/README.gigaset
 F:	drivers/isdn/gigaset/
 F:	include/linux/gigaset_dev.h
 
+GRETH 10/100/1G Ethernet MAC device driver
+M:	Kristoffer Glembo <kristoffer@gaisler.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/greth*
+
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 M:	Frank Seidel <frank@f-seidel.de>
 L:	lm-sensors@lm-sensors.org
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..d600074 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1955,6 +1955,15 @@ source "drivers/net/fs_enet/Kconfig"
 
 source "drivers/net/octeon/Kconfig"
 
+config GRETH
+	tristate "Aeroflex Gaisler GRETH Ethernet MAC support"
+	depends on OF
+	select PHYLIB
+	select CRC32
+	help
+	  Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC.
+
+
 endif # NET_ETHERNET
 
 #
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ad1346d..9f12170 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -246,6 +246,7 @@ pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o
 obj-$(CONFIG_MLX4_CORE) += mlx4/
 obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_GRETH) += greth.o
 
 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
 
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
new file mode 100644
index 0000000..e0b2fc1
--- /dev/null
+++ b/drivers/net/greth.c
@@ -0,0 +1,1573 @@
+/*
+ * Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
+ *
+ * 2005-2009 (c) Aeroflex Gaisler AB
+ *
+ * This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
+ * available in the GRLIB VHDL IP core library.
+ *
+ * Full documentation of both cores can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * The Gigabit version supports scatter/gather DMA, any alignment of
+ * buffers and checksum offloading.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Contributors: Kristoffer Glembo
+ *               Daniel Hellstrom
+ *               Marko Isomaki
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/io.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <asm/cacheflush.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_SPARC
+#include <asm/idprom.h>
+#endif
+
+#include "greth.h"
+
+#define GRETH_DEF_MSG_ENABLE	  \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_PROBE	| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_IFDOWN	| \
+	 NETIF_MSG_IFUP		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
+
+static int greth_debug = -1;	/* -1 == use GRETH_DEF_MSG_ENABLE as value */
+module_param(greth_debug, int, 0);
+MODULE_PARM_DESC(greth_debug, "GRETH bitmapped debugging message enable value");
+
+/* Accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
+static int macaddr[6];
+module_param_array(macaddr, int, NULL, 0);
+MODULE_PARM_DESC(macaddr, "GRETH Ethernet MAC address");
+
+static int greth_open(struct net_device *dev);
+static int greth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev);
+static int greth_rx(struct net_device *dev, int limit);
+static int greth_rx_gbit(struct net_device *dev, int limit);
+static void greth_clean_tx(struct net_device *dev);
+static void greth_clean_tx_gbit(struct net_device *dev);
+static irqreturn_t greth_interrupt(int irq, void *dev_id);
+static int greth_close(struct net_device *dev);
+static struct net_device_stats *greth_get_stats(struct net_device *dev);
+static int greth_set_mac_add(struct net_device *dev, void *p);
+static void greth_set_multicast_list(struct net_device *dev);
+
+#define GRETH_REGLOAD(a)	    (be32_to_cpu(__raw_readl(&(a))))
+#define GRETH_REGSAVE(a, v)         (__raw_writel(cpu_to_be32(v), &(a)))
+#define GRETH_REGORIN(a, v)         (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) | (v))))
+#define GRETH_REGANDIN(a, v)        (GRETH_REGSAVE(a, (GRETH_REGLOAD(a) & (v))))
+
+#define NEXT_TX(N)      (((N) + 1) & GRETH_TXBD_NUM_MASK)
+#define SKIP_TX(N, C)   (((N) + C) & GRETH_TXBD_NUM_MASK)
+#define NEXT_RX(N)      (((N) + 1) & GRETH_RXBD_NUM_MASK)
+
+static void greth_print_rx_packet(void *addr, int len)
+{
+	print_hex_dump(KERN_DEBUG, "RX: ", DUMP_PREFIX_OFFSET, 16, 1,
+			addr, len, true);
+}
+
+static void greth_print_tx_packet(struct sk_buff *skb)
+{
+	int i;
+	int length;
+
+	if (skb_shinfo(skb)->nr_frags == 0)
+		length = skb->len;
+	else
+		length = skb_headlen(skb);
+
+	print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
+			skb->data, length, true);
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+
+		print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
+			       phys_to_virt(page_to_phys(skb_shinfo(skb)->frags[i].page)) +
+			       skb_shinfo(skb)->frags[i].page_offset,
+			       length, true);
+	}
+}
+
+static inline void greth_enable_tx(struct greth_private *greth)
+{
+	wmb();
+	GRETH_REGORIN(greth->regs->control, GRETH_TXEN);
+}
+
+static inline void greth_disable_tx(struct greth_private *greth)
+{
+	GRETH_REGANDIN(greth->regs->control, ~GRETH_TXEN);
+}
+
+static inline void greth_enable_rx(struct greth_private *greth)
+{
+	wmb();
+	GRETH_REGORIN(greth->regs->control, GRETH_RXEN);
+}
+
+static inline void greth_disable_rx(struct greth_private *greth)
+{
+	GRETH_REGANDIN(greth->regs->control, ~GRETH_RXEN);
+}
+
+static inline void greth_enable_irqs(struct greth_private *greth)
+{
+	GRETH_REGORIN(greth->regs->control, GRETH_RXI | GRETH_TXI);
+}
+
+static inline void greth_disable_irqs(struct greth_private *greth)
+{
+	GRETH_REGANDIN(greth->regs->control, ~(GRETH_RXI|GRETH_TXI));
+}
+
+static inline void greth_write_bd(u32 *bd, u32 val)
+{
+	__raw_writel(cpu_to_be32(val), bd);
+}
+
+static inline u32 greth_read_bd(u32 *bd)
+{
+	return be32_to_cpu(__raw_readl(bd));
+}
+
+static void greth_clean_rings(struct greth_private *greth)
+{
+	int i;
+	struct greth_bd *rx_bdp = greth->rx_bd_base;
+	struct greth_bd *tx_bdp = greth->tx_bd_base;
+
+	if (greth->gbit_mac) {
+
+		/* Free and unmap RX buffers */
+		for (i = 0; i < GRETH_RXBD_NUM; i++, rx_bdp++) {
+			if (greth->rx_skbuff[i] != NULL) {
+				dev_kfree_skb(greth->rx_skbuff[i]);
+				dma_unmap_single(greth->dev,
+						 greth_read_bd(&rx_bdp->addr),
+						 MAX_FRAME_SIZE+NET_IP_ALIGN,
+						 DMA_FROM_DEVICE);
+			}
+		}
+
+		/* TX buffers */
+		while (greth->tx_free < GRETH_TXBD_NUM) {
+
+			struct sk_buff *skb = greth->tx_skbuff[greth->tx_last];
+			int nr_frags = skb_shinfo(skb)->nr_frags;
+			tx_bdp = greth->tx_bd_base + greth->tx_last;
+			greth->tx_last = NEXT_TX(greth->tx_last);
+
+			dma_unmap_single(greth->dev,
+					 greth_read_bd(&tx_bdp->addr),
+					 skb_headlen(skb),
+					 DMA_TO_DEVICE);
+
+			for (i = 0; i < nr_frags; i++) {
+				skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+				tx_bdp = greth->tx_bd_base + greth->tx_last;
+
+				dma_unmap_page(greth->dev,
+					       greth_read_bd(&tx_bdp->addr),
+					       frag->size,
+					       DMA_TO_DEVICE);
+
+				greth->tx_last = NEXT_TX(greth->tx_last);
+			}
+			greth->tx_free += nr_frags+1;
+			dev_kfree_skb(skb);
+		}
+
+
+	} else { /* 10/100 Mbps MAC */
+
+		for (i = 0; i < GRETH_RXBD_NUM; i++, rx_bdp++) {
+			kfree(greth->rx_bufs[i]);
+			dma_unmap_single(greth->dev,
+					 greth_read_bd(&rx_bdp->addr),
+					 MAX_FRAME_SIZE,
+					 DMA_FROM_DEVICE);
+		}
+		for (i = 0; i < GRETH_TXBD_NUM; i++, tx_bdp++) {
+			kfree(greth->tx_bufs[i]);
+			dma_unmap_single(greth->dev,
+					 greth_read_bd(&tx_bdp->addr),
+					 MAX_FRAME_SIZE,
+					 DMA_TO_DEVICE);
+		}
+	}
+}
+
+static int greth_init_rings(struct greth_private *greth)
+{
+	struct sk_buff *skb;
+	struct greth_bd *rx_bd, *tx_bd;
+	u32 dma_addr;
+	int i;
+
+	rx_bd = greth->rx_bd_base;
+	tx_bd = greth->tx_bd_base;
+
+	/* Initialize descriptor rings and buffers */
+	if (greth->gbit_mac) {
+
+		for (i = 0; i < GRETH_RXBD_NUM; i++) {
+			skb = netdev_alloc_skb(greth->netdev, MAX_FRAME_SIZE+NET_IP_ALIGN);
+			if (skb == NULL) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Error allocating DMA ring.\n");
+				goto cleanup;
+			}
+			skb_reserve(skb, NET_IP_ALIGN);
+			dma_addr = dma_map_single(greth->dev,
+						  skb->data,
+						  MAX_FRAME_SIZE+NET_IP_ALIGN,
+						  DMA_FROM_DEVICE);
+
+			if (dma_mapping_error(greth->dev, dma_addr)) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Could not create initial DMA mapping\n");
+				goto cleanup;
+			}
+			greth->rx_skbuff[i] = skb;
+			greth_write_bd(&rx_bd[i].addr, dma_addr);
+			greth_write_bd(&rx_bd[i].stat, GRETH_BD_EN | GRETH_BD_IE);
+		}
+
+	} else {
+
+		/* 10/100 MAC uses a fixed set of buffers and copy to/from SKBs */
+		for (i = 0; i < GRETH_RXBD_NUM; i++) {
+
+			greth->rx_bufs[i] = kmalloc(MAX_FRAME_SIZE, GFP_KERNEL);
+
+			if (greth->rx_bufs[i] == NULL) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Error allocating DMA ring.\n");
+				goto cleanup;
+			}
+
+			dma_addr = dma_map_single(greth->dev,
+						  greth->rx_bufs[i],
+						  MAX_FRAME_SIZE,
+						  DMA_FROM_DEVICE);
+
+			if (dma_mapping_error(greth->dev, dma_addr)) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Could not create initial DMA mapping\n");
+				goto cleanup;
+			}
+			greth_write_bd(&rx_bd[i].addr, dma_addr);
+			greth_write_bd(&rx_bd[i].stat, GRETH_BD_EN | GRETH_BD_IE);
+		}
+		for (i = 0; i < GRETH_TXBD_NUM; i++) {
+
+			greth->tx_bufs[i] = kmalloc(MAX_FRAME_SIZE, GFP_KERNEL);
+
+			if (greth->tx_bufs[i] == NULL) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Error allocating DMA ring.\n");
+				goto cleanup;
+			}
+
+			dma_addr = dma_map_single(greth->dev,
+						  greth->tx_bufs[i],
+						  MAX_FRAME_SIZE,
+						  DMA_TO_DEVICE);
+
+			if (dma_mapping_error(greth->dev, dma_addr)) {
+				if (netif_msg_ifup(greth))
+					dev_err(greth->dev, "Could not create initial DMA mapping\n");
+				goto cleanup;
+			}
+			greth_write_bd(&tx_bd[i].addr, dma_addr);
+			greth_write_bd(&tx_bd[i].stat, 0);
+		}
+	}
+	greth_write_bd(&rx_bd[GRETH_RXBD_NUM - 1].stat,
+		       greth_read_bd(&rx_bd[GRETH_RXBD_NUM - 1].stat) | GRETH_BD_WR);
+
+	/* Initialize pointers. */
+	greth->rx_cur = 0;
+	greth->tx_next = 0;
+	greth->tx_last = 0;
+	greth->tx_free = GRETH_TXBD_NUM;
+
+	/* Initialize descriptor base address */
+	GRETH_REGSAVE(greth->regs->tx_desc_p, greth->tx_bd_base_phys);
+	GRETH_REGSAVE(greth->regs->rx_desc_p, greth->rx_bd_base_phys);
+
+	return 0;
+
+cleanup:
+	greth_clean_rings(greth);
+	return -ENOMEM;
+}
+
+static int greth_open(struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	int err;
+
+	err = greth_init_rings(greth);
+	if (err) {
+		if (netif_msg_ifup(greth))
+			dev_err(&dev->dev, "Could not allocate memory for DMA rings\n");
+		return err;
+	}
+
+	err = request_irq(greth->irq, greth_interrupt, 0, "eth", (void *) dev);
+	if (err) {
+		if (netif_msg_ifup(greth))
+			dev_err(&dev->dev, "Could not allocate interrupt %d\n", dev->irq);
+		greth_clean_rings(greth);
+		return err;
+	}
+
+	if (netif_msg_ifup(greth))
+		dev_dbg(&dev->dev, " starting queue\n");
+	netif_start_queue(dev);
+
+	napi_enable(&greth->napi);
+
+	greth_enable_irqs(greth);
+	greth_enable_tx(greth);
+	greth_enable_rx(greth);
+	return 0;
+
+}
+
+static int greth_close(struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+
+	napi_disable(&greth->napi);
+
+	greth_disable_tx(greth);
+
+	netif_stop_queue(dev);
+
+	free_irq(greth->irq, (void *) dev);
+
+	greth_clean_rings(greth);
+
+	return 0;
+}
+
+static int greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	struct greth_bd *bdp;
+	int err = NETDEV_TX_OK;
+	u32 status, dma_addr;
+
+	bdp = greth->tx_bd_base + greth->tx_next;
+
+	if (unlikely(greth->tx_free <= 0)) {
+		netif_stop_queue(dev);
+		err = NETDEV_TX_BUSY;
+		goto out;
+	}
+
+	if (netif_msg_pktdata(greth))
+		greth_print_tx_packet(skb);
+
+
+	if (unlikely(skb->len > MAX_FRAME_SIZE)) {
+		greth->stats.tx_errors++;
+		goto out;
+	}
+
+	dma_addr = greth_read_bd(&bdp->addr);
+
+	memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
+
+	dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
+
+
+	status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
+
+	/* Wrap around descriptor ring */
+	if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
+		status |= GRETH_BD_WR;
+	}
+
+	greth->tx_next = NEXT_TX(greth->tx_next);
+	greth->tx_free--;
+
+	/* No more descriptors */
+	if (unlikely(greth->tx_free == 0)) {
+
+		/* Free transmitted descriptors */
+		greth_clean_tx(dev);
+
+		/* If nothing was cleaned, stop queue & wait for irq */
+		if (unlikely(greth->tx_free == 0)) {
+			status |= GRETH_BD_IE;
+			netif_stop_queue(dev);
+		}
+	}
+
+	/* Write descriptor control word and enable transmission */
+	greth_write_bd(&bdp->stat, status);
+	greth_enable_tx(greth);
+
+out:
+	dev_kfree_skb(skb);
+	return err;
+}
+
+
+static int greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	struct greth_bd *bdp;
+	u32 status = 0, dma_addr;
+	int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+
+	if (greth->tx_free < nr_frags + 1) {
+		netif_stop_queue(dev);
+		err = NETDEV_TX_BUSY;
+		goto out;
+	}
+
+	if (netif_msg_pktdata(greth))
+		greth_print_tx_packet(skb);
+
+	if (unlikely(skb->len > MAX_FRAME_SIZE)) {
+		greth->stats.tx_errors++;
+		goto out;
+	}
+
+	/* Save skb pointer. */
+	greth->tx_skbuff[greth->tx_next] = skb;
+
+	/* Linear buf */
+	if (nr_frags != 0)
+		status = GRETH_TXBD_MORE;
+
+	status |= GRETH_TXBD_CSALL;
+	status |= skb_headlen(skb) & GRETH_BD_LEN;
+	if (greth->tx_next == GRETH_TXBD_NUM_MASK)
+		status |= GRETH_BD_WR;
+
+
+	bdp = greth->tx_bd_base + greth->tx_next;
+	greth_write_bd(&bdp->stat, status);
+	dma_addr = dma_map_single(greth->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+
+	if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
+		goto map_error;
+
+	greth_write_bd(&bdp->addr, dma_addr);
+
+	curr_tx = NEXT_TX(greth->tx_next);
+
+	/* Frags */
+	for (i = 0; i < nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+		greth->tx_skbuff[curr_tx] = NULL;
+		bdp = greth->tx_bd_base + curr_tx;
+
+		status = GRETH_TXBD_CSALL;
+		status |= frag->size & GRETH_BD_LEN;
+
+		/* Wrap around descriptor ring */
+		if (curr_tx == GRETH_TXBD_NUM_MASK)
+			status |= GRETH_BD_WR;
+
+		/* More fragments left */
+		if (i < nr_frags - 1)
+			status |= GRETH_TXBD_MORE;
+
+		/* ... last fragment, check if out of descriptors  */
+		else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
+
+			/* Enable interrupts and stop queue */
+			status |= GRETH_BD_IE;
+			netif_stop_queue(dev);
+		}
+
+		greth_write_bd(&bdp->stat, status);
+
+		dma_addr = dma_map_page(greth->dev,
+					frag->page,
+					frag->page_offset,
+					frag->size,
+					DMA_TO_DEVICE);
+
+		if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
+			goto frag_map_error;
+
+		greth_write_bd(&bdp->addr, dma_addr);
+
+		curr_tx = NEXT_TX(curr_tx);
+	}
+
+	wmb();
+
+	/* Enable the descriptors that we configured ...  */
+	for (i = 0; i < nr_frags + 1; i++) {
+		bdp = greth->tx_bd_base + greth->tx_next;
+		greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
+		greth->tx_next = NEXT_TX(greth->tx_next);
+		greth->tx_free--;
+	}
+
+	greth_enable_tx(greth);
+
+	return NETDEV_TX_OK;
+
+frag_map_error:
+	/* Unmap SKB mappings that succeeded */
+	for (i = 0; greth->tx_next + i != curr_tx; i++) {
+		bdp = greth->tx_bd_base + greth->tx_next + i;
+		dma_unmap_single(greth->dev,
+				 greth_read_bd(&bdp->addr),
+				 greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
+				 DMA_TO_DEVICE);
+	}
+map_error:
+	if (net_ratelimit())
+		dev_warn(greth->dev, "Could not create TX DMA mapping\n");
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+
+out:
+	return err;
+}
+
+
+static irqreturn_t greth_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct greth_private *greth;
+	u32 status;
+	irqreturn_t retval = IRQ_NONE;
+
+	greth = netdev_priv(dev);
+
+	spin_lock(&greth->devlock);
+
+	/* Get the interrupt events that caused us to be here. */
+	status = GRETH_REGLOAD(greth->regs->status);
+
+	/* Handle rx and tx interrupts through poll */
+	if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
+
+		/* Clear interrupt status */
+		GRETH_REGORIN(greth->regs->status,
+			      status & (GRETH_INT_RX | GRETH_INT_TX));
+
+		retval = IRQ_HANDLED;
+
+		/* Disable interrupts and schedule poll() */
+		greth_disable_irqs(greth);
+		napi_schedule(&greth->napi);
+	}
+
+	mmiowb();
+	spin_unlock(&greth->devlock);
+
+	return retval;
+}
+
+static void greth_clean_tx(struct net_device *dev)
+{
+	struct greth_private *greth;
+	struct greth_bd *bdp;
+	u32 stat;
+
+	greth = netdev_priv(dev);
+
+	while (1) {
+		bdp = greth->tx_bd_base + greth->tx_last;
+		stat = greth_read_bd(&bdp->stat);
+
+		if (unlikely(stat & GRETH_BD_EN))
+			break;
+
+		if (greth->tx_free == GRETH_TXBD_NUM)
+			break;
+
+		/* Check status for errors */
+		if (unlikely(stat & GRETH_TXBD_STATUS)) {
+			greth->stats.tx_errors++;
+			if (stat & GRETH_TXBD_ERR_AL)
+				greth->stats.tx_aborted_errors++;
+			if (stat & GRETH_TXBD_ERR_UE)
+				greth->stats.tx_fifo_errors++;
+		}
+		greth->stats.tx_packets++;
+		greth->tx_last = NEXT_TX(greth->tx_last);
+		greth->tx_free++;
+	}
+
+	if (greth->tx_free > 0) {
+		netif_wake_queue(dev);
+	}
+
+}
+
+static inline void greth_update_tx_stats(struct greth_private *greth, u32 stat)
+{
+	/* Check status for errors */
+	if (unlikely(stat & GRETH_TXBD_STATUS)) {
+		greth->stats.tx_errors++;
+		if (stat & GRETH_TXBD_ERR_AL)
+			greth->stats.tx_aborted_errors++;
+		if (stat & GRETH_TXBD_ERR_UE)
+			greth->stats.tx_fifo_errors++;
+		if (stat & GRETH_TXBD_ERR_LC)
+			greth->stats.tx_aborted_errors++;
+	}
+	greth->stats.tx_packets++;
+}
+
+static void greth_clean_tx_gbit(struct net_device *dev)
+{
+	struct greth_private *greth;
+	struct greth_bd *bdp, *bdp_last_frag;
+	struct sk_buff *skb;
+	u32 stat;
+	int nr_frags, i;
+
+	greth = netdev_priv(dev);
+
+	while (greth->tx_free < GRETH_TXBD_NUM) {
+
+		skb = greth->tx_skbuff[greth->tx_last];
+
+		nr_frags = skb_shinfo(skb)->nr_frags;
+
+		/* We only clean fully completed SKBs */
+		bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
+		stat = bdp_last_frag->stat;
+
+		if (stat & GRETH_BD_EN)
+			break;
+
+		greth->tx_skbuff[greth->tx_last] = NULL;
+
+		greth_update_tx_stats(greth, stat);
+
+		bdp = greth->tx_bd_base + greth->tx_last;
+
+		greth->tx_last = NEXT_TX(greth->tx_last);
+
+		dma_unmap_single(greth->dev,
+				 greth_read_bd(&bdp->addr),
+				 skb_headlen(skb),
+				 DMA_TO_DEVICE);
+
+		for (i = 0; i < nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			bdp = greth->tx_bd_base + greth->tx_last;
+
+			dma_unmap_page(greth->dev,
+				       greth_read_bd(&bdp->addr),
+				       frag->size,
+				       DMA_TO_DEVICE);
+
+			greth->tx_last = NEXT_TX(greth->tx_last);
+		}
+		greth->tx_free += nr_frags+1;
+		dev_kfree_skb(skb);
+	}
+	if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
+		netif_wake_queue(dev);
+	}
+}
+
+static int greth_pending_packets(struct greth_private *greth)
+{
+	struct greth_bd *bdp;
+	u32 status;
+	bdp = greth->rx_bd_base + greth->rx_cur;
+	status = greth_read_bd(&bdp->stat);
+	if (status & GRETH_BD_EN)
+		return 0;
+	else
+		return 1;
+}
+
+static int greth_rx(struct net_device *dev, int limit)
+{
+	struct greth_private *greth;
+	struct greth_bd *bdp;
+	struct sk_buff *skb;
+	int pkt_len;
+	int bad, count;
+	u32 status, dma_addr;
+
+	greth = netdev_priv(dev);
+
+	for (count = 0; count < limit; ++count) {
+
+		bdp = greth->rx_bd_base + greth->rx_cur;
+		status = greth_read_bd(&bdp->stat);
+		dma_addr = greth_read_bd(&bdp->addr);
+		bad = 0;
+
+		if (unlikely(status & GRETH_BD_EN)) {
+			break;
+		}
+
+		/* Check status for errors. */
+		if (unlikely(status & GRETH_RXBD_STATUS)) {
+			if (status & GRETH_RXBD_ERR_FT) {
+				greth->stats.rx_length_errors++;
+				bad = 1;
+			}
+			if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) {
+				greth->stats.rx_frame_errors++;
+				bad = 1;
+			}
+			if (status & GRETH_RXBD_ERR_CRC) {
+				greth->stats.rx_crc_errors++;
+				bad = 1;
+			}
+		}
+		if (unlikely(bad)) {
+			greth->stats.rx_errors++;
+
+		} else {
+
+			pkt_len = status & GRETH_BD_LEN;
+
+			skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN);
+
+			if (unlikely(skb == NULL)) {
+
+				if (net_ratelimit())
+					dev_warn(&dev->dev, "low on memory - " "packet dropped\n");
+
+				greth->stats.rx_dropped++;
+
+			} else {
+				skb_reserve(skb, NET_IP_ALIGN);
+				skb->dev = dev;
+
+				dma_sync_single_for_cpu(greth->dev,
+							dma_addr,
+							pkt_len,
+							DMA_FROM_DEVICE);
+
+				if (netif_msg_pktdata(greth))
+					greth_print_rx_packet(phys_to_virt(dma_addr), pkt_len);
+
+				memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len);
+
+				skb->protocol = eth_type_trans(skb, dev);
+				greth->stats.rx_packets++;
+				netif_receive_skb(skb);
+			}
+		}
+
+		status = GRETH_BD_EN | GRETH_BD_IE;
+		if (greth->rx_cur == GRETH_RXBD_NUM_MASK) {
+			status |= GRETH_BD_WR;
+		}
+
+		wmb();
+		greth_write_bd(&bdp->stat, status);
+
+		dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
+
+		greth_enable_rx(greth);
+
+		greth->rx_cur = NEXT_RX(greth->rx_cur);
+	}
+
+	return count;
+}
+
+static inline int hw_checksummed(u32 status)
+{
+
+	if (status & GRETH_RXBD_IP_FRAG)
+		return 0;
+
+	if (status & GRETH_RXBD_IP && status & GRETH_RXBD_IP_CSERR)
+		return 0;
+
+	if (status & GRETH_RXBD_UDP && status & GRETH_RXBD_UDP_CSERR)
+		return 0;
+
+	if (status & GRETH_RXBD_TCP && status & GRETH_RXBD_TCP_CSERR)
+		return 0;
+
+	return 1;
+}
+
+static int greth_rx_gbit(struct net_device *dev, int limit)
+{
+	struct greth_private *greth;
+	struct greth_bd *bdp;
+	struct sk_buff *skb, *newskb;
+	int pkt_len;
+	int bad, count = 0;
+	u32 status, dma_addr;
+
+	greth = netdev_priv(dev);
+
+	for (count = 0; count < limit; ++count) {
+
+		bdp = greth->rx_bd_base + greth->rx_cur;
+		skb = greth->rx_skbuff[greth->rx_cur];
+		status = greth_read_bd(&bdp->stat);
+		bad = 0;
+
+		if (status & GRETH_BD_EN)
+			break;
+
+		/* Check status for errors. */
+		if (unlikely(status & GRETH_RXBD_STATUS)) {
+
+			if (status & GRETH_RXBD_ERR_FT) {
+				greth->stats.rx_length_errors++;
+				bad = 1;
+			} else if (status &
+				   (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE | GRETH_RXBD_ERR_LE)) {
+				greth->stats.rx_frame_errors++;
+				bad = 1;
+			} else if (status & GRETH_RXBD_ERR_CRC) {
+				greth->stats.rx_crc_errors++;
+				bad = 1;
+			}
+		}
+
+		/* Allocate new skb to replace current */
+		newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
+
+		if (!bad && newskb) {
+			skb_reserve(newskb, NET_IP_ALIGN);
+
+			dma_addr = dma_map_single(greth->dev,
+						      newskb->data,
+						      MAX_FRAME_SIZE + NET_IP_ALIGN,
+						      DMA_FROM_DEVICE);
+
+			if (!dma_mapping_error(greth->dev, dma_addr)) {
+				/* Process the incoming frame. */
+				pkt_len = status & GRETH_BD_LEN;
+
+				dma_unmap_single(greth->dev,
+						 greth_read_bd(&bdp->addr),
+						 MAX_FRAME_SIZE + NET_IP_ALIGN,
+						 DMA_FROM_DEVICE);
+
+				if (netif_msg_pktdata(greth))
+					greth_print_rx_packet(phys_to_virt(greth_read_bd(&bdp->addr)), pkt_len);
+
+				skb_put(skb, pkt_len);
+
+				if (hw_checksummed(status))
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+				else
+					skb->ip_summed = CHECKSUM_NONE;
+
+				skb->dev = dev;
+				skb->protocol = eth_type_trans(skb, dev);
+				greth->stats.rx_packets++;
+				netif_receive_skb(skb);
+
+				greth->rx_skbuff[greth->rx_cur] = newskb;
+				greth_write_bd(&bdp->addr, dma_addr);
+			} else {
+				if (net_ratelimit())
+					dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
+				dev_kfree_skb(newskb);
+				greth->stats.rx_dropped++;
+			}
+		} else {
+			if (net_ratelimit())
+				dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
+			greth->stats.rx_dropped++;
+		}
+
+		status = GRETH_BD_EN | GRETH_BD_IE;
+		if (greth->rx_cur == GRETH_RXBD_NUM_MASK) {
+			status |= GRETH_BD_WR;
+		}
+
+		wmb();
+		greth_write_bd(&bdp->stat, status);
+		greth_enable_rx(greth);
+		greth->rx_cur = NEXT_RX(greth->rx_cur);
+	}
+
+	return count;
+
+}
+
+static int greth_poll(struct napi_struct *napi, int budget)
+{
+	struct greth_private *greth;
+	int work_done = 0;
+	greth = container_of(napi, struct greth_private, napi);
+
+	if (greth->gbit_mac) {
+		greth_clean_tx_gbit(greth->netdev);
+	} else {
+		greth_clean_tx(greth->netdev);
+	}
+
+restart_poll:
+	if (greth->gbit_mac) {
+		work_done += greth_rx_gbit(greth->netdev, budget - work_done);
+	} else {
+		work_done += greth_rx(greth->netdev, budget - work_done);
+	}
+
+	if (work_done < budget) {
+
+		napi_complete(napi);
+
+		if (greth_pending_packets(greth)) {
+			napi_reschedule(napi);
+			goto restart_poll;
+		}
+	}
+
+	greth_enable_irqs(greth);
+	return work_done;
+}
+
+static struct net_device_stats *greth_get_stats(struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	return &greth->stats;
+}
+
+static int greth_set_mac_add(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct greth_private *greth;
+	struct greth_regs *regs;
+
+	greth = (struct greth_private *) netdev_priv(dev);
+	regs = (struct greth_regs *) greth->regs;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	GRETH_REGSAVE(regs->esa_msb, addr->sa_data[0] << 8 | addr->sa_data[1]);
+	GRETH_REGSAVE(regs->esa_lsb,
+		      addr->sa_data[2] << 24 | addr->
+		      sa_data[3] << 16 | addr->sa_data[4] << 8 | addr->sa_data[5]);
+	return 0;
+}
+
+static u32 greth_hash_get_index(__u8 *addr)
+{
+	return (ether_crc(6, addr)) & 0x3F;
+}
+
+static void greth_set_hash_filter(struct net_device *dev)
+{
+	struct dev_mc_list *curr;
+	struct greth_private *greth = (struct greth_private *) netdev_priv(dev);
+	struct greth_regs *regs = (struct greth_regs *) greth->regs;
+	u32 mc_filter[2];
+	unsigned int i, bitnr;
+
+	mc_filter[0] = mc_filter[1] = 0;
+
+	curr = dev->mc_list;
+
+	for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
+
+		if (!curr)
+			break;	/* unexpected end of list */
+
+		bitnr = greth_hash_get_index(curr->dmi_addr);
+		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+	}
+
+	GRETH_REGSAVE(regs->hash_msb, mc_filter[1]);
+	GRETH_REGSAVE(regs->hash_lsb, mc_filter[0]);
+}
+
+static void greth_set_multicast_list(struct net_device *dev)
+{
+	int cfg;
+	struct greth_private *greth = netdev_priv(dev);
+	struct greth_regs *regs = (struct greth_regs *) greth->regs;
+
+	cfg = GRETH_REGLOAD(regs->control);
+	if (dev->flags & IFF_PROMISC)
+		cfg |= GRETH_CTRL_PR;
+	else
+		cfg &= ~GRETH_CTRL_PR;
+
+	if (greth->multicast) {
+		if (dev->flags & IFF_ALLMULTI) {
+			GRETH_REGSAVE(regs->hash_msb, -1);
+			GRETH_REGSAVE(regs->hash_lsb, -1);
+			cfg |= GRETH_CTRL_MCEN;
+			GRETH_REGSAVE(regs->control, cfg);
+			return;
+		}
+
+		if (dev->mc_count == 0) {
+			cfg &= ~GRETH_CTRL_MCEN;
+			GRETH_REGSAVE(regs->control, cfg);
+			return;
+		}
+
+		/* Setup multicast filter */
+		greth_set_hash_filter(dev);
+		cfg |= GRETH_CTRL_MCEN;
+	}
+	GRETH_REGSAVE(regs->control, cfg);
+}
+
+static struct net_device_ops greth_netdev_ops = {
+	.ndo_open = greth_open,
+	.ndo_stop = greth_close,
+	.ndo_start_xmit = greth_start_xmit,
+	.ndo_set_mac_address = greth_set_mac_add,
+	.ndo_get_stats = greth_get_stats,
+};
+
+static struct net_device_ops greth_gbit_netdev_ops = {
+	.ndo_open = greth_open,
+	.ndo_stop = greth_close,
+	.ndo_start_xmit = greth_start_xmit_gbit,
+	.ndo_set_mac_address = greth_set_mac_add,
+	.ndo_get_stats = greth_get_stats,
+};
+
+/* Wait for a register change with a timeout, jiffies used has time reference */
+#define wait_loop(wait_statement, timeout, label_on_timeout, arg_on_timeout) \
+	{ \
+		unsigned long _timeout = jiffies + HZ/100*timeout; \
+		while (wait_statement) { \
+			if (time_after(jiffies, _timeout)) { \
+				arg_on_timeout; \
+goto label_on_timeout; \
+			} \
+		} \
+	}
+
+static int greth_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+	struct greth_private *greth = bus->priv;
+	int data, err = 0;
+
+	wait_loop((GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_BUSY), 4, out, err = -EBUSY);
+
+	GRETH_REGSAVE(greth->regs->mdio, ((phy & 0x1F) << 11) | ((reg & 0x1F) << 6) | 2);
+
+	wait_loop((GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_BUSY), 4, out, err = -EBUSY);
+
+	if (!(GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_NVALID)) {
+		data = (GRETH_REGLOAD(greth->regs->mdio) >> 16) & 0xFFFF;
+		return data;
+
+	} else {
+		return -1;
+	}
+out:
+	return err;
+}
+
+
+static int greth_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+	struct greth_private *greth = bus->priv;
+	int err = 0;
+
+	wait_loop((GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_BUSY), 4, out, err = -EBUSY);
+
+	GRETH_REGSAVE(greth->regs->mdio,
+		      ((val & 0xFFFF) << 16) | ((phy & 0x1F) << 11) | ((reg & 0x1F) << 6) | 1);
+
+	wait_loop((GRETH_REGLOAD(greth->regs->mdio) & GRETH_MII_BUSY), 4, out, err = -EBUSY);
+
+	return 0;
+
+out:
+	return err;
+}
+
+static int greth_mdio_reset(struct mii_bus *bus)
+{
+	return 0;
+}
+
+static void greth_link_change(struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	struct phy_device *phydev = greth->phy;
+	unsigned long flags;
+
+	int status_change = 0;
+
+	spin_lock_irqsave(&greth->devlock, flags);
+
+	if (phydev->link) {
+
+		if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
+
+			GRETH_REGANDIN(greth->regs->control,
+				       ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
+
+			if (phydev->duplex)
+				GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
+
+			if (phydev->speed == SPEED_100) {
+
+				GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
+			}
+
+			else if (phydev->speed == SPEED_1000)
+				GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
+
+			greth->speed = phydev->speed;
+			greth->duplex = phydev->duplex;
+			status_change = 1;
+		}
+	}
+
+	if (phydev->link != greth->link) {
+		if (!phydev->link) {
+			greth->speed = 0;
+			greth->duplex = -1;
+		}
+		greth->link = phydev->link;
+
+		status_change = 1;
+	}
+
+	spin_unlock_irqrestore(&greth->devlock, flags);
+
+	if (status_change) {
+		if (phydev->link)
+			pr_debug("%s: link up (%d/%s)\n",
+				dev->name, phydev->speed,
+				DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+		else
+			pr_debug("%s: link down\n", dev->name);
+	}
+}
+
+static int greth_mdio_probe(struct net_device *dev)
+{
+	struct greth_private *greth = netdev_priv(dev);
+	struct phy_device *phy = NULL;
+	u32 interface;
+	int i;
+
+	/* Find the first PHY */
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		if (greth->mdio->phy_map[i]) {
+			phy = greth->mdio->phy_map[i];
+			break;
+		}
+	}
+	if (!phy) {
+		if (netif_msg_probe(greth))
+			dev_err(&dev->dev, "no PHY found\n");
+		return -ENXIO;
+	}
+
+	if (greth->gbit_mac)
+		interface = PHY_INTERFACE_MODE_GMII;
+	else
+		interface = PHY_INTERFACE_MODE_MII;
+
+	phy = phy_connect(dev, dev_name(&phy->dev), &greth_link_change, 0, interface);
+
+	if (greth->gbit_mac)
+		phy->supported &= PHY_GBIT_FEATURES;
+	else
+		phy->supported &= PHY_BASIC_FEATURES;
+
+	phy->advertising = phy->supported;
+
+	if (IS_ERR(phy)) {
+		if (netif_msg_ifup(greth))
+			dev_err(&dev->dev, "could not attach to PHY\n");
+		return PTR_ERR(phy);
+	}
+
+	greth->link = 0;
+	greth->speed = 0;
+	greth->duplex = -1;
+	greth->phy = phy;
+
+	return 0;
+}
+
+static inline int phy_aneg_done(struct phy_device *phydev)
+{
+	int retval;
+
+	retval = phy_read(phydev, MII_BMSR);
+
+	return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+
+static int greth_mdio_init(struct greth_private *greth)
+{
+	int ret, phy;
+	unsigned long timeout;
+
+	greth->mdio = mdiobus_alloc();
+	if (!greth->mdio) {
+		return -ENOMEM;
+	}
+
+	greth->mdio->name = "greth-mdio";
+	snprintf(greth->mdio->id, MII_BUS_ID_SIZE, "%s-%d", greth->mdio->name, greth->irq);
+	greth->mdio->read = greth_mdio_read;
+	greth->mdio->write = greth_mdio_write;
+	greth->mdio->reset = greth_mdio_reset;
+	greth->mdio->priv = greth;
+
+	greth->mdio->irq = greth->mdio_irqs;
+
+	for (phy = 0; phy < PHY_MAX_ADDR; phy++)
+		greth->mdio->irq[phy] = PHY_POLL;
+
+	ret = mdiobus_register(greth->mdio);
+	if (ret) {
+		goto error;
+	}
+
+	ret = greth_mdio_probe(greth->netdev);
+	if (ret) {
+		if (netif_msg_probe(greth))
+			dev_err(&greth->netdev->dev, "failed to probe MDIO bus\n");
+		goto unreg_mdio;
+	}
+
+	phy_start(greth->phy);
+
+	/* If we have Ethernet debug link make autoneg happen right away */
+	if (greth->edcl) {
+		phy_start_aneg(greth->phy);
+		timeout = jiffies + 6*HZ;
+		while (!phy_aneg_done(greth->phy) && time_before(jiffies, timeout)) {
+		}
+		genphy_read_status(greth->phy);
+		greth_link_change(greth->netdev);
+	}
+
+	return 0;
+
+unreg_mdio:
+	mdiobus_unregister(greth->mdio);
+error:
+	mdiobus_free(greth->mdio);
+	return ret;
+}
+
+/* Initialize the GRETH MAC */
+static int __devinit greth_of_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+	struct net_device *dev;
+	struct net_device_ops *ops;
+	struct greth_private *greth;
+	struct greth_regs *regs;
+
+	int i;
+	int err;
+	int tmp;
+	unsigned long timeout;
+
+	unsigned int *irqs;
+	int irq;
+	struct amba_prom_registers *prom_regs;
+	unsigned int addr;
+
+	irqs = (int *) of_get_property(ofdev->node, "interrupts", NULL);
+	prom_regs = (struct amba_prom_registers *) of_get_property(ofdev->node, "reg", NULL);
+	if (!irqs || !prom_regs)
+		return -ENODEV;
+
+	addr = prom_regs->phys_addr;
+	irq = *irqs;
+
+	dev = alloc_etherdev(sizeof(struct greth_private));
+
+	if (dev == NULL)
+		return -ENOMEM;
+
+	greth = netdev_priv(dev);
+	greth->netdev = dev;
+	greth->dev = &ofdev->dev;
+
+	if (greth_debug > 0)
+		greth->msg_enable = greth_debug;
+	else
+		greth->msg_enable = GRETH_DEF_MSG_ENABLE;
+
+	spin_lock_init(&greth->devlock);
+
+	if (!request_mem_region(addr, 0x100, "grlib-greth")) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "Couldn't lock memory region at %x\n", addr);
+		err = -EBUSY;
+		goto error1;
+	}
+
+	greth->regs = (struct greth_regs *) ioremap(addr, sizeof(struct greth_regs));
+
+	if (greth->regs == NULL) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "Ioremap failure.\n");
+		err = -EIO;
+		goto error2;
+	}
+
+	regs = (struct greth_regs *) greth->regs;
+	greth->irq = irq;
+
+	dev_set_drvdata(greth->dev, dev);
+	SET_NETDEV_DEV(dev, greth->dev);
+
+	/* Reset the controller. */
+	GRETH_REGSAVE(regs->control, GRETH_RESET);
+
+	/* Wait for MAC to reset itself */
+	timeout = jiffies + HZ/100;
+	while (GRETH_REGLOAD(regs->control) & GRETH_RESET) {
+		if (time_after(jiffies, timeout)) {
+			err = -EIO;
+			if (netif_msg_probe(greth))
+				dev_err(greth->dev, "timeout when waiting for reset.\n");
+			goto error3;
+		}
+	}
+
+	/* Get default PHY address  */
+	greth->phyaddr = (GRETH_REGLOAD(regs->mdio) >> 11) & 0x1F;
+
+	/* Check if we have GBIT capable MAC */
+	tmp = GRETH_REGLOAD(regs->control);
+	greth->gbit_mac = (tmp >> 27) & 1;
+
+	/* Check for multicast capability */
+	greth->multicast = (tmp >> 25) & 1;
+
+	greth->edcl = (tmp >> 31) & 1;
+
+	/* If we have EDCL we disable the EDCL speed-duplex FSM so
+	 * it doesn't interfere with the software */
+	if (greth->edcl != 0)
+		GRETH_REGORIN(regs->control, GRETH_CTRL_DISDUPLEX);
+
+	/* Check if MAC can handle MDIO interrupts */
+	greth->mdio_int_en = (tmp >> 26) & 1;
+
+	err = greth_mdio_init(greth);
+	if (err) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "failed to register MDIO bus\n");
+		goto error3;
+	}
+
+	/* Allocate TX descriptor ring in coherent memory */
+	greth->tx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
+								   1024,
+								   &greth->tx_bd_base_phys,
+								   GFP_KERNEL);
+
+	if (!greth->tx_bd_base) {
+		if (netif_msg_probe(greth))
+			dev_err(&dev->dev, "could not allocate descriptor memory.\n");
+		err = -ENOMEM;
+		goto error4;
+	}
+
+	memset(greth->tx_bd_base, 0, 1024);
+
+	/* Allocate RX descriptor ring in coherent memory */
+	greth->rx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
+								   1024,
+								   &greth->rx_bd_base_phys,
+								   GFP_KERNEL);
+
+	if (!greth->rx_bd_base) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "could not allocate descriptor memory.\n");
+		err = -ENOMEM;
+		goto error5;
+	}
+
+	memset(greth->rx_bd_base, 0, 1024);
+
+	/* Get MAC address from: module param, OF property or ID prom */
+	for (i = 0; i < 6; i++) {
+		if (macaddr[i] != 0)
+			break;
+	}
+	if (i == 6) {
+		const unsigned char *addr;
+		int len;
+		addr = of_get_property(ofdev->node, "local-mac-address", &len);
+		if (addr != NULL && len == 6) {
+			for (i = 0; i < 6; i++)
+				macaddr[i] = (unsigned int) addr[i];
+		} else {
+#ifdef CONFIG_SPARC
+			for (i = 0; i < 6; i++)
+				macaddr[i] = (unsigned int) idprom->id_ethaddr[i];
+#endif
+		}
+	}
+
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = macaddr[i];
+
+	macaddr[5]++;
+
+	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "no valid ethernet address, aborting.\n");
+		err = -EINVAL;
+		goto error6;
+	}
+
+	GRETH_REGSAVE(regs->esa_msb, dev->dev_addr[0] << 8 | dev->dev_addr[1]);
+	GRETH_REGSAVE(regs->esa_lsb, dev->dev_addr[2] << 24 | dev->dev_addr[3] << 16 |
+		      dev->dev_addr[4] << 8 | dev->dev_addr[5]);
+
+	/* Clear all pending interrupts except PHY irq */
+	GRETH_REGSAVE(regs->status, 0xFF);
+
+	dev->base_addr = (unsigned long) addr;
+
+	if (greth->gbit_mac) {
+		dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+		ops = &greth_gbit_netdev_ops;
+	} else {
+		ops = &greth_netdev_ops;
+	}
+
+	if (greth->multicast) {
+		ops->ndo_set_multicast_list = greth_set_multicast_list;
+		dev->flags |= IFF_MULTICAST;
+	} else {
+		dev->flags &= ~IFF_MULTICAST;
+	}
+
+	dev->netdev_ops = ops;
+
+	if (register_netdev(dev)) {
+		if (netif_msg_probe(greth))
+			dev_err(greth->dev, "netdevice registration failed.\n");
+		err = -ENOMEM;
+		goto error6;
+	}
+
+	/* setup NAPI */
+	memset(&greth->napi, 0, sizeof(greth->napi));
+	netif_napi_add(dev, &greth->napi, greth_poll, 64);
+
+	return 0;
+
+error6:
+	dma_free_coherent(greth->dev, 1024, greth->rx_bd_base, greth->rx_bd_base_phys);
+error5:
+	dma_free_coherent(greth->dev, 1024, greth->tx_bd_base, greth->tx_bd_base_phys);
+error4:
+	mdiobus_unregister(greth->mdio);
+error3:
+	iounmap(greth->regs);
+error2:
+	release_mem_region(addr, 0x100);
+error1:
+	free_netdev(dev);
+	return err;
+}
+
+static int __devexit greth_of_remove(struct of_device *of_dev)
+{
+	struct net_device *ndev = dev_get_drvdata(&of_dev->dev);
+	struct greth_private *greth = netdev_priv(ndev);
+
+	/* Free descriptor areas */
+	dma_free_coherent(&of_dev->dev, 1024, greth->rx_bd_base, greth->rx_bd_base_phys);
+
+	dma_free_coherent(&of_dev->dev, 1024, greth->tx_bd_base, greth->tx_bd_base_phys);
+
+	release_mem_region(ndev->base_addr, 0x100);
+	dev_set_drvdata(&of_dev->dev, NULL);
+
+	if (greth->phy)
+		phy_stop(greth->phy);
+	mdiobus_unregister(greth->mdio);
+
+	unregister_netdev(ndev);
+	free_netdev(ndev);
+
+	iounmap(greth->regs);
+
+	return 0;
+}
+
+static struct of_device_id greth_of_match[] = {
+	{
+	 .name = "GAISLER_ETHMAC",
+	 },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, greth_of_match);
+
+static struct of_platform_driver greth_of_driver = {
+	.name = "grlib-greth",
+	.match_table = greth_of_match,
+	.probe = greth_of_probe,
+	.remove = __devexit_p(greth_of_remove),
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "grlib-greth",
+		   },
+};
+
+static int __init greth_init(void)
+{
+	return of_register_platform_driver(&greth_of_driver);
+}
+
+static void __exit greth_cleanup(void)
+{
+	of_unregister_platform_driver(&greth_of_driver);
+}
+
+module_init(greth_init);
+module_exit(greth_cleanup);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("Aeroflex Gaisler Ethernet MAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
new file mode 100644
index 0000000..7e820de
--- /dev/null
+++ b/drivers/net/greth.h
@@ -0,0 +1,149 @@
+#ifndef GRETH_H
+#define GRETH_H
+
+#include <linux/phy.h>
+
+/* Register bits and masks */
+#define GRETH_RESET 0x40
+#define GRETH_MII_BUSY 0x8
+#define GRETH_MII_NVALID 0x10
+
+#define GRETH_CTRL_FD         0x10
+#define GRETH_CTRL_PR         0x20
+#define GRETH_CTRL_SP         0x80
+#define GRETH_CTRL_GB         0x100
+#define GRETH_CTRL_PSTATIEN   0x400
+#define GRETH_CTRL_MCEN       0x800
+#define GRETH_CTRL_DISDUPLEX  0x1000
+#define GRETH_STATUS_PHYSTAT  0x100
+
+#define GRETH_BD_EN 0x800
+#define GRETH_BD_WR 0x1000
+#define GRETH_BD_IE 0x2000
+#define GRETH_BD_LEN 0x7FF
+
+#define GRETH_TXEN 0x1
+#define GRETH_INT_TX 0x8
+#define GRETH_TXI 0x4
+#define GRETH_TXBD_STATUS 0x0001C000
+#define GRETH_TXBD_MORE 0x20000
+#define GRETH_TXBD_IPCS 0x40000
+#define GRETH_TXBD_TCPCS 0x80000
+#define GRETH_TXBD_UDPCS 0x100000
+#define GRETH_TXBD_CSALL (GRETH_TXBD_IPCS | GRETH_TXBD_TCPCS | GRETH_TXBD_UDPCS)
+#define GRETH_TXBD_ERR_LC 0x10000
+#define GRETH_TXBD_ERR_UE 0x4000
+#define GRETH_TXBD_ERR_AL 0x8000
+
+#define GRETH_INT_RX         0x4
+#define GRETH_RXEN           0x2
+#define GRETH_RXI            0x8
+#define GRETH_RXBD_STATUS    0xFFFFC000
+#define GRETH_RXBD_ERR_AE    0x4000
+#define GRETH_RXBD_ERR_FT    0x8000
+#define GRETH_RXBD_ERR_CRC   0x10000
+#define GRETH_RXBD_ERR_OE    0x20000
+#define GRETH_RXBD_ERR_LE    0x40000
+#define GRETH_RXBD_IP        0x80000
+#define GRETH_RXBD_IP_CSERR  0x100000
+#define GRETH_RXBD_UDP       0x200000
+#define GRETH_RXBD_UDP_CSERR 0x400000
+#define GRETH_RXBD_TCP       0x800000
+#define GRETH_RXBD_TCP_CSERR 0x1000000
+#define GRETH_RXBD_IP_FRAG   0x2000000
+#define GRETH_RXBD_MCAST     0x4000000
+
+/* Descriptor parameters */
+#define GRETH_TXBD_NUM 128
+#define GRETH_TXBD_NUM_MASK (GRETH_TXBD_NUM-1)
+#define GRETH_TX_BUF_SIZE 2048
+#define GRETH_RXBD_NUM 128
+#define GRETH_RXBD_NUM_MASK (GRETH_RXBD_NUM-1)
+#define GRETH_RX_BUF_SIZE 2048
+
+/* Buffers per page */
+#define GRETH_RX_BUF_PPGAE	(PAGE_SIZE/GRETH_RX_BUF_SIZE)
+#define GRETH_TX_BUF_PPGAE	(PAGE_SIZE/GRETH_TX_BUF_SIZE)
+
+/* How many pages are needed for buffers */
+#define GRETH_RX_BUF_PAGE_NUM	(GRETH_RXBD_NUM/GRETH_RX_BUF_PPGAE)
+#define GRETH_TX_BUF_PAGE_NUM	(GRETH_TXBD_NUM/GRETH_TX_BUF_PPGAE)
+
+/* Buffer size.
+ * Gbit MAC uses tagged maximum frame size which is 1518 excluding CRC.
+ * Set to 1520 to make all buffers word aligned for non-gbit MAC.
+ */
+#define MAX_FRAME_SIZE		1520
+
+
+/* GRETH APB registers */
+struct greth_regs {
+	u32 control;
+	u32 status;
+	u32 esa_msb;
+	u32 esa_lsb;
+	u32 mdio;
+	u32 tx_desc_p;
+	u32 rx_desc_p;
+	u32 edclip;
+	u32 hash_msb;
+	u32 hash_lsb;
+};
+
+/* GRETH buffer descriptor */
+struct greth_bd {
+	u32 stat;
+	u32 addr;
+};
+
+struct greth_private {
+	struct sk_buff *rx_skbuff[GRETH_RXBD_NUM];
+	struct sk_buff *tx_skbuff[GRETH_TXBD_NUM];
+
+	unsigned char *tx_bufs[GRETH_TXBD_NUM];
+	unsigned char *rx_bufs[GRETH_RXBD_NUM];
+
+	u16 tx_next;
+	u16 tx_last;
+	u16 tx_free;
+	u16 rx_cur;
+
+	u8 phyaddr;
+	u8 multicast;
+	u8 gbit_mac;
+	u8 mdio_int_en;
+	u8 edcl;
+
+	struct greth_regs *regs;	/* Address of controller registers. */
+	struct greth_bd *rx_bd_base;	/* Address of Rx BDs. */
+	struct greth_bd *tx_bd_base;	/* Address of Tx BDs. */
+	dma_addr_t rx_bd_base_phys;
+	dma_addr_t tx_bd_base_phys;
+
+	int irq;
+
+	struct device *dev;	        /* Pointer to of_device->dev */
+	struct net_device *netdev;
+	struct napi_struct napi;
+	struct net_device_stats stats;
+	spinlock_t devlock;
+
+	struct work_struct greth_wq;
+
+	struct phy_device *phy;
+	struct mii_bus *mdio;
+	int mdio_irqs[PHY_MAX_ADDR];
+	unsigned int link;
+	unsigned int speed;
+	unsigned int duplex;
+
+	uint32_t msg_enable;
+};
+
+
+struct amba_prom_registers {
+	unsigned int phys_addr;
+	unsigned int reg_size;
+};
+
+#endif
-- 
1.6.4.1


^ permalink raw reply related

* [PATCH 0/1 V4] net: Add Aeroflex Gaisler 10/100/1G Ethernet MAC driver
From: Kristoffer Glembo @ 2010-01-25 11:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, Kristoffer Glembo

Adds device driver for Aeroflex Gaisler 10/100 and 10/100/1G Ethernet MAC IP cores.

Fourth submission. Removes warnings introduced by last patch ...

Kristoffer Glembo (1):
  net: Add Aeroflex Gaisler 10/100/1G Ethernet MAC driver

 MAINTAINERS          |    6 +
 drivers/net/Kconfig  |    9 +
 drivers/net/Makefile |    1 +
 drivers/net/greth.c  | 1573 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/greth.h  |  149 +++++
 5 files changed, 1738 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/greth.c
 create mode 100644 drivers/net/greth.h


^ permalink raw reply

* Re: [PATCH 1/1 V3] net: Add Aeroflex Gaisler 10/100/1G Ethernet MAC driver
From: Kristoffer Glembo @ 2010-01-25 10:54 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20100123.020549.147260506.davem@davemloft.net>

David Miller wrote:
> 
> Generates build warnings, please fix:
> 
> drivers/net/greth.c: In function ‘greth_rx’:
> drivers/net/greth.c:781: warning: passing argument 1 of ‘greth_print_rx_packet’ makes integer from pointer without a cast
> drivers/net/greth.c: In function ‘greth_rx_gbit’:
> drivers/net/greth.c:885: warning: passing argument 1 of ‘greth_print_rx_packet’ makes integer from pointer without a cast
> 
> phys_to_virt() give a virtual address pointer, so this should
> have generated warnings on 64-bit as well as 32-bit systems.
> 
> I can't see how you could have possibly build tested this and
> not seen the warnings.


After removing the #defines that guarded those calls I only built it as part of the
whole kernel and forgot to check for any warnings. Sorry!

I'll resend ...

/Kristoffer

^ permalink raw reply

* Re: [PATCH net-next-2.6] net: use helpers to access uc list
From: David Miller @ 2010-01-25 10:06 UTC (permalink / raw)
  To: jpirko; +Cc: netdev
In-Reply-To: <20100125083450.GA2902@psychotron.redhat.com>

From: Jiri Pirko <jpirko@redhat.com>
Date: Mon, 25 Jan 2010 09:34:52 +0100

> Well I use "unsigned char *" as iterator because it would allow
> smooth thansition to list_head in case of mc_list. Currently "struct
> dev_addr_list" is used to store address in the list but in the end
> "struct netdev_hw_addr *" will be used.  To use "struct list_head *"
> or "struct netdev_hw_addr *" as an iterator it would be needed to
> convert all drivers at once and that's not doable. Therefore I see
> "unsigned char *" cursor as the best option.

But it's not what you want to use in the end, at all.

If you're going to use a very ugly and opaque iterator type merely to
ease transition, that's not a good reason.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).