Netdev List
 help / color / mirror / Atom feed
* [Patch 1/1] AF_UNIX Datagram getpeersec (with minor fix)
From: Catherine Zhang @ 2006-06-18  6:17 UTC (permalink / raw)
  To: netdev, davem, jmorris, chrisw, herbert, sds, tjaeger, akpm
  Cc: latten, sergeh, gcwilson, czhang.us

Hi,

I added one file (include/linux/selinux.h) which was omitted from the 
previous patch, and removed a couple of unnecessary changes.

Again, comments are welcome!

thanks,
Catherine

--

From: cxzhang@watson.ibm.com

This patch implements an API whereby an application can determine the 
label of its peer's Unix datagram sockets via the auxiliary data mechanism of 
recvmsg.

Patch purpose:

This patch enables a security-aware application to retrieve the
security context of the peer of a Unix datagram socket.  The application 
can then use this security context to determine the security context for 
processing on behalf of the peer who sent the packet. 

Patch design and implementation:

The design and implementation is very similar to the UDP case for INET 
sockets.  Basically we build upon the existing Unix domain socket API for
retrieving user credentials.  Linux offers the API for obtaining user
credentials via ancillary messages (i.e., out of band/control messages
that are bundled together with a normal message).  To retrieve the security 
context, the application first indicates to the kernel such desire by 
setting the SO_PASSSEC option via getsockopt.  Then the application 
retrieves the security context using the auxiliary data mechanism.  

An example server application for Unix datagram socket should look like this:

toggle = 1;
toggle_len = sizeof(toggle);

setsockopt(sockfd, SOL_SOCKET, SO_PASSSEC, &toggle, &toggle_len);
recvmsg(sockfd, &msg_hdr, 0);
if (msg_hdr.msg_controllen > sizeof(struct cmsghdr)) {
    cmsg_hdr = CMSG_FIRSTHDR(&msg_hdr);
    if (cmsg_hdr->cmsg_len <= CMSG_LEN(sizeof(scontext)) &&
        cmsg_hdr->cmsg_level == SOL_SOCKET &&
        cmsg_hdr->cmsg_type == SCM_SECURITY) {
        memcpy(&scontext, CMSG_DATA(cmsg_hdr), sizeof(scontext));
    }
}

sock_setsockopt is enhanced with a new socket option SOCK_PASSSEC to allow
a server socket to receive security context of the peer.  

Testing:

We have tested the patch by setting up Unix datagram client and server
applications.  We verified that the server can retrieve the security context 
using the auxiliary data mechanism of recvmsg.


---

 include/asm-alpha/socket.h   |    1 +
 include/asm-arm/socket.h     |    1 +
 include/asm-arm26/socket.h   |    1 +
 include/asm-cris/socket.h    |    1 +
 include/asm-frv/socket.h     |    1 +
 include/asm-h8300/socket.h   |    1 +
 include/asm-i386/socket.h    |    1 +
 include/asm-ia64/socket.h    |    1 +
 include/asm-m32r/socket.h    |    1 +
 include/asm-m68k/socket.h    |    1 +
 include/asm-mips/socket.h    |    1 +
 include/asm-parisc/socket.h  |    1 +
 include/asm-powerpc/socket.h |    1 +
 include/asm-s390/socket.h    |    1 +
 include/asm-sh/socket.h      |    1 +
 include/asm-sparc/socket.h   |    1 +
 include/asm-sparc64/socket.h |    1 +
 include/asm-v850/socket.h    |    1 +
 include/asm-x86_64/socket.h  |    1 +
 include/asm-xtensa/socket.h  |    1 +
 include/linux/net.h          |    1 +
 include/linux/selinux.h      |   15 +++++++++++++++
 include/net/af_unix.h        |    2 ++
 include/net/scm.h            |   14 ++++++++++++++
 net/core/sock.c              |   11 +++++++++++
 net/unix/af_unix.c           |    2 ++
 security/selinux/exports.c   |   11 +++++++++++
 27 files changed, 76 insertions(+)

diff -puN include/asm-i386/socket.h~lsm-secpeer-unix include/asm-i386/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-i386/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-i386/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-x86_64/socket.h~lsm-secpeer-unix include/asm-x86_64/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-x86_64/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-x86_64/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-ia64/socket.h~lsm-secpeer-unix include/asm-ia64/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-ia64/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-ia64/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -57,5 +57,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_IA64_SOCKET_H */
diff -puN include/asm-powerpc/socket.h~lsm-secpeer-unix include/asm-powerpc/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-powerpc/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-powerpc/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -55,5 +55,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif	/* _ASM_POWERPC_SOCKET_H */
diff -puN include/asm-h8300/socket.h~lsm-secpeer-unix include/asm-h8300/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-h8300/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-h8300/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-s390/socket.h~lsm-secpeer-unix include/asm-s390/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-s390/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-s390/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -56,5 +56,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-mips/socket.h~lsm-secpeer-unix include/asm-mips/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-mips/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-mips/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -69,6 +69,7 @@ To add: #define SO_REUSEPORT 0x0200	/* A
 #define SO_PEERSEC		30
 #define SO_SNDBUFFORCE		31
 #define SO_RCVBUFFORCE		33
+#define SO_PASSSEC		34
 
 #ifdef __KERNEL__
 
diff -puN include/asm-alpha/socket.h~lsm-secpeer-unix include/asm-alpha/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-alpha/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-alpha/socket.h	2006-06-16 16:02:55.000000000 -0400
@@ -51,6 +51,7 @@
 #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		30
+#define SO_PASSSEC		34
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		19
diff -puN include/asm-v850/socket.h~lsm-secpeer-unix include/asm-v850/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-v850/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-v850/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* __V850_SOCKET_H__ */
diff -puN include/asm-sh/socket.h~lsm-secpeer-unix include/asm-sh/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-sh/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-sh/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* __ASM_SH_SOCKET_H */
diff -puN include/asm-m68k/socket.h~lsm-secpeer-unix include/asm-m68k/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-m68k/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-m68k/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-arm/socket.h~lsm-secpeer-unix include/asm-arm/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-arm/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-arm/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-cris/socket.h~lsm-secpeer-unix include/asm-cris/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-cris/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-cris/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -50,6 +50,7 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
 
diff -puN include/asm-arm26/socket.h~lsm-secpeer-unix include/asm-arm26/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-arm26/socket.h~lsm-secpeer-unix	2006-06-12 17:56:06.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-arm26/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-frv/socket.h~lsm-secpeer-unix include/asm-frv/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-frv/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-frv/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,6 +48,7 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_SOCKET_H */
 
diff -puN include/asm-xtensa/socket.h~lsm-secpeer-unix include/asm-xtensa/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-xtensa/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-xtensa/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -59,5 +59,6 @@
 
 #define SO_ACCEPTCONN		30
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif	/* _XTENSA_SOCKET_H */
diff -puN include/asm-m32r/socket.h~lsm-secpeer-unix include/asm-m32r/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-m32r/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-m32r/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
+#define SO_PASSSEC		34
 
 #endif /* _ASM_M32R_SOCKET_H */
diff -puN include/asm-parisc/socket.h~lsm-secpeer-unix include/asm-parisc/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-parisc/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-parisc/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN		0x401c
 
 #define SO_PEERSEC		0x401d
+#define SO_PASSSEC		0x401e
 
 #endif /* _ASM_SOCKET_H */
diff -puN include/asm-sparc/socket.h~lsm-secpeer-unix include/asm-sparc/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-sparc/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-sparc/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,6 +48,7 @@
 #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
+#define SO_PASSSEC		0x001f
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
diff -puN include/asm-sparc64/socket.h~lsm-secpeer-unix include/asm-sparc64/socket.h
--- linux-2.6.17-rc6-mm2/include/asm-sparc64/socket.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/asm-sparc64/socket.h	2006-06-13 15:45:34.000000000 -0400
@@ -48,6 +48,7 @@
 #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
+#define SO_PASSSEC		0x001f
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
diff -puN include/linux/net.h~lsm-secpeer-unix include/linux/net.h
--- linux-2.6.17-rc6-mm2/include/linux/net.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/linux/net.h	2006-06-13 15:45:34.000000000 -0400
@@ -61,6 +61,7 @@ typedef enum {
 #define SOCK_ASYNC_WAITDATA	1
 #define SOCK_NOSPACE		2
 #define SOCK_PASSCRED		3
+#define SOCK_PASSSEC		4
 
 #ifndef ARCH_HAS_SOCKET_TYPES
 /**
diff -puN include/net/af_unix.h~lsm-secpeer-unix include/net/af_unix.h
--- linux-2.6.17-rc6-mm2/include/net/af_unix.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/net/af_unix.h	2006-06-13 15:45:34.000000000 -0400
@@ -53,10 +53,12 @@ struct unix_address {
 struct unix_skb_parms {
 	struct ucred		creds;		/* Skb credentials	*/
 	struct scm_fp_list	*fp;		/* Passed files		*/
+	u32			sid;		/* Security ID		*/
 };
 
 #define UNIXCB(skb) 	(*(struct unix_skb_parms*)&((skb)->cb))
 #define UNIXCREDS(skb)	(&UNIXCB((skb)).creds)
+#define UNIXSID(skb)	(&UNIXCB((skb)).sid)
 
 #define unix_state_rlock(s)	spin_lock(&unix_sk(s)->lock)
 #define unix_state_runlock(s)	spin_unlock(&unix_sk(s)->lock)
diff -puN include/net/scm.h~lsm-secpeer-unix include/net/scm.h
--- linux-2.6.17-rc6-mm2/include/net/scm.h~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/net/scm.h	2006-06-18 01:23:17.000000000 -0400
@@ -3,6 +3,9 @@
 
 #include <linux/limits.h>
 #include <linux/net.h>
+#include <linux/security.h>
+#include <linux/selinux.h>
+#include <net/sock.h>
 
 /* Well, we should have at least one descriptor open
  * to accept passed FDs 8)
@@ -19,6 +22,7 @@ struct scm_cookie
 {
 	struct ucred		creds;		/* Skb credentials	*/
 	struct scm_fp_list	*fp;		/* Passed files		*/
+	u32			sid;		/* Passed security ID	*/
 	unsigned long		seq;		/* Connection seqno	*/
 };
 
@@ -42,6 +46,7 @@ static __inline__ int scm_send(struct so
 	scm->creds.gid = p->gid;
 	scm->creds.pid = p->tgid;
 	scm->fp = NULL;
+	selinux_get_sock_sid(sock, &scm->sid);
 	scm->seq = 0;
 	if (msg->msg_controllen <= 0)
 		return 0;
@@ -51,6 +56,9 @@ static __inline__ int scm_send(struct so
 static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
 				struct scm_cookie *scm, int flags)
 {
+	char *scontext;
+	int scontext_len, err;
+
 	if (!msg->msg_control)
 	{
 		if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp)
@@ -62,6 +70,12 @@ static __inline__ void scm_recv(struct s
 	if (test_bit(SOCK_PASSCRED, &sock->flags))
 		put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
 
+	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
+		err = selinux_ctxid_to_string(scm->sid, &scontext, &scontext_len);
+		if (!err)
+			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scontext_len, scontext);
+	}
+
 	if (!scm->fp)
 		return;
 	
diff -puN net/core/sock.c~lsm-secpeer-unix net/core/sock.c
--- linux-2.6.17-rc6-mm2/net/core/sock.c~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/net/core/sock.c	2006-06-13 15:45:34.000000000 -0400
@@ -565,6 +565,13 @@ set_rcvbuf:
 			ret = -ENONET;
 			break;
 
+		case SO_PASSSEC:
+			if (valbool)
+				set_bit(SOCK_PASSSEC, &sock->flags);
+			else
+				clear_bit(SOCK_PASSSEC, &sock->flags);
+			break;
+
 		/* We implement the SO_SNDLOWAT etc to
 		   not be settable (1003.1g 5.3) */
 		default:
@@ -723,6 +730,10 @@ int sock_getsockopt(struct socket *sock,
 			v.val = sk->sk_state == TCP_LISTEN;
 			break;
 
+		case SO_PASSSEC:
+			v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+			break;
+
 		case SO_PEERSEC:
 			return security_socket_getpeersec_stream(sock, optval, optlen, len);
 
diff -puN net/unix/af_unix.c~lsm-secpeer-unix net/unix/af_unix.c
--- linux-2.6.17-rc6-mm2/net/unix/af_unix.c~lsm-secpeer-unix	2006-06-12 17:56:07.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/net/unix/af_unix.c	2006-06-13 15:45:34.000000000 -0400
@@ -1290,6 +1290,7 @@ static int unix_dgram_sendmsg(struct kio
 	memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 	if (siocb->scm->fp)
 		unix_attach_fds(siocb->scm, skb);
+	memcpy(UNIXSID(skb), &siocb->scm->sid, sizeof(u32));
 
 	skb->h.raw = skb->data;
 	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
@@ -1570,6 +1571,7 @@ static int unix_dgram_recvmsg(struct kio
 		memset(&tmp_scm, 0, sizeof(tmp_scm));
 	}
 	siocb->scm->creds = *UNIXCREDS(skb);
+	siocb->scm->sid   = *UNIXSID(skb);
 
 	if (!(flags & MSG_PEEK))
 	{
diff -puN security/selinux/exports.c~lsm-secpeer-unix security/selinux/exports.c
--- linux-2.6.17-rc6-mm2/security/selinux/exports.c~lsm-secpeer-unix	2006-06-18 01:14:50.000000000 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/security/selinux/exports.c	2006-06-18 01:15:19.000000000 -0400
@@ -17,6 +17,7 @@
 #include <linux/selinux.h>
 #include <linux/fs.h>
 #include <linux/ipc.h>
+#include <net/sock.h>
 
 #include "security.h"
 #include "objsec.h"
@@ -72,6 +73,16 @@ void selinux_get_task_sid(struct task_st
 	*sid = 0;
 }
 
+void selinux_get_sock_sid(const struct socket *sock, u32 *sid)
+{
+	if (selinux_enabled) {
+		const struct inode *inode = SOCK_INODE(sock);
+		selinux_get_inode_sid(inode, sid);
+		return;
+	}
+	*sid = 0;
+}
+
 int selinux_string_to_sid(char *str, u32 *sid)
 {
 	if (selinux_enabled)
diff -puN include/linux/selinux.h~lsm-secpeer-unix include/linux/selinux.h
--- linux-2.6.17-rc6-mm2/include/linux/selinux.h~lsm-secpeer-unix	2006-06-18 01:44:44.198292264 -0400
+++ linux-2.6.17-rc6-mm2-cxzhang/include/linux/selinux.h	2006-06-18 01:29:36.000000000 -0400
@@ -18,6 +18,7 @@ struct selinux_audit_rule;
 struct audit_context;
 struct inode;
 struct kern_ipc_perm;
+struct socket;
 
 #ifdef CONFIG_SECURITY_SELINUX
 
@@ -119,6 +120,15 @@ void selinux_get_ipc_sid(const struct ke
 void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
 
 /**
+ *     selinux_get_sock_sid - return the SID of socket
+ *     @sock: the socket whose SID will be returned
+ *     @sid: pointer to security context ID to be filled in.
+ *
+ *     Returns nothing
+ */
+void selinux_get_sock_sid(const struct socket *sock, u32 *sid);
+
+/**
  *     selinux_string_to_sid - map a security context string to a security ID
  *     @str: the security context string to be mapped
  *     @sid: ID value returned via this.
@@ -193,6 +203,11 @@ static inline void selinux_get_task_sid(
 	*sid = 0;
 }
 
+static inline void selinux_get_sock_sid(struct socket *sock, u32 *sid)
+{
+	*sid = 0;
+}
+
 static inline int selinux_string_to_sid(const char *str, u32 *sid)
 {
        *sid = 0;
_

^ permalink raw reply

* Re: [PATCH 1/6][SCTP]: Limit association max_retrans setting in setsockopt
From: David Miller @ 2006-06-18  5:59 UTC (permalink / raw)
  To: sri; +Cc: netdev, lksctp-developers
In-Reply-To: <1150411572.6028.31.camel@w-sridhar2.beaverton.ibm.com>

From: Sridhar Samudrala <sri@us.ibm.com>
Date: Thu, 15 Jun 2006 15:46:12 -0700

> Please apply the following 6 SCTP patches to 2.6 tree.

Sridhar, I missed the 2.6.17 release but I will be sure
to queue these up for the first 2.6.17.x stable release.

Sorry about that.

^ permalink raw reply

* Re: [2/2] [BRIDGE]: Add support for NETIF_F_HW_CSUM devices
From: David Miller @ 2006-06-18  5:06 UTC (permalink / raw)
  To: herbert; +Cc: shemminger, netdev
In-Reply-To: <20060613112543.GA13253@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 13 Jun 2006 21:25:43 +1000

> [BRIDGE]: Add support for NETIF_F_HW_CSUM devices
> 
> As it is the bridge will only ever declare NETIF_F_IP_CSUM even if all
> its constituent devices support NETIF_F_HW_CSUM.  This patch fixes this
> by supporting the first one out of NETIF_F_NO_CSUM, NETIF_F_HW_CSUM,
> and NETIF_F_IP_CSUM that is supported by all constituent devices.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Also applied, thanks a lot!

^ permalink raw reply

* Re: [1/2] [NET]: Add NETIF_F_GEN_CSUM and NETIF_F_ALL_CSUM
From: David Miller @ 2006-06-18  5:06 UTC (permalink / raw)
  To: herbert; +Cc: shemminger, netdev
In-Reply-To: <20060613112511.GA13204@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 13 Jun 2006 21:25:11 +1000

> [NET]: Add NETIF_F_GEN_CSUM and NETIF_F_ALL_CSUM
> 
> The current stack treats NETIF_F_HW_CSUM and NETIF_F_NO_CSUM identically
> so we test for them in quite a few places.  For the sake of brevity, I'm
> adding the macro NETIF_F_GEN_CSUM for these two.  We also test the disjunct
> of NETIF_F_IP_CSUM and the other two in various places, for that purpose
> I've added NETIF_F_ALL_CSUM.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Applied, thanks Herbert.

^ permalink raw reply

* Re: [PATCH 2.6.18 2/3] tg3: Convert to non-LLTX
From: David Miller @ 2006-06-18  4:58 UTC (permalink / raw)
  To: mchan; +Cc: herbert, jgarzik, netdev
In-Reply-To: <1149536852.13155.7.camel@rh4>

From: "Michael Chan" <mchan@broadcom.com>
Date: Mon, 05 Jun 2006 12:47:32 -0700

> Herbert Xu pointed out that it is unsafe to call netif_tx_disable()
> from LLTX drivers because it uses dev->xmit_lock to synchronize
> whereas LLTX drivers use private locks.
> 
> Convert tg3 to non-LLTX to fix this issue. tg3 is a lockless driver
> where hard_start_xmit and tx completion handling can run concurrently
> under normal conditions. A tx_lock is only needed to prevent
> netif_stop_queue and netif_wake_queue race condtions when the queue
> is full.
> 
> So whether we use LLTX or non-LLTX, it makes practically no
> difference.
> 
> Signed-off-by: Michael Chan <mchan@broadcom.com>

Applied, thanks a lot.

^ permalink raw reply

* Re: [PATCH 2.6.18 1/3] tg3: Remove unnecessary tx_lock
From: David Miller @ 2006-06-18  4:57 UTC (permalink / raw)
  To: mchan; +Cc: herbert, jgarzik, netdev
In-Reply-To: <1149536843.13155.6.camel@rh4>

From: "Michael Chan" <mchan@broadcom.com>
Date: Mon, 05 Jun 2006 12:47:23 -0700

> Remove tx_lock where it is unnecessary. tg3 runs lockless and so it
> requires interrupts to be disabled and sync'ed, netif_queue and NAPI
> poll to be stopped before the device can be reconfigured. After
> stopping everything, it is no longer necessary to get the tx_lock.
> 
> Signed-off-by: Michael Chan <mchan@broadcom.com>

Applied, thanks.

^ permalink raw reply

* [PATCH wireless-dev] add adm8211 driver
From: Michael Wu @ 2006-06-18  4:52 UTC (permalink / raw)
  To: linville; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 90486 bytes --]

This patch adds support for the ADMtek ADM8211 card. It is not completed yet, 
but I feel the code is clean enough to merge into wireless-dev. It currently 
supports STA mode.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>

diff --git a/drivers/net/wireless/d80211/Kconfig 
b/drivers/net/wireless/d80211/Kconfig
index 972c473..3656ee5 100644
--- a/drivers/net/wireless/d80211/Kconfig
+++ b/drivers/net/wireless/d80211/Kconfig
@@ -1,2 +1,3 @@
 source "drivers/net/wireless/d80211/bcm43xx/Kconfig"
 source "drivers/net/wireless/d80211/rt2x00/Kconfig"
+source "drivers/net/wireless/d80211/adm8211/Kconfig"
diff --git a/drivers/net/wireless/d80211/Makefile 
b/drivers/net/wireless/d80211/Makefile
index 32c5c8d..e491a41 100644
--- a/drivers/net/wireless/d80211/Makefile
+++ b/drivers/net/wireless/d80211/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_BCM43XX_D80211)	+= bcm43xx/
 obj-$(CONFIG_RT2X00)		+= rt2x00/
+obj-$(CONFIG_ADM8211)		+= adm8211/
diff --git a/drivers/net/wireless/d80211/adm8211/Kconfig 
b/drivers/net/wireless/d80211/adm8211/Kconfig
new file mode 100644
index 0000000..9846cdf
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/Kconfig
@@ -0,0 +1,24 @@
+config ADM8211
+	tristate "ADMtek ADM8211 support"
+	depends on NET_RADIO && PCI && D80211 && EXPERIMENTAL
+	---help---
+	  This driver is for ADM8211A, ADM8211B, and ADM8211C based cards.
+	  These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as:
+
+	  Xterasys Cardbus XN-2411b
+	  Blitz NetWave Point PC
+	  TrendNet 221pc
+	  Belkin F5D6001
+	  SMC 2635W
+	  Linksys WPC11 v1
+	  Fiberline FL-WL-200X
+	  3com Office Connect (3CRSHPW796)
+	  Corega WLPCIB-11
+	  SMC 2602W V2 EU
+	  D-Link DWL-520 Revision C
+
+	  However, some of these cards have been replaced with other chips
+	  like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or
+	  the Ralink RT2400 (SMC2635W) without a model number change.
+
+	  Thanks to Infineon-ADMtek for their support of this driver.
diff --git a/drivers/net/wireless/d80211/adm8211/Makefile 
b/drivers/net/wireless/d80211/adm8211/Makefile
new file mode 100644
index 0000000..9cca7e5
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ADM8211)	+= adm8211.o
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.c 
b/drivers/net/wireless/d80211/adm8211/adm8211.c
new file mode 100644
index 0000000..c766c4e
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.c
@@ -0,0 +1,2202 @@
+
+/*
+ * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
+ *
+ * Copyright (c) 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Michael Wu <flamingice@sourmilk.net>
+ * Some parts copyright (c) 2003 by David Young <dyoung@pobox.com>
+ * and used with permission.
+ *
+ * Much thanks to Infineon-ADMtek for their support of this driver.
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/wireless.h>
+#include <net/d80211.h>
+#include <asm/delay.h>
+#include <asm/unaligned.h>
+#include <asm/types.h>
+#include <asm/div64.h>
+
+#include "adm8211.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>, Jouni Malinen 
<jkmaline@cc.hut.fi>");
+MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless LAN cards based on 
ADMtek ADM8211");
+MODULE_SUPPORTED_DEVICE("ADM8211");
+MODULE_LICENSE("GPL");
+
+static unsigned int tx_ring_size = 16;
+static unsigned int rx_ring_size = 16;
+static int debug = 1;
+
+module_param(tx_ring_size, uint, 0);
+module_param(rx_ring_size, uint, 0);
+module_param(debug, int, 0);
+
+static const char *version = KERN_INFO "adm8211: " 
+"Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>; "
+"Copyright 2004-2006, Michael Wu <flamingice@sourmilk.net>\n";
+
+
+static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+	/* ADMtek ADM8211 */
+	{ 0x10B7, 0x6000, PCI_ANY_ID, PCI_ANY_ID }, /* 3Com 3CRSHPW796 */
+	{ 0x1200, 0x8201, PCI_ANY_ID, PCI_ANY_ID }, /* ? */
+	{ 0x1317, 0x8201, PCI_ANY_ID, PCI_ANY_ID }, /* ADM8211A */
+	{ 0x1317, 0x8211, PCI_ANY_ID, PCI_ANY_ID }, /* ADM8211B/C */
+	{ 0 }
+};
+
+#define ADM8211_INTMASK \
+(ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | \
+ADM8211_IER_TDUIE | ADM8211_IER_GPTIE)
+
+#define PLCP_SIGNAL_1M		0x0a
+#define PLCP_SIGNAL_2M		0x14
+#define PLCP_SIGNAL_5M5		0x37
+#define PLCP_SIGNAL_11M		0x6e
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],
((u8*)(x))[4],((u8*)(x))[5]
+
+struct adm8211_tx_hdr {
+	u8 da[6];
+	u8 signal; /* PLCP signal / TX rate in 100 Kbps */
+	u8 service;
+	__le16 frame_body_size;
+	__le16 frame_control;
+	__le16 plcp_frag_tail_len;
+	__le16 plcp_frag_head_len;
+	__le16 dur_frag_tail;
+	__le16 dur_frag_head;
+	u8 addr4[6];
+
+#define ADM8211_TXHDRCTL_SHORT_PREAMBLE		(1 <<  0)
+#define ADM8211_TXHDRCTL_MORE_FRAG		(1 <<  1)
+#define ADM8211_TXHDRCTL_MORE_DATA		(1 <<  2)
+#define ADM8211_TXHDRCTL_FRAG_NO		(1 <<  3) /* ? */
+#define ADM8211_TXHDRCTL_ENABLE_RTS		(1 <<  4)
+#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE	(1 <<  5)
+#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER	(1 << 15) /* ? */
+	__le16 header_control;
+	__le16 frag;
+	u8 reserved_0;
+	u8 retry_limit;
+
+	u32 wep2key0;
+	u32 wep2key1;
+	u32 wep2key2;
+	u32 wep2key3;
+
+	u8 keyid;
+	u8 entry_control;	// huh??
+	u16 reserved_1;
+	u32 reserved_2;
+} __attribute__ ((packed));
+
+
+#define RX_COPY_BREAK 128
+#define RX_PKT_SIZE 2500
+
+/* Serial EEPROM reading for 93C66/93C46 */
+#define EE_ENB		(0x4000 | ADM8211_SPR_SRS | ADM8211_SPR_SCS)
+#define EE_READ_CMD	(6)
+#define eeprom_delay()	ADM8211_CSR_READ(SPR);
+
+
+static u16 adm8211_eeprom_read_word(struct net_device *dev, unsigned int 
addr,
+				    unsigned int addr_len)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int read_cmd = addr | (EE_READ_CMD << addr_len);
+	int i;
+	u16 retval = 0;
+
+	ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB & ~ADM8211_SPR_SCS));
+	eeprom_delay();
+	ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+	eeprom_delay();
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		u32 dataval = EE_ENB | ((read_cmd & (1 << i)) ? ADM8211_SPR_SDI : 0);
+		ADM8211_CSR_WRITE(SPR, cpu_to_le32(dataval));
+		eeprom_delay();
+		ADM8211_CSR_WRITE(SPR, cpu_to_le32(dataval | ADM8211_SPR_SCLK));
+		eeprom_delay();
+	}
+
+	ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+	eeprom_delay();
+
+	for (i = 16; i > 0; i--) {
+		ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB | ADM8211_SPR_SCLK));
+		eeprom_delay();
+		retval <<= 1;
+		if (ADM8211_CSR_READ(SPR) & __constant_cpu_to_le32(ADM8211_SPR_SDO))
+			retval |= 1;
+		ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB & ~ADM8211_SPR_SCS));
+
+	return retval;
+}
+
+
+static int adm8211_read_eeprom(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int addr_len, words, i;
+	struct ieee80211_chan_range chan_range;
+	u16 cr49;
+
+	if (ADM8211_CSR_READ(CSR_TEST0) & __constant_cpu_to_le32
(ADM8211_CSR_TEST0_EPTYP)) {
+		printk(KERN_DEBUG "%s (adm8211): EEPROM type: 93C66\n", 
pci_name(priv->pdev));
+		/* 256 * 16-bit = 512 bytes */
+		addr_len = 8;
+		words = 256;
+	} else {
+		printk(KERN_DEBUG "%s (adm8211): EEPROM type 93C46\n", 
pci_name(priv->pdev));
+		/* 64 * 16-bit = 128 bytes */
+		addr_len = 6;
+		words = 64;
+	}
+
+	priv->eeprom_len = words * 2;
+	priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL);
+	if (priv->eeprom == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < words; i++)
+		*((u16 *) &((u8 *)priv->eeprom)[i * 2]) =
+			adm8211_eeprom_read_word(dev, i, addr_len);
+
+	cr49 = le16_to_cpu(priv->eeprom->cr49);
+	priv->rf_type = (cr49 >> 3) & 0x7;
+	switch (priv->rf_type) {
+	case ADM8211_TYPE_INTERSIL:
+	case ADM8211_TYPE_RFMD:
+	case ADM8211_TYPE_MARVEL:
+	case ADM8211_TYPE_AIROHA:
+	case ADM8211_TYPE_ADMTEK:
+		break;
+	
+	default:
+		if (priv->revid < ADM8211_REV_CA)
+			priv->rf_type = ADM8211_TYPE_RFMD;
+		else
+			priv->rf_type = ADM8211_TYPE_AIROHA;
+
+		printk(KERN_WARNING "%s (adm8211): Invalid or unsupported RFtype: %d, 
assuming %d\n",
+		       pci_name(priv->pdev), (cr49 >> 3) & 0x7, priv->rf_type);
+	}
+
+	priv->bbp_type = cr49 & 0x7;
+	switch (priv->bbp_type) {
+	case ADM8211_TYPE_INTERSIL:
+	case ADM8211_TYPE_RFMD:
+	case ADM8211_TYPE_MARVEL:
+	case ADM8211_TYPE_AIROHA:
+	case ADM8211_TYPE_ADMTEK:
+		break;
+	
+	default:
+		if (priv->revid < ADM8211_REV_CA)
+			priv->bbp_type = ADM8211_TYPE_RFMD;
+		else
+			priv->bbp_type = ADM8211_TYPE_ADMTEK;
+
+		printk(KERN_WARNING "%s (adm8211): Invalid or unsupported BBPtype: %d, 
assuming %d\n",
+		       pci_name(priv->pdev), cr49 >> 3, priv->bbp_type);
+	}
+
+	if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) {
+		printk(KERN_WARNING "%s (adm8211): Invalid country code (%d) in EEPROM, 
assuming ETSI\n",
+		       pci_name(priv->pdev), priv->eeprom->country_code);
+
+		chan_range = cranges[2];
+	} else
+		chan_range = cranges[priv->eeprom->country_code];
+
+	printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+	       pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+	priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+	priv->modes[0].channels = kmalloc(priv->modes[0].num_channels * 
sizeof(struct ieee80211_channel), GFP_KERNEL);
+	if (priv->modes[0].channels == NULL) {
+		kfree(priv->eeprom);
+		return -ENOMEM;
+	}
+
+	memcpy(priv->modes[0].channels, &adm8211_channels[chan_range.min-1],
+		priv->modes[0].num_channels * sizeof(struct ieee80211_channel));
+
+	switch (priv->eeprom->specific_bbptype) {
+	case ADM8211_BBP_RFMD3000:
+	case ADM8211_BBP_RFMD3002:
+	case ADM8211_BBP_ADM8011:
+		priv->specific_bbptype = priv->eeprom->specific_bbptype;
+		break;
+	
+	default:
+		if (priv->revid < ADM8211_REV_CA)
+			priv->specific_bbptype = ADM8211_BBP_RFMD3000;
+		else
+			priv->specific_bbptype = ADM8211_BBP_ADM8011;
+
+		printk(KERN_WARNING "%s (adm8211): Invalid or unsupported specific BBP: %d, 
assuming %d\n",
+		       pci_name(priv->pdev), priv->eeprom->specific_bbptype, 
priv->specific_bbptype);
+	}
+	
+	switch (priv->eeprom->specific_rftype) {
+	case ADM8211_RFMD2948:
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+	case ADM8211_MAX2820:
+	case ADM8211_AL2210L:
+		priv->transceiver_type = priv->eeprom->specific_rftype;
+		break;
+
+	default:
+		if (priv->revid == ADM8211_REV_BA)
+			priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER;
+		else if (priv->revid == ADM8211_REV_CA)
+			priv->transceiver_type = ADM8211_AL2210L;
+		else if (priv->revid == ADM8211_REV_AB)
+			priv->transceiver_type = ADM8211_RFMD2948;
+
+		printk(KERN_WARNING "%s (adm8211): Invalid or unsupported transceiver: %d, 
assuming %d\n",
+		       pci_name(priv->pdev), priv->eeprom->specific_rftype, 
priv->transceiver_type);
+
+		break;
+	}
+
+	printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d 
Transceiver=%d\n",
+	       pci_name(priv->pdev), priv->rf_type, priv->bbp_type,
+	       priv->specific_bbptype, priv->transceiver_type);
+
+	return 0;
+}
+
+static inline void adm8211_write_sram(struct net_device *dev, u32 addr, 
__le32 data)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	ADM8211_CSR_WRITE(WEPCTL, cpu_to_le32(addr | ADM8211_WEPCTL_TABLE_WR |
+			  (priv->revid < ADM8211_REV_BA ?
+			   0 : ADM8211_WEPCTL_SEL_WEPTABLE )) );
+	ADM8211_CSR_READ(WEPCTL);
+	mdelay(1);
+
+	ADM8211_CSR_WRITE(WESK, data);
+	ADM8211_CSR_READ(WESK);
+	mdelay(1);
+}
+
+static void adm8211_write_sram_bytes(struct net_device *dev,
+				     unsigned int addr, u8 *buf, unsigned int len)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	__le32 reg = ADM8211_CSR_READ(WEPCTL);
+	unsigned int i;
+
+	if (priv->revid < ADM8211_REV_BA) {
+		for (i = 0; i < len; i += 2) {
+			u16 val = buf[i] | buf[i + 1] << 8;
+			adm8211_write_sram(dev, addr + i / 2, cpu_to_le32(val));
+		}
+	} else {
+		for (i = 0; i < len; i += 4) {
+			u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) |
+				  (buf[i + 2] << 16) | (buf[i + 3] << 24);
+			adm8211_write_sram(dev, addr + i / 4, cpu_to_le32(val));
+		}
+	}
+
+	ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static void adm8211_clear_sram(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	__le32 reg = ADM8211_CSR_READ(WEPCTL);
+	unsigned int addr;
+
+	for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++)
+			adm8211_write_sram(dev, addr, 0);
+
+	ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static int adm8211_get_stats(struct net_device *dev,
+			     struct ieee80211_low_level_stats *stats)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	memcpy(stats, &priv->stats, sizeof(*stats));
+
+	return 0;
+}
+
+static void adm8211_set_rx_mode(struct net_device *dev,
+				unsigned short flags, int mc_count)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int bit_nr;
+	__le32 mc_filter[2];
+	struct dev_mc_list *mclist;
+	void *tmp;
+
+		mc_filter[1] = mc_filter[0] = 0;
+	if (flags & IFF_PROMISC) {
+		priv->nar |= ADM8211_NAR_PR;
+		priv->nar &= ~ADM8211_NAR_MM;
+		mc_filter[1] = mc_filter[0] = __constant_cpu_to_le32(~0);
+	} else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
+		priv->nar &= ~ADM8211_NAR_PR;
+		priv->nar |= ADM8211_NAR_MM;
+		mc_filter[1] = mc_filter[0] = __constant_cpu_to_le32(~0);
+	} else {
+		priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+		mc_filter[1] = mc_filter[0] = 0;
+		mclist = NULL;
+		while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
+			bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			bit_nr &= 0x3F;
+			mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
+		}
+	}
+
+	ADM8211_IDLE_RX();
+
+	ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+	ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+	ADM8211_CSR_READ(NAR);
+
+	ADM8211_RESTORE();
+}
+
+static int adm8211_get_tx_stats(struct net_device *dev,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
+
+	data->len = priv->cur_tx - priv->dirty_tx;
+	data->limit = priv->tx_ring_size - 2;
+	data->count = priv->dirty_tx;
+
+	return 0;
+}
+
+static void adm8211_interrupt_tci(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	struct net_device_stats *stats = ieee80211_dev_stats(dev);
+	unsigned dirty_tx;
+
+	spin_lock(&priv->lock);
+
+	for (dirty_tx = priv->dirty_tx;
+	     priv->cur_tx - dirty_tx > 0; dirty_tx++) {
+		unsigned entry = dirty_tx % priv->tx_ring_size;
+		u32 status = le32_to_cpu(priv->tx_ring[entry].status);
+		struct sk_buff *skb;
+
+		if (status & TDES0_CONTROL_OWN ||
+		    !(status & TDES0_CONTROL_DONE))
+			break;
+
+		if (status & TDES0_STATUS_ES) {
+			stats->tx_errors++;
+			priv->tx_buffers[entry].tx_status.ack = 0;
+
+			if (status & (TDES0_STATUS_TUF | TDES0_STATUS_TRO))
+				stats->tx_fifo_errors++;
+		} else
+			priv->tx_buffers[entry].tx_status.ack = 1;
+
+		skb = priv->tx_buffers[entry].skb;
+		pci_unmap_single(priv->pdev, priv->tx_buffers[entry].mapping,
+				 skb->len, PCI_DMA_TODEVICE);
+
+		if (priv->tx_buffers[entry].tx_status.control.req_tx_status ||
+		    priv->tx_buffers[entry].unicast)
+			ieee80211_tx_status_irqsafe(dev, priv->tx_buffers[entry].skb,
+						    &priv->tx_buffers[entry].tx_status);
+		else
+			dev_kfree_skb_irq(priv->tx_buffers[entry].skb);
+		priv->tx_buffers[entry].skb = NULL;
+	}
+
+	if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
+		netif_wake_queue(dev);
+
+	priv->dirty_tx = dirty_tx;
+	spin_unlock(&priv->lock);
+}
+
+
+static void adm8211_interrupt_rci(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	struct net_device_stats *stats = ieee80211_dev_stats(dev);
+	unsigned int entry = priv->cur_rx % priv->rx_ring_size;
+	u32 status;
+	unsigned pktlen;
+	struct sk_buff *skb, *newskb;
+	unsigned int limit = priv->rx_ring_size;
+	static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+	u8 rssi, rate;
+
+	while (!(priv->rx_ring[entry].status &
+		 __constant_cpu_to_le32(RDES0_STATUS_OWN))) {
+		if (limit-- == 0)
+			break;
+
+		status = le32_to_cpu(priv->rx_ring[entry].status);
+		rate = (status & RDES0_STATUS_RXDR) >> 12;
+		rssi = le32_to_cpu(priv->rx_ring[entry].length) &
+			RDES1_STATUS_RSSI;
+
+		pktlen = status & RDES0_STATUS_FL;
+		if (pktlen > RX_PKT_SIZE) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: too long frame (pktlen=%d)\n",
+				       dev->name, pktlen);
+			pktlen = RX_PKT_SIZE;
+		}
+
+		if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) {
+			skb = NULL; /* old buffer will be reused */
+			stats->rx_errors++;
+			if (status & (RDES0_STATUS_CRC16E | RDES0_STATUS_CRC32E))
+				stats->rx_crc_errors++;
+
+		} else if (pktlen < RX_COPY_BREAK) {
+			skb = dev_alloc_skb(pktlen);
+			if (skb) {
+				skb->dev = dev;
+				pci_dma_sync_single_for_cpu(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					pktlen, PCI_DMA_FROMDEVICE);
+				memcpy(skb_put(skb, pktlen),
+				       priv->rx_buffers[entry].skb->tail,
+				       pktlen);
+				pci_dma_sync_single_for_device(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+			}
+		} else {
+			newskb = dev_alloc_skb(RX_PKT_SIZE);
+			if (newskb) {
+				newskb->dev = dev;
+				skb = priv->rx_buffers[entry].skb;
+				skb_put(skb, pktlen);
+				pci_unmap_single(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+				priv->rx_buffers[entry].skb = newskb;
+				priv->rx_buffers[entry].mapping =
+					pci_map_single(priv->pdev,
+						       newskb->tail,
+						       RX_PKT_SIZE,
+						       PCI_DMA_FROMDEVICE);
+			} else {
+				skb = NULL;
+				stats->rx_dropped++;
+			}
+
+			priv->rx_ring[entry].buffer1 =
+				cpu_to_le32(priv->rx_buffers[entry].mapping);
+		}
+
+		priv->rx_ring[entry].status = cpu_to_le32( RDES0_STATUS_OWN | 
RDES0_STATUS_SQL );
+		priv->rx_ring[entry].length =
+			cpu_to_le32(RX_PKT_SIZE |
+				    (entry == priv->rx_ring_size - 1 ?
+				     RDES1_CONTROL_RER : 0));
+
+		if (skb) {
+			struct ieee80211_rx_status rx_status = {0};
+
+			if (priv->revid < ADM8211_REV_CA)
+				rx_status.ssi = rssi;
+			else
+				rx_status.ssi = 100 - rssi;
+
+			if (rate <= 4)
+				rx_status.rate = rate_tbl[rate];
+	
+			/* remove FCS */
+			/* TODO: remove this and set flag in ieee80211_hw instead? */
+			if (dev->flags & IFF_PROMISC)
+				skb_trim(skb, skb->len - FCS_LEN);
+
+			ieee80211_rx_irqsafe(dev, skb, &rx_status);
+		}
+
+		entry = (++priv->cur_rx) % priv->rx_ring_size;
+	}
+
+	stats->rx_missed_errors += le32_to_cpu(ADM8211_CSR_READ(LPC)) & 0xFFFF;
+}
+
+
+static irqreturn_t adm8211_interrupt(int irq, void *dev_id,
+				     struct pt_regs *regs)
+{
+#define ADM8211_INT(x) if (unlikely(stsr & ADM8211_STSR_ ## x)) 
printk(KERN_DEBUG "%s: " #x "\n", dev->name)
+
+	struct net_device *dev = dev_id;
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int count = 0;
+	u32 stsr;
+
+	do {
+		stsr = le32_to_cpu(ADM8211_CSR_READ(STSR));
+		ADM8211_CSR_WRITE(STSR, cpu_to_le32(stsr));
+		if (stsr == 0xffffffff)
+			return IRQ_HANDLED;
+
+		if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS)))
+			break;
+
+		if (stsr & ADM8211_STSR_RCI)
+			adm8211_interrupt_rci(dev);
+		if (stsr & ADM8211_STSR_TCI)
+			adm8211_interrupt_tci(dev);
+
+		if ((stsr & (ADM8211_STSR_LinkOn | ADM8211_STSR_LinkOff))
+			 != (ADM8211_STSR_LinkOn | ADM8211_STSR_LinkOff)) {
+			if (stsr & ADM8211_STSR_LinkOn)
+				printk(KERN_DEBUG "%s: LinkOn\n", dev->name);
+		
+			if (stsr & ADM8211_STSR_LinkOff)
+				printk(KERN_DEBUG "%s: LinkOff\n", dev->name);
+		}
+
+		ADM8211_INT(PCF);
+		ADM8211_INT(BCNTC);
+		ADM8211_INT(GPINT);
+		ADM8211_INT(ATIMTC);
+		ADM8211_INT(TSFTF);
+		ADM8211_INT(TSCZ);
+		ADM8211_INT(SQL);
+		ADM8211_INT(WEPTD);
+		ADM8211_INT(ATIME);
+		/*ADM8211_INT(TBTT);*/
+		ADM8211_INT(TEIS);
+		ADM8211_INT(FBE);
+		ADM8211_INT(REIS);
+		ADM8211_INT(GPTT);
+		ADM8211_INT(RPS);
+		ADM8211_INT(RDU);
+		ADM8211_INT(TUF);
+		/*ADM8211_INT(TRT);*/
+		/*ADM8211_INT(TLT);*/
+		/*ADM8211_INT(TDU);*/
+		ADM8211_INT(TPS);
+
+	} while (count++ < 20);
+
+	return IRQ_RETVAL(count);
+
+#undef ADM8211_INT
+}
+
+#define 
WRITE_SYN(valmask,valshift,addrmask,addrshift,bits,prewrite,postwrite) do {\
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);\
+	unsigned int i;\
+	u32 reg, bitbuf;\
+	\
+	value &= valmask;\
+	addr &= addrmask;\
+	bitbuf = (value << valshift) | (addr << addrshift);\
+	\
+	ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_IF_SELECT_1));
\
+	ADM8211_CSR_READ(SYNRF);\
+	ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_IF_SELECT_0));
\
+	ADM8211_CSR_READ(SYNRF);\
+	\
+	if (prewrite) {\
+		ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32
(ADM8211_SYNRF_WRITE_SYNDATA_0));\
+		ADM8211_CSR_READ(SYNRF);\
+	}\
+	\
+	for (i = 0; i <= bits; i++) {\
+		if ( bitbuf & (1 << (bits - i)) )\
+			reg = ADM8211_SYNRF_WRITE_SYNDATA_1;\
+		else\
+			reg = ADM8211_SYNRF_WRITE_SYNDATA_0;\
+		\
+		ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg));\
+		ADM8211_CSR_READ(SYNRF);\
+		\
+		ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_WRITE_CLOCK_1));\
+		ADM8211_CSR_READ(SYNRF);\
+		ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_WRITE_CLOCK_0));\
+		ADM8211_CSR_READ(SYNRF);\
+	}\
+	\
+	if (postwrite == 1) {\
+		ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_IF_SELECT_0));\
+		ADM8211_CSR_READ(SYNRF);\
+	}\
+	if (postwrite == 2) {\
+		ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_IF_SELECT_1));\
+		ADM8211_CSR_READ(SYNRF);\
+	}\
+	\
+	ADM8211_CSR_WRITE(SYNRF, 0);\
+	ADM8211_CSR_READ(SYNRF);\
+} while (0)
+
+static void adm8211_rf_write_syn_max2820 (struct net_device *dev, u16 addr, 
u32 value)
+{
+	WRITE_SYN(0x00FFF, 0, 0x0F, 12, 15, 1, 1);
+}
+
+static void adm8211_rf_write_syn_al2210l (struct net_device *dev, u16 addr, 
u32 value)
+{
+	WRITE_SYN(0xFFFFF, 4, 0x0F,  0, 23, 1, 1);
+}
+
+static void adm8211_rf_write_syn_rfmd2958 (struct net_device *dev, u16 addr, 
u32 value)
+{
+	WRITE_SYN(0x3FFFF, 0, 0x1F, 18, 23, 0, 1);
+}
+
+static void adm8211_rf_write_syn_rfmd2948 (struct net_device *dev, u16 addr, 
u32 value)
+{
+	WRITE_SYN(0x0FFFF, 4, 0x0F,  0, 21, 0, 2);
+}
+
+static int adm8211_write_bbp(struct net_device *dev, u8 addr, u8 data)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int timeout;
+	u32 reg;
+
+	timeout = 10;
+	while (timeout > 0) {
+		reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+		if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD)))
+			break;
+		timeout--;
+		mdelay(2);
+	}
+
+	if (timeout == 0) {
+		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed prewrite "
+		       "(reg=0x%08x)\n",
+		       dev->name, addr, data, reg);
+		return -ETIMEDOUT;
+	}
+
+	switch (priv->bbp_type) {
+	case ADM8211_TYPE_INTERSIL:
+		reg = ADM8211_BBPCTL_MMISEL;	/* three wire interface */
+		break;
+	case ADM8211_TYPE_RFMD:
+		reg = (0x20<<24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+		      (0x01<<18);
+		break;
+	case ADM8211_TYPE_ADMTEK:
+		reg = (0x20<<24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+		      (0x05<<18);
+		break;
+	}
+	reg |= ADM8211_BBPCTL_WR | (addr << 8) | data;
+
+	ADM8211_CSR_WRITE(BBPCTL, cpu_to_le32(reg));
+
+	timeout = 10;
+	while (timeout > 0) {
+		reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+		if (!(reg & ADM8211_BBPCTL_WR))
+			break;
+		timeout--;
+		mdelay(2);
+	}
+
+	if (timeout == 0) {
+		ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
+				  __constant_cpu_to_le32(~ADM8211_BBPCTL_WR));
+		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed postwrite "
+		       "(reg=0x%08x)\n",
+		       dev->name, addr, data, reg);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int adm8211_rf_set_channel(struct net_device *dev, unsigned int 
channel)
+{
+	static const u32 adm8211_rfmd2958_reg5[] =
+		{0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340,
+		 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7};
+	static const u32 adm8211_rfmd2958_reg6[] =
+		{0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000,
+		 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745};
+
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u8 ant_power = priv->ant_power > 0x3F ?
+		priv->eeprom->antenna_power[channel-1] : priv->ant_power;
+	u8 tx_power = priv->tx_power > 0x3F ?
+		priv->eeprom->tx_power[channel-1] : priv->tx_power;
+	u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ?
+		priv->eeprom->lpf_cutoff[channel-1] : priv->lpf_cutoff;
+	u8 lnags_thresh = priv->lnags_threshold == 0xFF ?
+		priv->eeprom->lnags_threshold[channel-1] : priv->lnags_threshold;
+	u32 reg;
+
+	if (channel < 1 || channel > 14)
+		return -EINVAL;
+
+	ADM8211_IDLE();
+
+	/* Program synthesizer to new channel */
+	switch (priv->transceiver_type) {
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+		adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007);
+		adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033);
+
+		adm8211_rf_write_syn_rfmd2958(dev, 0x05,
+					adm8211_rfmd2958_reg5[channel-1]);
+		adm8211_rf_write_syn_rfmd2958(dev, 0x06,
+					adm8211_rfmd2958_reg6[channel-1]);
+		break;
+
+	case ADM8211_RFMD2948:
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF, SI4126_MAIN_XINDIV2);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN,
+				     SI4126_POWERDOWN_PDIB | SI4126_POWERDOWN_PDRB);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV,
+				     (channel == 14 ? 2110 : (2033 + (channel * 5))));
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44);
+		break;
+
+	case ADM8211_MAX2820:
+		adm8211_rf_write_syn_max2820(dev, 0x3,
+			(channel == 14 ? 0x054 : (0x7 + (channel * 5))));
+		break;
+
+	case ADM8211_AL2210L:
+		adm8211_rf_write_syn_al2210l(dev, 0x0,
+			(channel == 14 ? 0x229B4 : (0x22967 + (channel * 5))));
+		break;
+
+	default:
+		printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+		       dev->name, priv->transceiver_type);
+		break;
+	}
+
+	/* write BBP regs */
+	if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+
+	/* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */
+	/* TODO: remove if SMC 2635W doesn't need this */
+	if (priv->transceiver_type == ADM8211_RFMD2948) {
+		reg = le32_to_cpu(ADM8211_CSR_READ(GPIO));
+		reg &= 0xfffc0000;
+		reg |= ADM8211_CSR_GPIO_EN0;
+		if (channel != 14)
+			reg |= ADM8211_CSR_GPIO_O0;
+		ADM8211_CSR_WRITE(GPIO, cpu_to_le32(reg));
+	}
+
+	if (priv->transceiver_type == ADM8211_RFMD2958) {
+		/* set PCNT2 */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100);
+		/* set PCNT1 P_DESIRED/MID_BIAS */
+		reg = le16_to_cpu(priv->eeprom->cr49);
+		reg >>= 13;
+		reg <<= 15;
+		reg |= ant_power<<9;
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg);
+		/* set TXRX TX_GAIN */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 |
+			(priv->revid < ADM8211_REV_CA ? tx_power : 0));
+	} else {
+		reg = le32_to_cpu(ADM8211_CSR_READ(PLCPHD));
+		reg &= 0xff00ffff;
+		reg |= tx_power<<18;
+		ADM8211_CSR_WRITE(PLCPHD, cpu_to_le32(reg));
+	}
+
+	ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_SELRF |
+			  ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST));
+	ADM8211_CSR_READ(SYNRF);
+	mdelay(30);
+
+	/* RF3000 BBP */
+	if (priv->transceiver_type != ADM8211_RFMD2958)
+		adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT,
+				  tx_power<<2);
+	adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff);
+	adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh);
+	adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA
+			  ? priv->eeprom->cr28 : 0);
+	adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+
+	ADM8211_CSR_WRITE(SYNRF, 0);
+
+	} else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) {	/* Nothing to do for 
ADMtek BBP */
+		printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+		       dev->name, priv->bbp_type);
+	}
+
+	ADM8211_RESTORE();
+
+	/* update current channel for adhoc (and maybe AP mode) */
+	reg = le32_to_cpu(ADM8211_CSR_READ(CAP0));
+	reg &= ~0xF;
+	reg |= channel;
+	ADM8211_CSR_WRITE(CAP0, cpu_to_le32(reg));
+
+	return 0;
+}
+
+static void adm8211_update_mode(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	ADM8211_IDLE();
+
+	priv->soft_rx_crc = 0;
+	switch (priv->mode) {
+	case IEEE80211_IF_TYPE_STA:
+		priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
+		priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
+		break;
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->nar &= ~ADM8211_NAR_PR;
+		priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
+
+		/* don't trust the error bits on rev 0x20 and up in adhoc */
+		if (priv->revid >= ADM8211_REV_BA)
+			priv->soft_rx_crc = 1;
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
+		priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
+		break;
+	}
+
+	ADM8211_RESTORE();
+}
+
+static void adm8211_hw_init_syn(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	switch (priv->transceiver_type) {
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+		/* comments taken from ADMtek driver */
+		
+		/* Reset RF2958 after power on */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000);
+		/* Initialize RF VCO Core Bias to maximum */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F);
+		/* Initialize IF PLL */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03);
+		/* Initialize IF PLL Coarse Tuning */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F);
+		/* Initialize RF PLL */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403);
+		/* Initialize RF PLL Coarse Tuning */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F);
+		/* Initialize TX gain and filter BW (R9) */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x09,
+			(priv->transceiver_type == ADM8211_RFMD2958
+			? 0x10050 : 0x00050) );
+		/* Initialize CAL register */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8);
+		break;
+
+	case ADM8211_MAX2820:
+		adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E);
+		adm8211_rf_write_syn_max2820(dev, 0x2, 0x001);
+		adm8211_rf_write_syn_max2820(dev, 0x3, 0x054);
+		adm8211_rf_write_syn_max2820(dev, 0x4, 0x310);
+		adm8211_rf_write_syn_max2820(dev, 0x5, 0x000);
+		break;
+
+	case ADM8211_AL2210L:
+		adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C);
+		adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB);
+		adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F);
+		adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9);
+		adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280);
+		adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641);
+		adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130);
+		adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000);
+		adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F);
+		adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C);
+		adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000);
+		adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000);
+		break;
+
+	case ADM8211_RFMD2948:
+	default:
+		break;
+	}
+}
+
+static int adm8211_hw_init_bbp(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+
+	/* write addresses */
+	if (priv->bbp_type == ADM8211_TYPE_INTERSIL) {
+		ADM8211_CSR_WRITE(MMIWA,  __constant_cpu_to_le32(0x100E0C0A));
+		ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00007c7e));
+		ADM8211_CSR_WRITE(MMIRD1, __constant_cpu_to_le32(0x00100000));
+	} else if (priv->bbp_type == ADM8211_TYPE_RFMD ||
+		   priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+
+	/* check specific BBP type */
+	switch (priv->specific_bbptype) {
+	case ADM8211_BBP_RFMD3000:
+	case ADM8211_BBP_RFMD3002:
+		ADM8211_CSR_WRITE(MMIWA,  __constant_cpu_to_le32(0x00009101));
+		ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00000301));
+		break;
+
+	case ADM8211_BBP_ADM8011:
+		ADM8211_CSR_WRITE(MMIWA,  __constant_cpu_to_le32(0x00008903));
+		ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00001716));
+
+		reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+		reg &= ~ADM8211_BBPCTL_TYPE;
+		reg |= 0x5 << 18;
+		ADM8211_CSR_WRITE(BBPCTL, cpu_to_le32(reg));
+		break;
+	}
+
+	switch (priv->revid) {
+	case ADM8211_REV_CA:
+		if (priv->transceiver_type == ADM8211_RFMD2958 ||
+		    priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+		    priv->transceiver_type == ADM8211_RFMD2948)
+			ADM8211_CSR_WRITE(SYNCTL, __constant_cpu_to_le32(0x1 << 22));
+		else if (priv->transceiver_type == ADM8211_MAX2820 ||
+			 priv->transceiver_type == ADM8211_AL2210L)
+			ADM8211_CSR_WRITE(SYNCTL, __constant_cpu_to_le32(0x3 << 22));
+		break;
+
+	case ADM8211_REV_BA:
+		reg  = le32_to_cpu(ADM8211_CSR_READ(MMIRD1));
+		reg &= 0x0000FFFF;
+		reg |= 0x7e100000;
+		ADM8211_CSR_WRITE(MMIRD1, cpu_to_le32(reg));
+		break;
+
+	case ADM8211_REV_AB:
+	case ADM8211_REV_AF:
+	default:
+		ADM8211_CSR_WRITE(MMIRD1, __constant_cpu_to_le32(0x7e100000));
+		break;
+	}
+
+	/* For RFMD */
+	ADM8211_CSR_WRITE(MACTEST, __constant_cpu_to_le32(0x800));
+	}
+
+	adm8211_hw_init_syn(dev);
+
+	/* Set RF Power control IF pin to PE1+PHYRST# */
+	ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_SELRF |
+			  ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST));
+	ADM8211_CSR_READ(SYNRF);
+	mdelay(20);
+
+	/* write BBP regs */
+	if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+		/* RF3000 BBP */
+		/* another set:
+		 * 11: c8
+		 * 14: 14
+		 * 15: 50 (chan 1..13; chan 14: d0)
+		 * 1c: 00
+		 * 1d: 84
+		 */
+		adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80);
+		adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80); /* antenna selection: 
diversity */
+		adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74);
+		adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38);
+		adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40);
+
+		if (priv->eeprom->major_version < 2) {
+			adm8211_write_bbp(dev, 0x1c, 0x00);
+			adm8211_write_bbp(dev, 0x1d, 0x80);
+		} else {
+			if (priv->revid == ADM8211_REV_BA)
+				adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28);
+			else
+				adm8211_write_bbp(dev, 0x1c, 0x00);
+
+			adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+		}
+	} else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+	adm8211_write_bbp(dev, 0x00, 0xFF);	/* reset baseband */
+	adm8211_write_bbp(dev, 0x07, 0x0A);	/* antenna selection: diversity */
+
+	/* TODO: find documentation for this */
+	switch (priv->transceiver_type) {
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+		adm8211_write_bbp(dev, 0x00, 0x00);
+		adm8211_write_bbp(dev, 0x01, 0x00);
+		adm8211_write_bbp(dev, 0x02, 0x00);
+		adm8211_write_bbp(dev, 0x03, 0x00);
+		adm8211_write_bbp(dev, 0x06, 0x0f);
+		adm8211_write_bbp(dev, 0x09, 0x00);
+		adm8211_write_bbp(dev, 0x0a, 0x00);
+		adm8211_write_bbp(dev, 0x0b, 0x00);
+		adm8211_write_bbp(dev, 0x0c, 0x00);
+		adm8211_write_bbp(dev, 0x0f, 0xAA);
+		adm8211_write_bbp(dev, 0x10, 0x8c);
+		adm8211_write_bbp(dev, 0x11, 0x43);
+		adm8211_write_bbp(dev, 0x18, 0x40);
+		adm8211_write_bbp(dev, 0x20, 0x23);
+		adm8211_write_bbp(dev, 0x21, 0x02);
+		adm8211_write_bbp(dev, 0x22, 0x28);
+		adm8211_write_bbp(dev, 0x23, 0x30);
+		adm8211_write_bbp(dev, 0x24, 0x2d);
+		adm8211_write_bbp(dev, 0x28, 0x35);
+		adm8211_write_bbp(dev, 0x2a, 0x8c);
+		adm8211_write_bbp(dev, 0x2b, 0x81);
+		adm8211_write_bbp(dev, 0x2c, 0x44);
+		adm8211_write_bbp(dev, 0x2d, 0x0A);
+		adm8211_write_bbp(dev, 0x29, 0x40);
+		adm8211_write_bbp(dev, 0x60, 0x08);
+		adm8211_write_bbp(dev, 0x64, 0x01);
+		break;
+
+	case ADM8211_MAX2820:
+		adm8211_write_bbp(dev, 0x00, 0x00);
+		adm8211_write_bbp(dev, 0x01, 0x00);
+		adm8211_write_bbp(dev, 0x02, 0x00);
+		adm8211_write_bbp(dev, 0x03, 0x00);
+		adm8211_write_bbp(dev, 0x06, 0x0f);
+		adm8211_write_bbp(dev, 0x09, 0x05);
+		adm8211_write_bbp(dev, 0x0a, 0x02);
+		adm8211_write_bbp(dev, 0x0b, 0x00);
+		adm8211_write_bbp(dev, 0x0c, 0x0f);
+		adm8211_write_bbp(dev, 0x0f, 0x55);
+		adm8211_write_bbp(dev, 0x10, 0x8d);
+		adm8211_write_bbp(dev, 0x11, 0x43);
+		adm8211_write_bbp(dev, 0x18, 0x4a);
+		adm8211_write_bbp(dev, 0x20, 0x20);
+		adm8211_write_bbp(dev, 0x21, 0x02);
+		adm8211_write_bbp(dev, 0x22, 0x23);
+		adm8211_write_bbp(dev, 0x23, 0x30);
+		adm8211_write_bbp(dev, 0x24, 0x2d);
+		adm8211_write_bbp(dev, 0x2a, 0x8c);
+		adm8211_write_bbp(dev, 0x2b, 0x81);
+		adm8211_write_bbp(dev, 0x2c, 0x44);
+		adm8211_write_bbp(dev, 0x29, 0x4a);
+		adm8211_write_bbp(dev, 0x60, 0x2b);
+		adm8211_write_bbp(dev, 0x64, 0x01);
+		break;
+
+	case ADM8211_AL2210L:
+		adm8211_write_bbp(dev, 0x00, 0x00);
+		adm8211_write_bbp(dev, 0x01, 0x00);
+		adm8211_write_bbp(dev, 0x02, 0x00);
+		adm8211_write_bbp(dev, 0x03, 0x00);
+		adm8211_write_bbp(dev, 0x06, 0x0f);
+		adm8211_write_bbp(dev, 0x07, 0x05);
+		adm8211_write_bbp(dev, 0x08, 0x03);
+		adm8211_write_bbp(dev, 0x09, 0x00);
+		adm8211_write_bbp(dev, 0x0a, 0x00);
+		adm8211_write_bbp(dev, 0x0b, 0x00);
+		adm8211_write_bbp(dev, 0x0c, 0x10);
+		adm8211_write_bbp(dev, 0x0f, 0x55);
+		adm8211_write_bbp(dev, 0x10, 0x8d);
+		adm8211_write_bbp(dev, 0x11, 0x43);
+		adm8211_write_bbp(dev, 0x18, 0x4a);
+		adm8211_write_bbp(dev, 0x20, 0x20);
+		adm8211_write_bbp(dev, 0x21, 0x02);
+		adm8211_write_bbp(dev, 0x22, 0x23);
+		adm8211_write_bbp(dev, 0x23, 0x30);
+		adm8211_write_bbp(dev, 0x24, 0x2d);
+		adm8211_write_bbp(dev, 0x2a, 0xaa);
+		adm8211_write_bbp(dev, 0x2b, 0x81);
+		adm8211_write_bbp(dev, 0x2c, 0x44);
+		adm8211_write_bbp(dev, 0x29, 0xfa);
+		adm8211_write_bbp(dev, 0x60, 0x2d);
+		adm8211_write_bbp(dev, 0x64, 0x01);
+		break;
+
+	case ADM8211_RFMD2948:
+		break;
+
+	default:
+		printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+		       dev->name, priv->transceiver_type);
+		break;
+	}
+	} else {
+		printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+		       dev->name, priv->bbp_type);
+	}
+
+	ADM8211_CSR_WRITE(SYNRF, 0);
+
+	/* Set RF CAL control source to MAC control */
+	reg = le32_to_cpu(ADM8211_CSR_READ(SYNCTL));
+	reg |= ADM8211_SYNCTL_SELCAL;
+	ADM8211_CSR_WRITE(SYNCTL, cpu_to_le32(reg));
+
+	return 0;
+}
+
+// configures hw beacons/probe responses
+static int adm8211_set_rate(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+	int i = 0;
+	u8 rate_buf[12] = {0};
+
+	/* write supported rates */
+	if (priv->revid != ADM8211_REV_BA) {
+		rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+		for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+			rate_buf[i+1] = (adm8211_rates[i].rate/5) | 0x80;
+	} else {
+		/* workaround for rev BA specific bug */
+		rate_buf[0]=4;
+		rate_buf[1]=0x82;
+		rate_buf[2]=0x04;
+		rate_buf[3]=0x0b;
+		rate_buf[4]=0x16;
+	}
+	
+	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf, 
ARRAY_SIZE(adm8211_rates)+1);
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(PLCPHD)) & 0x00FFFFFF; /* keep bits 0-23 
*/
+	reg |= (1 << 15);	/* short preamble */
+	reg |= 110 << 24;
+	ADM8211_CSR_WRITE(PLCPHD, cpu_to_le32(reg));
+
+	/* MTMLT   = 512 TU (max TX MSDU lifetime)
+	 * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate)
+	 * SRTYLIM = 224 (short retry limit, value in TX header used by default) */
+	ADM8211_CSR_WRITE(TXLMT, cpu_to_le32((512<<16) | (110<<8) | (224<<0)));
+
+	return 0;
+}
+
+static void adm8211_hw_init(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+	u8 cacheline;
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+	reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+	reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+	if (!pci_set_mwi(priv->pdev)) {
+		reg |= (0x1<<24);
+		pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cacheline);
+
+		switch (cacheline) {
+		case  0x8: reg |= (0x1<<14);
+			   break;
+		case 0x16: reg |= (0x2<<14);
+			   break;
+		case 0x32: reg |= (0x3<<14);
+			   break;
+		  default: reg |= (0x0<<14);
+			   break;
+		}
+	}
+
+	ADM8211_CSR_WRITE(PAR, cpu_to_le32(reg));
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+	reg &= ~(0xF<<28);
+	reg |= ((1 << 28) | (1 << 31));
+	ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+
+	/* lose link after 4 lost beacons */
+	reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE;
+	ADM8211_CSR_WRITE(WCSR, cpu_to_le32(reg));
+
+	/* Disable APM, enable receive FIFO threshold, and set drain receive
+	 * threshold to store-and-forward */
+	reg = le32_to_cpu(ADM8211_CSR_READ(CMDR));
+	reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT);
+	reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF;
+	ADM8211_CSR_WRITE(CMDR, cpu_to_le32(reg));
+
+	adm8211_set_rate(dev);
+
+	/* 4-bit values:
+	 * PWR1UP   = 8 * 2 ms
+	 * PWR0PAPE = 8 us or 5 us
+	 * PWR1PAPE = 1 us or 3 us
+	 * PWR0TRSW = 5 us
+	 * PWR1TRSW = 12 us
+	 * PWR0PE2  = 13 us
+	 * PWR1PE2  = 1 us
+	 * PWR0TXPE = 8 or 6 */
+	if (priv->revid < ADM8211_REV_CA)
+		ADM8211_CSR_WRITE(TOFS2, __constant_cpu_to_le32(0x8815cd18));
+	else
+		ADM8211_CSR_WRITE(TOFS2, __constant_cpu_to_le32(0x8535cd16));
+
+	/* Enable store and forward for transmit */
+	priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB;
+	ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar));
+
+	/* Reset RF */
+	ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_RADIO));
+	ADM8211_CSR_READ(SYNRF);
+	mdelay(10);
+	ADM8211_CSR_WRITE(SYNRF, 0);
+	ADM8211_CSR_READ(SYNRF);
+	mdelay(5);
+
+	/* Set CFP Max Duration to 0x10 TU */
+	reg = le32_to_cpu(ADM8211_CSR_READ(CFPP));
+	reg &= ~(0xffff<<8);
+	reg |= 0x0010<<8;
+	ADM8211_CSR_WRITE(CFPP, cpu_to_le32(reg));
+
+	/* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us
+	 * TUCNT = 0x3ff - Tu counter 1024 us  */
+	ADM8211_CSR_WRITE(TOFS0, __constant_cpu_to_le32((0x16 << 24) | 0x3ff));
+
+	/* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us),
+	 * DIFS=50 us, EIFS=100 us */
+	if (priv->revid < ADM8211_REV_CA)
+		ADM8211_CSR_WRITE(IFST, __constant_cpu_to_le32(
+					(20 << 23) | (110 << 15) |
+					(50 << 9)  | 100));
+	else
+		ADM8211_CSR_WRITE(IFST, __constant_cpu_to_le32(
+					(20 << 23) | (24 << 15) |
+					(50 << 9)  | 100));
+
+	/* PCNT = 1 (MAC idle time awake/sleep, unit S)
+	 * RMRD = 2346 * 8 + 1 us (max RX duration)  */
+	ADM8211_CSR_WRITE(RMD, __constant_cpu_to_le32((1 << 16) | 18769));
+
+	/* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */
+	ADM8211_CSR_WRITE(RSPT, __constant_cpu_to_le32(0xffffff00));
+
+	/* Initialize BBP (and SYN) */
+	adm8211_hw_init_bbp(dev);
+
+	/* make sure interrupts are off */
+	ADM8211_CSR_WRITE(IER, 0);
+
+	/* ACK interrupts */
+	ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR));
+
+	/* Setup WEP (turns it off for now) */
+	reg = le32_to_cpu(ADM8211_CSR_READ(MACTEST));
+	reg &= ~(7<<20);
+	ADM8211_CSR_WRITE(MACTEST, cpu_to_le32(reg));
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(WEPCTL));
+	reg &= ~ADM8211_WEPCTL_WEPENABLE;
+	reg |= ADM8211_WEPCTL_WEPRXBYP;
+	ADM8211_CSR_WRITE(WEPCTL, cpu_to_le32(reg));
+
+	/* Clear the missed-packet counter. */
+	ADM8211_CSR_READ(LPC);
+
+	/* set mac address */
+	ADM8211_CSR_WRITE(PAR0, *(u32 *)dev->dev_addr);
+	ADM8211_CSR_WRITE(PAR1, *(u16 *)(dev->dev_addr + 4));
+}
+
+static int adm8211_hw_reset(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+	__le32 tmp;
+	int timeout = 50;
+
+	/* Power-on issue */
+	/* TODO: check if this is necessary */
+	ADM8211_CSR_WRITE(FRCTL, 0);
+
+	/* Reset the chip */
+	tmp = ADM8211_CSR_READ(PAR);
+	ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR);
+
+	while ((ADM8211_CSR_READ(PAR) & __constant_cpu_to_le32(ADM8211_PAR_SWR)) && 
timeout--)
+		mdelay(100);
+
+	if (timeout <= 0)
+		return -ETIMEDOUT;
+
+	ADM8211_CSR_WRITE(PAR, tmp);
+
+	if (priv->revid == ADM8211_REV_BA &&
+	    ( priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER
+	   || priv->transceiver_type == ADM8211_RFMD2958)) {
+		reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+		reg |= (1 << 4) | (1 << 5);
+		ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+	} else if (priv->revid == ADM8211_REV_CA) {
+		reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+		reg &= ~((1 << 4) | (1 << 5));
+		ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+	}
+
+	ADM8211_CSR_WRITE(FRCTL, 0);
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST0));
+	reg |= ADM8211_CSR_TEST0_EPRLD;	/* EEPROM Recall */
+	ADM8211_CSR_WRITE(CSR_TEST0, cpu_to_le32(reg));
+
+	adm8211_clear_sram(dev);
+
+	return 0;
+}
+
+static u64 adm8211_get_tsft(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 tsftl;
+	u64 tsft;
+
+	tsftl = le32_to_cpu(ADM8211_CSR_READ(TSFTL));
+	tsft = le32_to_cpu(ADM8211_CSR_READ(TSFTH));
+	tsft <<= 32;
+	tsft |= tsftl;
+
+	return tsft;
+}
+
+static void adm8211_set_interval(struct net_device *dev,
+				 unsigned short bi, unsigned short li)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+
+	/* BP (beacon interval) = data->beacon_interval
+	 * LI (listen interval) = data->listen_interval (in beacon intervals) */
+	reg = (bi << 16) | li;
+	ADM8211_CSR_WRITE(BPLI, cpu_to_le32(reg));
+}
+
+static void adm8211_set_bssid(struct net_device *dev, u8 *bssid)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u32 reg;
+
+	reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
+	ADM8211_CSR_WRITE(BSSID0, cpu_to_le32(reg));
+	reg = le32_to_cpu(ADM8211_CSR_READ(ABDA1));
+	reg &= 0x0000ffff;
+	reg |= (bssid[4] << 16) | (bssid[5] << 24);
+	ADM8211_CSR_WRITE(ABDA1, cpu_to_le32(reg));
+}
+
+static int adm8211_set_ssid(struct net_device *dev, u8 *ssid, size_t 
ssid_len)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	u8 buf[36];
+
+	if (ssid_len > 32)
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = ssid_len;
+	memcpy(buf + 1, ssid, ssid_len);
+	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
+	//adm8211_set_beacon(dev);
+	return 0;
+}
+
+static int adm8211_config(struct net_device *dev, struct ieee80211_conf 
*conf)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	if (conf->channel != priv->channel) {
+		priv->channel = conf->channel;
+		adm8211_rf_set_channel(dev, priv->channel);
+	}
+
+	return 0;
+}
+
+static int adm8211_config_interface(struct net_device *dev, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
+		adm8211_set_bssid(dev, conf->bssid);
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	}
+
+	if (conf->ssid_len != priv->ssid_len ||
+	    memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
+		adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
+		priv->ssid_len = conf->ssid_len;
+		memcpy(priv->ssid, conf->ssid, conf->ssid_len);
+	}
+
+	return 0;
+}
+static int adm8211_scan(struct net_device *dev, int state,
+			struct ieee80211_scan_conf *conf)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	if (state == IEEE80211_SCAN_START) {
+		priv->channel = conf->scan_channel;
+		adm8211_rf_set_channel(dev, conf->scan_channel);
+	} else if (state == IEEE80211_SCAN_END) {
+		priv->channel = conf->running_channel;
+		adm8211_rf_set_channel(dev, conf->running_channel);
+	}
+
+	return 0;
+}
+
+static int adm8211_add_interface(struct net_device *dev,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
+	if (priv->mode != IEEE80211_IF_TYPE_MGMT)
+		return -1;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->mode = conf->type;
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+static void adm8211_remove_interface(struct net_device *dev,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
+static int adm8211_init_rings(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	struct adm8211_desc *desc = NULL;
+	struct adm8211_ring_info *info;
+	unsigned int i;
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		desc = &priv->rx_ring[i];
+		desc->status = 0;
+		desc->length = cpu_to_le32(RX_PKT_SIZE);
+		priv->rx_buffers[i].skb = NULL;
+	}
+	/* Mark the end of RX ring; hw returns to base address after this
+	 * descriptor */
+	desc->length |= cpu_to_le32(RDES1_CONTROL_RER);
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		desc = &priv->rx_ring[i];
+		info = &priv->rx_buffers[i];
+
+		info->skb = dev_alloc_skb(RX_PKT_SIZE);
+		if (info->skb == NULL)
+			break;
+		info->mapping = pci_map_single(priv->pdev, info->skb->tail,
+					       RX_PKT_SIZE,
+					       PCI_DMA_FROMDEVICE);
+		info->skb->dev = dev;
+		desc->buffer1 = cpu_to_le32(info->mapping);
+		desc->status = cpu_to_le32( RDES0_STATUS_OWN | RDES0_STATUS_SQL );
+	}
+
+	/* Setup TX ring. TX buffers descriptors will be filled in as needed */
+	for (i = 0; i < priv->tx_ring_size; i++) {
+		desc = &priv->tx_ring[i];
+		info = &priv->tx_buffers[i];
+
+		info->skb = NULL;
+		info->mapping = 0;
+		desc->status = 0;
+	}
+	desc->length = cpu_to_le32(TDES1_CONTROL_TER);
+
+	priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0;
+	ADM8211_CSR_WRITE(RDB, cpu_to_le32(priv->rx_ring_dma));
+	ADM8211_CSR_WRITE(TDBD, cpu_to_le32(priv->tx_ring_dma));
+
+	return 0;
+}
+
+static void adm8211_free_rings(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int i;
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		if (!priv->rx_buffers[i].skb)
+			continue;
+
+		pci_unmap_single(
+			priv->pdev,
+			priv->rx_buffers[i].mapping,
+			RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+
+		dev_kfree_skb(priv->rx_buffers[i].skb);
+	}
+
+	for (i = 0; i < priv->tx_ring_size; i++) {
+		if (!priv->tx_buffers[i].skb)
+			continue;
+
+		pci_unmap_single(
+			priv->pdev,
+			priv->tx_buffers[i].mapping,
+			priv->tx_buffers[i].skb->len, PCI_DMA_TODEVICE);
+
+		dev_kfree_skb(priv->tx_buffers[i].skb);
+	}
+}
+
+static int adm8211_open(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	int retval;
+
+	/* Power up MAC and RF chips */
+	retval = adm8211_hw_reset(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: hardware reset failed\n", dev->name);
+		goto fail;
+	}
+
+	retval = adm8211_init_rings(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: failed to initialize rings\n", dev->name);
+		goto fail;
+	}
+
+	/* Init hardware */
+	adm8211_hw_init(dev);
+	adm8211_rf_set_channel(dev, priv->channel);
+
+	retval = request_irq(dev->irq, &adm8211_interrupt,
+			     SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		printk(KERN_ERR "%s: failed to register IRQ handler\n",
+		       dev->name);
+		goto fail;
+	}
+
+	ADM8211_CSR_WRITE(IER, __constant_cpu_to_le32(ADM8211_INTMASK));
+	adm8211_update_mode(dev);
+	ADM8211_CSR_WRITE(RDR, 0);
+
+	adm8211_set_interval(dev, 100, 10);
+	return 0;
+
+fail:
+	return retval;
+}
+
+static int adm8211_stop(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+	priv->nar = 0;
+	ADM8211_CSR_WRITE(NAR, 0);
+	ADM8211_CSR_WRITE(IER, 0);
+	ADM8211_CSR_READ(NAR);
+
+	free_irq(dev->irq, dev);
+
+	adm8211_free_rings(dev);
+
+	adm8211_hw_reset(dev);
+	return 0;
+}
+
+static int adm8211_reset(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	int retval = 0;
+
+	priv->nar = 0;
+	ADM8211_CSR_WRITE(NAR, 0);
+	ADM8211_CSR_WRITE(IER, 0);
+	ADM8211_CSR_READ(NAR);
+
+	adm8211_free_rings(dev);
+
+	retval = adm8211_hw_reset(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: hardware reset failed\n", dev->name);
+		goto fail;
+	}
+
+	retval = adm8211_init_rings(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: failed to initialize rings\n", dev->name);
+		goto fail;
+	}
+
+	adm8211_hw_init(dev);
+	adm8211_rf_set_channel(dev, priv->channel);
+
+	ADM8211_CSR_WRITE(IER, __constant_cpu_to_le32(ADM8211_INTMASK));
+	adm8211_update_mode(dev);
+	ADM8211_CSR_WRITE(RDR, 0);
+
+fail:
+	return retval;
+}
+
+static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, 
int len,
+				   int plcp_signal, int short_preamble)
+{
+	/* Alternative calculation from NetBSD: */
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE	144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE	72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR	24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR	48
+#define IEEE80211_DUR_DS_SLOW_ACK	112
+#define IEEE80211_DUR_DS_FAST_ACK	56
+#define IEEE80211_DUR_DS_SLOW_CTS	112
+#define IEEE80211_DUR_DS_FAST_CTS	56
+#define IEEE80211_DUR_DS_SLOT		20
+#define IEEE80211_DUR_DS_SIFS		10
+
+	int remainder;
+
+	*dur = (80 * (24 + payload_len) + plcp_signal - 1)
+		/ plcp_signal;
+
+	if (plcp_signal <= PLCP_SIGNAL_2M)
+		/* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */
+		*dur += 3 * (IEEE80211_DUR_DS_SIFS +
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE +
+			     IEEE80211_DUR_DS_FAST_PLCPHDR) +
+			     IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;
+	else
+		/* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */
+		*dur += 3 * (IEEE80211_DUR_DS_SIFS +
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE +
+			     IEEE80211_DUR_DS_FAST_PLCPHDR) +
+			     IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;
+
+	/* lengthen duration if long preamble */
+	if (!short_preamble)
+		*dur +=	3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+			3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+			     IEEE80211_DUR_DS_FAST_PLCPHDR);
+
+
+	*plcp = (80 * len) / plcp_signal;
+	remainder = (80 * len) % plcp_signal;
+	if (plcp_signal == PLCP_SIGNAL_11M &&
+	    remainder <= 30 && remainder > 0)
+		*plcp = (*plcp | 0x8000) + 1;
+	else if (remainder)
+		(*plcp)++;
+}
+
+/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
+static void adm8211_tx_raw(struct net_device *dev, struct sk_buff *skb,
+			   u16 plcp_signal, struct ieee80211_tx_control *control, int unicast)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned long flags;
+	dma_addr_t mapping;
+	unsigned entry;
+	u32 flag;
+
+	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size / 2)
+		flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+	else if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
+		flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+	else if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size - 2)
+		flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+	else {
+		flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+		printk(KERN_DEBUG "%s: Yikes, this shouldn't happen!\n", dev->name);
+		netif_stop_queue(dev);
+	}
+
+	entry = priv->cur_tx % priv->tx_ring_size;
+
+	priv->tx_buffers[entry].skb = skb;
+	priv->tx_buffers[entry].mapping = mapping;
+	memcpy(&priv->tx_buffers[entry].tx_status.control, control, 
sizeof(*control));
+	priv->tx_buffers[entry].unicast = unicast;
+	priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
+
+	if (entry == priv->tx_ring_size - 1)
+		flag |= TDES1_CONTROL_TER;
+	priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);
+
+	/* Set TX rate (SIGNAL field in PLCP PPDU format) */
+	flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;
+	priv->tx_ring[entry].status = cpu_to_le32(flag);
+
+	priv->cur_tx++;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Trigger transmit poll */
+	ADM8211_CSR_WRITE(TDR, 0);
+
+	dev->trans_start = jiffies;
+}
+
+/* Put adm8211_tx_hdr on skb and transmit */
+static int adm8211_tx(struct net_device *dev, struct sk_buff *skb,
+		      struct ieee80211_tx_control *control)
+{
+	struct adm8211_tx_hdr *txhdr;
+	struct ieee80211_hdr *hdr;
+	u16 fc_;
+	__le16 fc;
+	u8 dst[ETH_ALEN];
+	size_t payload_len, hdrlen;
+	int plcp, dur, len;
+	int plcp_signal;
+	int short_preamble;
+
+	if (control->tx_rate < 0) {
+		short_preamble = 1;
+		plcp_signal = -control->tx_rate;
+	} else {
+		short_preamble = 0;
+		plcp_signal = control->tx_rate;
+	}
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc  = hdr->frame_control;
+	fc_ = le16_to_cpu(fc);
+	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
+
+	hdrlen = ieee80211_get_hdrlen(fc_);
+	skb_pull(skb, hdrlen);
+	fc_ &= ~WLAN_FC_ISWEP;
+	payload_len = skb->len;
+
+	if (skb_headroom(skb) < sizeof(struct adm8211_tx_hdr)) {
+		if (pskb_expand_head(skb, sizeof(struct adm8211_tx_hdr), 0, GFP_ATOMIC)) {
+			printk(KERN_DEBUG "%s: failed to allocate room for TX "
+			       "header\n", dev->name);
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
+	memset(txhdr, 0, sizeof(*txhdr));
+	memcpy(txhdr->da, dst, ETH_ALEN);
+	txhdr->signal = plcp_signal;
+	txhdr->frame_body_size = cpu_to_le16(payload_len);
+	txhdr->frame_control = fc;
+
+	len = hdrlen + payload_len + FCS_LEN;
+	if (fc_ & WLAN_FC_ISWEP)
+		len += 8;
+
+	txhdr->frag = cpu_to_le16(0x0FFF);
+	adm8211_calc_durations(&dur, &plcp, payload_len,
+			       len, plcp_signal, short_preamble);
+	txhdr->plcp_frag_head_len = cpu_to_le16(plcp);
+	txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);
+	txhdr->dur_frag_head = cpu_to_le16(dur);
+	txhdr->dur_frag_tail = cpu_to_le16(dur);
+
+	txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);
+
+	if (short_preamble)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+
+	if (control->use_rts_cts)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+
+	if (fc_ & WLAN_FC_ISWEP)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
+
+	txhdr->retry_limit = control->retry_limit;
+
+	adm8211_tx_raw(dev, skb, plcp_signal, 
control, !is_multicast_ether_addr(dst));
+
+	return NETDEV_TX_OK;
+}
+
+static int adm8211_alloc_rings(struct net_device *dev)
+{
+	struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+	unsigned int ring_size;
+
+	priv->rx_buffers = kmalloc(sizeof(struct adm8211_ring_info) *
+				(priv->rx_ring_size + priv->tx_ring_size), GFP_KERNEL);
+	if (!priv->rx_buffers)
+		return -ENOMEM;
+	
+	priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct 
adm8211_ring_info) * priv->tx_ring_size;
+
+	/* Allocate TX/RX descriptors */
+	ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
+		    sizeof(struct adm8211_desc) * priv->tx_ring_size;
+	priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,
+					     &priv->rx_ring_dma);
+
+	if (!priv->rx_ring) {
+		kfree(priv->rx_buffers);
+		priv->rx_buffers = priv->tx_buffers = NULL;
+		return -ENOMEM;
+	}
+
+	priv->tx_ring = (struct adm8211_desc *) (priv->rx_ring + 
priv->rx_ring_size);
+	priv->tx_ring_dma = priv->rx_ring_dma +
+		sizeof(struct adm8211_desc) * priv->rx_ring_size;
+
+	return 0;
+}
+
+static int __devinit adm8211_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	struct net_device *dev;
+	struct ieee80211_hw *hw;
+	struct adm8211_priv *priv;
+	unsigned long mem_addr, mem_len;
+	unsigned int io_addr, io_len;
+	int err;
+	u32 reg;
+
+#ifndef MODULE
+	static unsigned int cardidx;
+	if (!cardidx++)
+		printk(version);
+#endif
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n", 
pci_name(pdev));
+		return err;
+	}
+
+	io_addr = pci_resource_start(pdev, 0);
+	io_len = pci_resource_len(pdev, 0);
+	mem_addr = pci_resource_start(pdev, 1);
+	mem_len = pci_resource_len(pdev, 1);
+	if (io_len < 256 || mem_len < 1024) {
+		printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", pci_name(pdev));
+		goto err_disable_pdev;
+	}
+
+
+	/* check signature */
+	pci_read_config_dword(pdev, 0x80 /* CR32 */, &reg);
+	if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {
+		printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n", pci_name(pdev), 
reg);
+		goto err_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, "adm8211");
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n", 
pci_name(pdev));
+		return err; /* someone else grabbed it? don't disable it */
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+	    pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR "%s (adm8211): No suitable DMA available\n", 
pci_name(pdev));
+		goto err_free_reg;
+	}
+
+	pci_set_master(pdev);
+
+	dev = ieee80211_alloc_hw(sizeof(*priv), NULL);
+	if (!dev) {
+		printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n", pci_name(pdev));
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+	priv = ieee80211_dev_hw_data(dev);
+	hw = &priv->hw;
+	priv->pdev = pdev;
+
+	spin_lock_init(&priv->lock);
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	pci_set_drvdata(pdev, dev);
+	priv->msg_enable = netif_msg_init(debug, NETIF_MSG_DRV | NETIF_MSG_PROBE);
+
+	priv->map = pci_iomap(pdev, 1, mem_len);
+	if (!priv->map)
+		priv->map = pci_iomap(pdev, 0, io_len);
+
+	if (!priv->map) {
+		printk(KERN_ERR "%s (adm8211): Cannot map device memory\n", 
pci_name(pdev));
+		goto err_free_dev;
+	}
+
+	dev->mem_start = mem_addr;
+	dev->mem_end = mem_addr + mem_len;
+	dev->base_addr = io_addr;
+	dev->irq = pdev->irq;
+
+	priv->rx_ring_size = rx_ring_size;
+	priv->tx_ring_size = tx_ring_size;
+	
+	if (adm8211_alloc_rings(dev)) {
+		printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n", 
pci_name(pdev));
+		goto err_iounmap;
+	}
+
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid);
+
+	put_unaligned(ADM8211_CSR_READ(PAR0), (u32 *) dev->dev_addr);
+	put_unaligned(ADM8211_CSR_READ(PAR1) & (__force u32) __constant_cpu_to_le32
(0xffff),
+		      (u16 *) &dev->dev_addr[4]);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s (adm8211): Invalid hwaddr! Using randomly generated 
hwaddr\n", pci_name(pdev));
+		random_ether_addr(dev->dev_addr);
+	}
+
+	hw->version = 2;
+	hw->name = "adm8211";
+	hw->host_gen_beacon = 0;
+	hw->device_hides_wep = 0;
+	hw->rx_includes_fcs = 0;	// however, FCS is kept in promisc mode
+	hw->host_broadcast_ps_buffering = 0;
+	hw->wep_include_iv = 1;
+	hw->data_nullfunc_ack = 0;
+	hw->no_tkip_wmm_hwaccel = 1;
+	hw->extra_hdr_room = 0;
+	hw->device_strips_mic = 0;
+	hw->monitor_during_oper = 0;
+	hw->fraglist = 0;
+	hw->channel_change_time = 1000;
+
+	hw->num_modes = 1;
+	hw->modes = priv->modes;
+	priv->modes[0].mode = MODE_IEEE80211B;
+	/* channel info filled in by adm8211_read_eeprom */
+	memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+	priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+	priv->modes[0].rates = priv->rates;
+
+	hw->tx = adm8211_tx;
+	hw->reset = adm8211_reset;
+	hw->open = adm8211_open;
+	hw->stop = adm8211_stop;
+	hw->add_interface = adm8211_add_interface;
+	hw->remove_interface = adm8211_remove_interface;
+
+	hw->config = adm8211_config;
+	hw->config_interface = adm8211_config_interface;
+	hw->set_multicast_list = adm8211_set_rx_mode;
+	hw->passive_scan = adm8211_scan;
+	hw->get_stats = adm8211_get_stats;
+	hw->get_tsf = adm8211_get_tsft;
+	hw->get_tx_stats = adm8211_get_tx_stats;
+	hw->queues = 1;		// ADM8211C supports more, maybe ADM8211B
+
+	priv->retry_limit = 3;
+	priv->ant_power = 0x40;
+	priv->tx_power = 0x40;
+	priv->lpf_cutoff = 0xFF;
+	priv->lnags_threshold = 0xFF;
+
+	/* Power-on issue. EEPROM won't read correctly without */
+	if (priv->revid >= ADM8211_REV_BA) {
+		ADM8211_CSR_WRITE(FRCTL, 0);
+		ADM8211_CSR_READ(FRCTL);
+		ADM8211_CSR_WRITE(FRCTL, 1);
+		ADM8211_CSR_READ(FRCTL);
+		mdelay(100);
+	}
+
+	err = adm8211_read_eeprom(dev);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot allocate eeprom buffer\n", 
pci_name(pdev));
+		goto err_free_desc;
+	}
+
+	priv->channel = priv->modes[0].channels[0].chan;
+
+	err = ieee80211_register_hw(dev, &priv->hw);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot register netdevice\n", 
pci_name(pdev));
+		goto err_free_desc;
+	}
+
+	printk("%s: hwaddr " MAC_FMT ", Rev 0x%02x\n",
+	       dev->name, MAC_ARG(dev->dev_addr), priv->revid);
+
+	return 0;
+
+ err_free_desc:
+	pci_free_consistent(pdev,
+			    sizeof(struct adm8211_desc) * priv->rx_ring_size +
+			    sizeof(struct adm8211_desc) * priv->tx_ring_size,
+			    priv->rx_ring, priv->rx_ring_dma);
+	kfree(priv->rx_buffers);
+
+ err_iounmap:
+	pci_iounmap(pdev, priv->map);
+
+ err_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	ieee80211_free_hw(dev);
+
+ err_free_reg:
+	pci_release_regions(pdev);
+
+ err_disable_pdev:
+	pci_disable_device(pdev);
+	return err;
+}
+
+
+static void __devexit adm8211_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct adm8211_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+
+	priv = ieee80211_dev_hw_data(dev);
+
+	pci_free_consistent(pdev,
+			    sizeof(struct adm8211_desc) * priv->rx_ring_size +
+			    sizeof(struct adm8211_desc) * priv->tx_ring_size,
+			    priv->rx_ring, priv->rx_ring_dma);
+
+	kfree(priv->rx_buffers);
+	kfree(priv->eeprom);
+	pci_iounmap(pdev, priv->map);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	ieee80211_free_hw(dev);
+}
+
+
+#ifdef CONFIG_PM
+static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	netif_device_detach(dev);
+
+	if (dev->flags & IFF_UP)
+		dev->stop(dev);
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+	return 0;
+}
+
+static int adm8211_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (dev->flags & IFF_UP)
+		dev->open(dev);
+
+	netif_device_attach(dev);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);
+
+/* TODO: enable_wake */
+static struct pci_driver adm8211_driver = {
+	.name		= "adm8211",
+	.id_table	= adm8211_pci_id_table,
+	.probe		= adm8211_probe,
+	.remove		= __devexit_p(adm8211_remove),
+#ifdef CONFIG_PM
+	.suspend	= adm8211_suspend,
+	.resume		= adm8211_resume,
+#endif /* CONFIG_PM */
+};
+
+
+
+static int __init adm8211_init(void)
+{
+#ifdef MODULE
+	printk(version);
+#endif
+
+	return pci_register_driver(&adm8211_driver);
+}
+
+
+static void __exit adm8211_exit(void)
+{
+	pci_unregister_driver(&adm8211_driver);
+}
+
+
+module_init(adm8211_init);
+module_exit(adm8211_exit);
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.h 
b/drivers/net/wireless/d80211/adm8211/adm8211.h
new file mode 100644
index 0000000..c215013
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.h
@@ -0,0 +1,631 @@
+#ifndef ADM8211_H
+#define ADM8211_H
+
+/* ADM8211 Registers */
+
+/* CR32 (SIG) signature */
+#define ADM8211_SIG1		0x82011317 /* ADM8211A */
+#define ADM8211_SIG2		0x82111317 /* ADM8211B/ADM8211C */
+
+#define ADM8211_CSR_READ(r) ioread32(&priv->map->r)
+#define ADM8211_CSR_WRITE(r, val) iowrite32((__force u32)(val), 
&priv->map->r)
+
+/* CSR (Host Control and Status Registers) */
+struct adm8211_csr {
+	__le32 PAR;		/* 0x00 CSR0 */
+	__le32 FRCTL;		/* 0x04 CSR0A */
+	__le32 TDR;		/* 0x08 CSR1 */
+	__le32 WTDP;		/* 0x0C CSR1A */
+	__le32 RDR;		/* 0x10 CSR2 */
+	__le32 WRDP;		/* 0x14 CSR2A */
+	__le32 RDB;		/* 0x18 CSR3 */
+	__le32 TDBH;		/* 0x1C CSR3A */
+	__le32 TDBD;		/* 0x20 CSR4 */
+	__le32 TDBP;		/* 0x24 CSR4A */
+	__le32 STSR;		/* 0x28 CSR5 */
+	__le32 TDBB;		/* 0x2C CSR5A */
+	__le32 NAR;		/* 0x30 CSR6 */
+	__le32 CSR6A;		/* reserved */
+	__le32 IER;		/* 0x38 CSR7 */
+	__le32 TKIPSCEP;	/* 0x3C CSR7A */	
+	__le32 LPC;		/* 0x40 CSR8 */
+	__le32 CSR_TEST1;	/* 0x44 CSR8A */
+	__le32 SPR;		/* 0x48 CSR9 */
+	__le32 CSR_TEST0;	/* 0x4C CSR9A */
+	__le32 WCSR;		/* 0x50 CSR10 */
+	__le32 WPDR;		/* 0x54 CSR10A */
+	__le32 GPTMR;		/* 0x58 CSR11 */
+	__le32 GPIO;		/* 0x5C CSR11A */
+	__le32 BBPCTL;		/* 0x60 CSR12 */
+	__le32 SYNCTL;		/* 0x64 CSR12A */
+	__le32 PLCPHD;		/* 0x68 CSR13 */
+	__le32 MMIWA;		/* 0x6C CSR13A */
+	__le32 MMIRD0;		/* 0x70 CSR14 */
+	__le32 MMIRD1;		/* 0x74 CSR14A */
+	__le32 TXBR;		/* 0x78 CSR15 */
+	__le32 SYNDATA;		/* 0x7C CSR15A */
+	__le32 ALCS;		/* 0x80 CSR16 */
+	__le32 TOFS2;		/* 0x84 CSR17 */
+	__le32 CMDR;		/* 0x88 CSR18 */
+	__le32 PCIC;		/* 0x8C CSR19 */
+	__le32 PMCSR;		/* 0x90 CSR20 */
+	__le32 PAR0;		/* 0x94 CSR21 */
+	__le32 PAR1;		/* 0x98 CSR22 */
+	__le32 MAR0;		/* 0x9C CSR23 */
+	__le32 MAR1;		/* 0xA0 CSR24 */
+	__le32 ATIMDA0;		/* 0xA4 CSR25 */
+	__le32 ABDA1;		/* 0xA8 CSR26 */
+	__le32 BSSID0;		/* 0xAC CSR27 */
+	__le32 TXLMT;		/* 0xB0 CSR28 */
+	__le32 MIBCNT;		/* 0xB4 CSR29 */
+	__le32 BCNT;		/* 0xB8 CSR30 */
+	__le32 TSFTH;		/* 0xBC CSR31 */
+	__le32 TSC;		/* 0xC0 CSR32 */
+	__le32 SYNRF;		/* 0xC4 CSR33 */
+	__le32 BPLI;		/* 0xC8 CSR34 */
+	__le32 CAP0;		/* 0xCC CSR35 */
+	__le32 CAP1;		/* 0xD0 CSR36 */
+	__le32 RMD;		/* 0xD4 CSR37 */
+	__le32 CFPP;		/* 0xD8 CSR38 */
+	__le32 TOFS0;		/* 0xDC CSR39 */
+	__le32 TOFS1;		/* 0xE0 CSR40 */
+	__le32 IFST;		/* 0xE4 CSR41 */
+	__le32 RSPT;		/* 0xE8 CSR42 */
+	__le32 TSFTL;		/* 0xEC CSR43 */
+	__le32 WEPCTL;		/* 0xF0 CSR44 */
+	__le32 WESK;		/* 0xF4 CSR45 */
+	__le32 WEPCNT;		/* 0xF8 CSR46 */
+	__le32 MACTEST;		/* 0xFC CSR47 */
+	__le32 FER;		/* 0x100 */
+	__le32 FEMR;		/* 0x104 */
+	__le32 FPSR;		/* 0x108 */
+	__le32 FFER;		/* 0x10C */
+} __attribute__ ((packed));
+
+/* CSR0 - PAR (PCI Address Register) */
+#define ADM8211_PAR_MWIE	(1 << 24)
+#define ADM8211_PAR_MRLE	(1 << 23)
+#define ADM8211_PAR_MRME	(1 << 21)
+#define ADM8211_PAR_RAP		((1 << 18) | (1 << 17))
+#define ADM8211_PAR_CAL		((1 << 15) | (1 << 14))
+#define ADM8211_PAR_PBL		0x00003f00
+#define ADM8211_PAR_BLE		(1 << 7)
+#define ADM8211_PAR_DSL		0x0000007c
+#define ADM8211_PAR_BAR		(1 << 1)
+#define ADM8211_PAR_SWR		(1 << 0)
+
+/* CSR1 - FRCTL (Frame Control Register) */
+#define ADM8211_FRCTL_PWRMGT	(1 << 31)
+#define ADM8211_FRCTL_MAXPSP	(1 << 27)
+#define ADM8211_FRCTL_DRVPRSP	(1 << 26)
+#define ADM8211_FRCTL_DRVBCON	(1 << 25)
+#define ADM8211_FRCTL_AID	0x0000ffff
+#define ADM8211_FRCTL_AID_ON	0x0000c000
+
+/* CSR5 - STSR (Status Register) */
+#define ADM8211_STSR_PCF	(1 << 31)
+#define ADM8211_STSR_BCNTC	(1 << 30)
+#define ADM8211_STSR_GPINT	(1 << 29)
+#define ADM8211_STSR_LinkOff	(1 << 28)
+#define ADM8211_STSR_ATIMTC	(1 << 27)
+#define ADM8211_STSR_TSFTF	(1 << 26)
+#define ADM8211_STSR_TSCZ	(1 << 25)
+#define ADM8211_STSR_LinkOn	(1 << 24)
+#define ADM8211_STSR_SQL	(1 << 23)
+#define ADM8211_STSR_WEPTD	(1 << 22)
+#define ADM8211_STSR_ATIME	(1 << 21)
+#define ADM8211_STSR_TBTT	(1 << 20)
+#define ADM8211_STSR_NISS	(1 << 16)
+#define ADM8211_STSR_AISS	(1 << 15)
+#define ADM8211_STSR_TEIS	(1 << 14)
+#define ADM8211_STSR_FBE	(1 << 13)
+#define ADM8211_STSR_REIS	(1 << 12)
+#define ADM8211_STSR_GPTT	(1 << 11)
+#define ADM8211_STSR_RPS	(1 << 8)
+#define ADM8211_STSR_RDU	(1 << 7)
+#define ADM8211_STSR_RCI	(1 << 6)
+#define ADM8211_STSR_TUF	(1 << 5)
+#define ADM8211_STSR_TRT	(1 << 4)
+#define ADM8211_STSR_TLT	(1 << 3)
+#define ADM8211_STSR_TDU	(1 << 2)
+#define ADM8211_STSR_TPS	(1 << 1)
+#define ADM8211_STSR_TCI	(1 << 0)
+
+/* CSR6 - NAR (Network Access Register) */
+#define ADM8211_NAR_TXCF	(1 << 31)
+#define ADM8211_NAR_HF		(1 << 30)
+#define ADM8211_NAR_UTR		(1 << 29)
+#define ADM8211_NAR_SQ		(1 << 28)
+#define ADM8211_NAR_CFP		(1 << 27)
+#define ADM8211_NAR_SF		(1 << 21)
+#define ADM8211_NAR_TR		((1 << 15) | (1 << 14))
+#define ADM8211_NAR_ST		(1 << 13)
+#define ADM8211_NAR_OM		((1 << 11) | (1 << 10))
+#define ADM8211_NAR_MM		(1 << 7)
+#define ADM8211_NAR_PR		(1 << 6)
+#define ADM8211_NAR_EA		(1 << 5)
+#define ADM8211_NAR_PB		(1 << 3)
+#define ADM8211_NAR_STPDMA	(1 << 2)
+#define ADM8211_NAR_SR		(1 << 1)
+#define ADM8211_NAR_CTX		(1 << 0)
+
+#define ADM8211_IDLE()		do { \
+	if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) {\
+		ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~(ADM8211_NAR_SR | 
ADM8211_NAR_ST)));\
+		ADM8211_CSR_READ(NAR);\
+		mdelay(20);\
+	}\
+} while (0)
+
+#define ADM8211_IDLE_RX()	do { \
+	if (priv->nar & ADM8211_NAR_SR) {\
+		ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~ADM8211_NAR_SR));\
+		ADM8211_CSR_READ(NAR);\
+		mdelay(20);\
+	}\
+} while (0)
+
+#define ADM8211_IDLE_TX()	do { \
+	if (priv->nar & ADM8211_NAR_ST) {\
+		ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~ADM8211_NAR_ST));\
+		ADM8211_CSR_READ(NAR);\
+		mdelay(20);\
+	}\
+} while (0)
+
+#define ADM8211_RESTORE()	do { \
+	if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \
+		ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar));\
+} while (0)
+
+/* CSR7 - IER (Interrupt Enable Register) */
+#define ADM8211_IER_PCFIE	(1 << 31)
+#define ADM8211_IER_BCNTCIE	(1 << 30)
+#define ADM8211_IER_GPIE	(1 << 29)
+#define ADM8211_IER_LinkOffIE	(1 << 28)
+#define ADM8211_IER_ATIMTCIE	(1 << 27)
+#define ADM8211_IER_TSFTFIE	(1 << 26)
+#define ADM8211_IER_TSCZE	(1 << 25)
+#define ADM8211_IER_LinkOnIE	(1 << 24)
+#define ADM8211_IER_SQLIE	(1 << 23)
+#define ADM8211_IER_WEPIE	(1 << 22)
+#define ADM8211_IER_ATIMEIE	(1 << 21)
+#define ADM8211_IER_TBTTIE	(1 << 20)
+#define ADM8211_IER_NIE		(1 << 16)
+#define ADM8211_IER_AIE		(1 << 15)
+#define ADM8211_IER_TEIE	(1 << 14)
+#define ADM8211_IER_FBEIE	(1 << 13)
+#define ADM8211_IER_REIE	(1 << 12)
+#define ADM8211_IER_GPTIE	(1 << 11)
+#define ADM8211_IER_RSIE	(1 << 8)
+#define ADM8211_IER_RUIE	(1 << 7)
+#define ADM8211_IER_RCIE	(1 << 6)
+#define ADM8211_IER_TUIE	(1 << 5)
+#define ADM8211_IER_TRTIE	(1 << 4)
+#define ADM8211_IER_TLTTIE	(1 << 3)
+#define ADM8211_IER_TDUIE	(1 << 2)
+#define ADM8211_IER_TPSIE	(1 << 1)
+#define ADM8211_IER_TCIE	(1 << 0)
+
+/* CSR9 - SPR (Serial Port Register) */
+#define ADM8211_SPR_SRS		(1 << 11)
+#define ADM8211_SPR_SDO		(1 << 3)
+#define ADM8211_SPR_SDI		(1 << 2)
+#define ADM8211_SPR_SCLK	(1 << 1)
+#define ADM8211_SPR_SCS		(1 << 0)
+
+/* CSR9A - CSR_TEST0 */
+#define ADM8211_CSR_TEST0_EPNE	(1 << 18)
+#define ADM8211_CSR_TEST0_EPSNM	(1 << 17)
+#define ADM8211_CSR_TEST0_EPTYP	(1 << 16)
+#define ADM8211_CSR_TEST0_EPRLD	(1 << 15)
+
+/* CSR10 - WCSR (Wake-up Control/Status Register) */
+#define ADM8211_WCSR_CRCT	(1 << 30)
+#define ADM8211_WCSR_TSFTWE	(1 << 20)
+#define ADM8211_WCSR_TIMWE	(1 << 19)
+#define ADM8211_WCSR_ATIMWE	(1 << 18)
+#define ADM8211_WCSR_KEYWE	(1 << 17)
+#define ADM8211_WCSR_MPRE	(1 << 9)
+#define ADM8211_WCSR_LSOE	(1 << 8)
+#define ADM8211_WCSR_KEYUP	(1 << 6)
+#define ADM8211_WCSR_TSFTW	(1 << 5)
+#define ADM8211_WCSR_TIMW	(1 << 4)
+#define ADM8211_WCSR_ATIMW	(1 << 3)
+#define ADM8211_WCSR_MPR	(1 << 1)
+#define ADM8211_WCSR_LSO	(1 << 0)
+
+/* CSR11A - GPIO */
+#define ADM8211_CSR_GPIO_EN5	(1 << 17)
+#define ADM8211_CSR_GPIO_EN4	(1 << 16)
+#define ADM8211_CSR_GPIO_EN3	(1 << 15)
+#define ADM8211_CSR_GPIO_EN2	(1 << 14)
+#define ADM8211_CSR_GPIO_EN1	(1 << 13)
+#define ADM8211_CSR_GPIO_EN0	(1 << 12)
+#define ADM8211_CSR_GPIO_O5	(1 << 11)
+#define ADM8211_CSR_GPIO_O4	(1 << 10)
+#define ADM8211_CSR_GPIO_O3	(1 << 9)
+#define ADM8211_CSR_GPIO_O2	(1 << 8)
+#define ADM8211_CSR_GPIO_O1	(1 << 7)
+#define ADM8211_CSR_GPIO_O0	(1 << 6)
+#define ADM8211_CSR_GPIO_IN	0x0000003f
+
+/* CSR12 - BBPCTL (BBP Control port) */
+#define ADM8211_BBPCTL_MMISEL	(1 << 31)
+#define ADM8211_BBPCTL_SPICADD  (0x7F << 24)
+#define ADM8211_BBPCTL_RF3000	(0x20 << 24)
+#define ADM8211_BBPCTL_TXCE	(1 << 23)
+#define ADM8211_BBPCTL_RXCE	(1 << 22)
+#define ADM8211_BBPCTL_CCAP	(1 << 21)
+#define ADM8211_BBPCTL_TYPE	0x001c0000
+#define ADM8211_BBPCTL_WR	(1 << 17)
+#define ADM8211_BBPCTL_RD	(1 << 16)
+#define ADM8211_BBPCTL_ADDR	0x0000ff00
+#define ADM8211_BBPCTL_DATA	0x000000ff
+
+/* CSR12A - SYNCTL (Synthesizer Control port) */
+#define ADM8211_SYNCTL_WR	(1 << 31)
+#define ADM8211_SYNCTL_RD	(1 << 30)
+#define ADM8211_SYNCTL_CS0	(1 << 29)
+#define ADM8211_SYNCTL_CS1	(1 << 28)
+#define ADM8211_SYNCTL_CAL	(1 << 27)
+#define ADM8211_SYNCTL_SELCAL	(1 << 26)
+#define ADM8211_SYNCTL_RFtype	((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFMD	(1 << 22)
+#define ADM8211_SYNCTL_GENERAL	(0x7 << 22)
+/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
+
+/* CSR18 - CMDR (Command Register) */
+#define ADM8211_CMDR_PM		(1 << 19)
+#define ADM8211_CMDR_APM	(1 << 18)
+#define ADM8211_CMDR_RTE	(1 << 4)
+#define ADM8211_CMDR_DRT	((1 << 3) | (1 << 2))
+#define ADM8211_CMDR_DRT_8DW	(0x0 << 2)
+#define ADM8211_CMDR_DRT_16DW	(0x1 << 2)
+#define ADM8211_CMDR_DRT_SF	(0x2 << 2)
+
+/* CSR33 - SYNRF (SYNRF direct control) */
+#define ADM8211_SYNRF_SELSYN	(1 << 31)
+#define ADM8211_SYNRF_SELRF	(1 << 30)
+#define ADM8211_SYNRF_LERF	(1 << 29)
+#define ADM8211_SYNRF_LEIF	(1 << 28)
+#define ADM8211_SYNRF_SYNCLK	(1 << 27)
+#define ADM8211_SYNRF_SYNDATA	(1 << 26)
+#define ADM8211_SYNRF_PE1	(1 << 25)
+#define ADM8211_SYNRF_PE2	(1 << 24)
+#define ADM8211_SYNRF_PA_PE	(1 << 23)
+#define ADM8211_SYNRF_TR_SW	(1 << 22)
+#define ADM8211_SYNRF_TR_SWN	(1 << 21)
+#define ADM8211_SYNRF_RADIO	(1 << 20)
+#define ADM8211_SYNRF_CAL_EN	(1 << 19)
+#define ADM8211_SYNRF_PHYRST	(1 << 18)
+
+#define ADM8211_SYNRF_IF_SELECT_0 	(1 << 31)
+#define ADM8211_SYNRF_IF_SELECT_1 	((1 << 31) | (1 << 28))
+#define ADM8211_SYNRF_WRITE_SYNDATA_0	(1 << 31)
+#define ADM8211_SYNRF_WRITE_SYNDATA_1	((1 << 31) | (1 << 26))
+#define ADM8211_SYNRF_WRITE_CLOCK_0	(1 << 31)
+#define ADM8211_SYNRF_WRITE_CLOCK_1	((1 << 31) | (1 << 27))
+
+/* CSR44 - WEPCTL (WEP Control) */
+#define ADM8211_WEPCTL_WEPENABLE   (1 << 31)
+#define ADM8211_WEPCTL_WPAENABLE   (1 << 30)
+#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29)
+#define ADM8211_WEPCTL_TABLE_WR	(1 << 28)
+#define ADM8211_WEPCTL_TABLE_RD	(1 << 27)
+#define ADM8211_WEPCTL_WEPRXBYP	(1 << 25)
+#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23)
+#define ADM8211_WEPCTL_ADDR	(0x000001ff)
+
+/* CSR45 - WESK (Data Entry for Share/Individual Key) */
+#define ADM8211_WESK_DATA	(0x0000ffff)
+
+/* FER (Function Event Register) */
+#define ADM8211_FER_INTR_EV_ENT	(1 << 15)
+
+
+/* Si4126 RF Synthesizer - Control Registers */
+#define SI4126_MAIN_CONF	0
+#define SI4126_PHASE_DET_GAIN	1
+#define SI4126_POWERDOWN	2
+#define SI4126_RF1_N_DIV	3 /* only Si4136 */
+#define SI4126_RF2_N_DIV	4
+#define SI4126_IF_N_DIV		5
+#define SI4126_RF1_R_DIV	6 /* only Si4136 */
+#define SI4126_RF2_R_DIV	7
+#define SI4126_IF_R_DIV		8
+
+/* Main Configuration */
+#define SI4126_MAIN_XINDIV2	(1 << 6)
+#define SI4126_MAIN_IFDIV	((1 << 11) | (1 << 10))
+/* Powerdown */
+#define SI4126_POWERDOWN_PDIB	(1 << 1)
+#define SI4126_POWERDOWN_PDRB	(1 << 0)
+
+
+/* RF3000 BBP - Control Port Registers */
+/* 0x00 - reserved */
+#define RF3000_MODEM_CTRL__RX_STATUS 0x01
+#define RF3000_CCA_CTRL 0x02
+#define RF3000_DIVERSITY__RSSI 0x03
+#define RF3000_RX_SIGNAL_FIELD 0x04
+#define RF3000_RX_LEN_MSB 0x05
+#define RF3000_RX_LEN_LSB 0x06
+#define RF3000_RX_SERVICE_FIELD 0x07
+#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11
+#define RF3000_TX_LEN_MSB 0x12
+#define RF3000_TX_LEN_LSB 0x13
+#define RF3000_LOW_GAIN_CALIB 0x14
+#define RF3000_HIGH_GAIN_CALIB 0x15
+
+/* ADM8211 revisions */
+#define ADM8211_REV_AB 0x11
+#define ADM8211_REV_AF 0x15
+#define ADM8211_REV_BA 0x20
+#define ADM8211_REV_CA 0x30
+
+struct adm8211_desc {
+	__le32 status;
+	__le32 length;
+	__le32 buffer1;
+	__le32 buffer2;
+};
+
+#define RDES0_STATUS_OWN	(1 << 31)
+#define RDES0_STATUS_ES		(1 << 30)
+#define RDES0_STATUS_SQL	(1 << 29)
+#define RDES0_STATUS_DE		(1 << 28)
+#define RDES0_STATUS_FS		(1 << 27)
+#define RDES0_STATUS_LS		(1 << 26)
+#define RDES0_STATUS_PCF	(1 << 25)
+#define RDES0_STATUS_SFDE	(1 << 24)
+#define RDES0_STATUS_SIGE	(1 << 23)
+#define RDES0_STATUS_CRC16E	(1 << 22)
+#define RDES0_STATUS_RXTOE	(1 << 21)
+#define RDES0_STATUS_CRC32E	(1 << 20)
+#define RDES0_STATUS_ICVE	(1 << 19)
+#define RDES0_STATUS_DA1	(1 << 17)
+#define RDES0_STATUS_DA0	(1 << 16)
+#define RDES0_STATUS_RXDR	((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12))
+#define RDES0_STATUS_FL		(0x00000fff)
+
+#define RDES1_CONTROL_RER	(1 << 25)
+#define RDES1_CONTROL_RCH	(1 << 24)
+#define RDES1_CONTROL_RBS2	(0x00fff000)
+#define RDES1_CONTROL_RBS1	(0x00000fff)
+
+#define RDES1_STATUS_RSSI	(0x0000007f)
+
+
+#define TDES0_CONTROL_OWN	(1 << 31)
+#define TDES0_CONTROL_DONE	(1 << 30)
+#define TDES0_CONTROL_TXDR	(0x0ff00000)
+
+#define TDES0_STATUS_OWN	(1 << 31)
+#define TDES0_STATUS_DONE	(1 << 30)
+#define TDES0_STATUS_ES		(1 << 29)
+#define TDES0_STATUS_TLT	(1 << 28)
+#define TDES0_STATUS_TRT	(1 << 27)
+#define TDES0_STATUS_TUF	(1 << 26)
+#define TDES0_STATUS_TRO	(1 << 25)
+#define TDES0_STATUS_SOFBR	(1 << 24)
+#define TDES0_STATUS_ACR	(0x00000fff)
+
+#define TDES1_CONTROL_IC	(1 << 31)
+#define TDES1_CONTROL_LS	(1 << 30)
+#define TDES1_CONTROL_FS	(1 << 29)
+#define TDES1_CONTROL_TER	(1 << 25)
+#define TDES1_CONTROL_TCH	(1 << 24)
+#define TDES1_CONTROL_RBS2	(0x00fff000)
+#define TDES1_CONTROL_RBS1	(0x00000fff)
+
+/* SRAM offsets */
+#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \
+        ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x)
+
+#define ADM8211_SRAM_INDIV_KEY   0x0000
+#define ADM8211_SRAM_A_SHARE_KEY 0x0160
+#define ADM8211_SRAM_B_SHARE_KEY 0x00c0
+
+#define ADM8211_SRAM_A_SSID      0x0180
+#define ADM8211_SRAM_B_SSID      0x00d4
+#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID)
+
+#define ADM8211_SRAM_A_SUPP_RATE 0x0191
+#define ADM8211_SRAM_B_SUPP_RATE 0x00dd
+#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE)
+
+#define ADM8211_SRAM_A_SIZE      0x0200
+#define ADM8211_SRAM_B_SIZE      0x01c0
+#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
+
+struct adm8211_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	struct ieee80211_tx_status tx_status;
+	int unicast;
+};
+
+struct adm8211_eeprom {
+	__le16	signature;		/* 0x00 */
+	u8	major_version;		/* 0x02 */
+	u8	minor_version;		/* 0x03 */
+	u8	reserved_1[4];		/* 0x04 */
+	u8	hwaddr[6];		/* 0x08 */
+	u8	reserved_2[8];		/* 0x1E */
+	__le16	cr49;			/* 0x16 */
+	u8	cr03;			/* 0x18 */
+	u8	cr28;			/* 0x19 */
+	u8	cr29;			/* 0x1A */
+	u8	country_code;		/* 0x1B */
+
+/* specific bbp types */
+#define ADM8211_BBP_RFMD3000	0x00
+#define ADM8211_BBP_RFMD3002	0x01
+#define ADM8211_BBP_ADM8011	0x04
+	u8	specific_bbptype;	/* 0x1C */
+	u8	specific_rftype;	/* 0x1D */
+	u8	reserved_3[2];		/* 0x1E */
+	__le16	device_id;		/* 0x20 */
+	__le16	vendor_id;		/* 0x22 */
+	__le16	subsystem_id;		/* 0x24 */
+	__le16	subsystem_vendor_id;	/* 0x26 */
+	u8	maxlat;			/* 0x28 */
+	u8	mingnt;			/* 0x29 */
+	__le16	cis_pointer_low;	/* 0x2A */
+	__le16	cis_pointer_high;	/* 0x2C */
+	__le16	csr18;			/* 0x2E */
+	u8	reserved_4[16];		/* 0x30 */
+	u8	d1_pwrdara;		/* 0x40 */
+	u8	d0_pwrdara;		/* 0x41 */
+	u8	d3_pwrdara;		/* 0x42 */
+	u8	d2_pwrdara;		/* 0x43 */
+	u8	antenna_power[14];	/* 0x44 */
+	__le16	cis_wordcnt;		/* 0x52 */
+	u8	tx_power[14];		/* 0x54 */
+	u8	lpf_cutoff[14];		/* 0x62 */
+	u8	lnags_threshold[14];	/* 0x70 */
+	__le16	checksum;		/* 0x7E */
+	u8	cis_data[0];		/* 0x80, 384 bytes */
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate adm8211_rates[] = {
+	{ .rate = 10,
+	  .val = 10,
+	  .val2 = -10,
+	  .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK },
+	{ .rate = 20,
+	  .val = 20,
+	  .val2 = -20,
+	  .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 },
+	{ .rate = 55,
+	  .val = 55,
+	  .val2 = -55,
+	  .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 },
+	{ .rate = 110,
+	  .val = 110,
+	  .val2 = -110,
+	  .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 }
+};
+
+struct ieee80211_chan_range {
+	u8 min;
+	u8 max;
+};
+
+struct adm8211_priv {
+	struct pci_dev *pdev;
+	spinlock_t lock;
+	struct adm8211_csr __iomem *map;
+	struct adm8211_desc *rx_ring;
+	struct adm8211_desc *tx_ring;
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	struct adm8211_ring_info *rx_buffers;
+	struct adm8211_ring_info *tx_buffers;
+	unsigned rx_ring_size, tx_ring_size;
+	unsigned cur_tx, dirty_tx, cur_rx;
+
+	struct ieee80211_hw hw;
+	struct ieee80211_low_level_stats stats;
+	struct ieee80211_hw_modes modes[1];
+	struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+	int mode;
+
+	int channel;
+	u8 bssid[ETH_ALEN];
+	u8 ssid[32];
+	size_t ssid_len;
+
+	u32 msg_enable;
+
+	int (*eth_header_parse)(struct sk_buff *skb, unsigned char *haddr);
+
+	u8 soft_rx_crc;
+	u8 retry_limit;
+
+	u8 ant_power;
+	u8 tx_power;
+	u8 lpf_cutoff;
+	u8 lnags_threshold;
+	struct adm8211_eeprom *eeprom;
+	size_t eeprom_len;
+
+	u8 revid;
+
+	u32 nar;
+
+#define ADM8211_TYPE_INTERSIL	0x00
+#define ADM8211_TYPE_RFMD	0x01
+#define ADM8211_TYPE_MARVEL	0x02
+#define ADM8211_TYPE_AIROHA	0x03
+#define ADM8211_TYPE_ADMTEK     0x05
+	unsigned int rf_type:3;
+	unsigned int bbp_type:3;
+
+	u8 specific_bbptype;
+	enum {
+		ADM8211_RFMD2948 = 0x0,
+		ADM8211_RFMD2958 = 0x1,
+		ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2,
+		ADM8211_MAX2820 = 0x8,
+		ADM8211_AL2210L = 0xC,	/* Airoha */
+	} transceiver_type;
+};
+
+static const struct ieee80211_chan_range cranges[] = {
+	{1,  11},	/* FCC */
+	{1,  11},	/* IC */
+	{1,  13},	/* ETSI */
+	{10, 11},	/* SPAIN */
+	{10, 13},	/* FRANCE */
+	{14, 14},	/* MMK */
+	{1,  14},	/* MMK2 */
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+	{ .chan = 1,
+	  .freq = 2412,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 2,
+	  .freq = 2417,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 3,
+	  .freq = 2422,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 4,
+	  .freq = 2427,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 5,
+	  .freq = 2432,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 6,
+	  .freq = 2437,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 7,
+	  .freq = 2442,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 8,
+	  .freq = 2447,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 9,
+	  .freq = 2452,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 10,
+	  .freq = 2457,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 11,
+	  .freq = 2462,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 12,
+	  .freq = 2467,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 13,
+	  .freq = 2472,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS},
+	{ .chan = 14,
+	  .freq = 2484,
+	  .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | 
IEEE80211_CHAN_W_IBSS}
+};
+
+#endif /* ADM8211_H */

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related

* Re: updated [Patch 1/1] AF_UNIX Datagram getpeersec
From: Catherine Zhang @ 2006-06-18  4:46 UTC (permalink / raw)
  To: James Morris
  Cc: Stephen Hemminger, Catherine Zhang, netdev, davem, jmorris,
	chrisw, herbert, sds, tjaeger, akpm, latten, sergeh, gcwilson
In-Reply-To: <Pine.LNX.4.64.0606171151320.16944@d.namei>

On 6/17/06, James Morris <jmorris@namei.org> wrote:
> On Fri, 16 Jun 2006, Stephen Hemminger wrote:
>
> > This is so short, it would make sense to put it in scm.h
> > and why not have it return the value instead of call by reference?
> > Same goes for selinux_get_inode_sid
>
> Actually, all of the SELinux API functions are like this, and I'm not sure
> why for void return methods (it's a good idea when they return errnos).
>

Yes, the reason I used void return method is consistency with the
remaining SELinux API functions.

> Once this area has settled down (post 2.6.18), I'm planning to do some
> cleanups for this API anyway, and can fix these all at the same time.
>

OK.

Thanks,
Catherine

^ permalink raw reply

* Re: tg3 timeouts with 2.6.17-rc6
From: David Miller @ 2006-06-18  4:08 UTC (permalink / raw)
  To: mchan; +Cc: jk, linux-kernel, netdev
In-Reply-To: <1150568608.26368.49.camel@rh4>

From: "Michael Chan" <mchan@broadcom.com>
Date: Sat, 17 Jun 2006 11:23:28 -0700

> David, Here's the patch if you haven't already made one:
> 
> [TG3]: Disable TSO by default on 5780 class chips.

Sorry, I didn't get a chance to push this into 2.6.17
in time.  I will push it into the first 2.6.17.x -stable
release.

^ permalink raw reply

* Re: Network performance degradation from 2.6.11.12 to 2.6.16.20
From: Stephen Hemminger @ 2006-06-18  3:16 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Harry Edmon, linux-kernel, netdev
In-Reply-To: <20060617165611.2c478723.akpm@osdl.org>

Andrew Morton wrote:
> On Sat, 17 Jun 2006 16:23:34 -0700
> Harry Edmon <harry@atmos.washington.edu> wrote:
>
>   
>> Andrew Morton wrote:
>>     
>>> On Fri, 16 Jun 2006 09:01:23 -0700
>>> Harry Edmon <harry@atmos.washington.edu> wrote:
>>>
>>>       
>>>> I have a system with a strange network performance degradation from 
>>>> 2.6.11.12 to most recent kernels including 2.6.16.20 and 2.6.17-rc6.   
>>>> The system is has Dual single core Xeons with hyperthreading on.   The 
>>>> application is the LDM system from UCAR/Unidata 
>>>> (http://www.unidata.ucar.edu/software/ldm).   This system requests 
>>>> weather data from a variety of systems using RPC calls over a reserved 
>>>> TCP port (388), puts them into a memory mapped queue file, and then 
>>>> sends the data out to a variety of downstream requesting systems, again 
>>>> using RPC calls.  When the load is heavy, the 2.6.16.20 kernel falls way 
>>>> behind with the data ingestion.  The 2.6.11.12 kernel does not.   I have 
>>>> tried an experiment with a 2.6.17-rc6 system where it just does the 
>>>> ingestion, and not the downstream distribution, and it is able to keep 
>>>> up.   I would really appreciate any pointers as to where the problem may 
>>>> be and how to diagnose it.  I have attached the config files from both 
>>>> kernels and the sysctl.conf file I am using.   I have also included the 
>>>> output from "netstat -s" on the 2.6.16.20 system during a time when it 
>>>> was having problems.
>>>>
>>>>         
>>> (added netdev)
>>>
>>> A quick grep indicates that it isn't using TCP_NODELAY - we've had problems
>>> with that in the past.
>>>
>>> Perhaps a tcpdump of the net traffic will help to determine what's going on.
>>>       
>
> [ edit, edit - please don't top-post ]
>
>   
>> I assume you are talking about using TCP_NODELAY as a socket option within the 
>> LDM software.  I could give that a try.
>>     
>
> The use of TCP_NODELAY caused problems with the JVM debugger.  I'm not
> suggesting that enabling it will fix anything here.
>
>   
>> There is a lot of traffic on this node, on the order of 2000 packets in and out 
>> per second, so the tcpdump output will grow pretty fast.  How long a tcpdump 
>> would be useful, and what options would you suggest?
>>     
>
> I don't know, frankly - first one needs to develop some sort of theory,
> then use the diagnostic tools to prove or disprove that theory.  And I
> don't have a theory.
>
> I guess a simple one-second bare `tcpdump -i eth0' would be a starting
> point.  Perhaps compare the output of that with the output from a
> correctly-operating kernel, see if anything suggests itself.  That might
> also give us something which the networking developers can use.
>
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>   
Does this fix it?
    # sysctl -w net.ipv4.tcp_abc=0


^ permalink raw reply

* Re: [PATCH] bcm43xx: enable shared key authentication
From: Dan Williams @ 2006-06-18  3:01 UTC (permalink / raw)
  To: Daniel Drake; +Cc: linville, netdev, mb
In-Reply-To: <20060616195022.E73CD8A3591@zog.reactivated.net>

On Fri, 2006-06-16 at 20:50 +0100, Daniel Drake wrote:
> I recently patched softmac to enable shared key authentication. This small patch
> will enable crazy or unfortunate bcm43xx users to use this new capability.

Meaning that _until now_, softmac couldn't do Shared Key auth???  That
might explain a few NM bugs I think I've seen floating around.

Dan

> Signed-off-by: Daniel Drake <dsd@gentoo.org>
> 
> Index: linux/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> ===================================================================
> --- linux.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> +++ linux/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> @@ -3599,6 +3599,10 @@ static void bcm43xx_ieee80211_set_securi
>  		secinfo->encrypt = sec->encrypt;
>  		dprintk(KERN_INFO PFX "   .encrypt = %d\n", sec->encrypt);
>  	}
> +	if (sec->flags & SEC_AUTH_MODE) {
> +		secinfo->auth_mode = sec->auth_mode;
> +		dprintk(KERN_INFO PFX "   .auth_mode = %d\n", sec->auth_mode);
> +	}
>  	if (bcm->initialized && !bcm->ieee->host_encrypt) {
>  		if (secinfo->enabled) {
>  			/* upload WEP keys to hardware */
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply

* Re: Network performance degradation from 2.6.11.12 to 2.6.16.20
From: Andrew Morton @ 2006-06-17 23:56 UTC (permalink / raw)
  To: Harry Edmon; +Cc: linux-kernel, netdev
In-Reply-To: <44948EF6.1060201@atmos.washington.edu>

On Sat, 17 Jun 2006 16:23:34 -0700
Harry Edmon <harry@atmos.washington.edu> wrote:

> Andrew Morton wrote:
> > On Fri, 16 Jun 2006 09:01:23 -0700
> > Harry Edmon <harry@atmos.washington.edu> wrote:
> > 
> >> I have a system with a strange network performance degradation from 
> >> 2.6.11.12 to most recent kernels including 2.6.16.20 and 2.6.17-rc6.   
> >> The system is has Dual single core Xeons with hyperthreading on.   The 
> >> application is the LDM system from UCAR/Unidata 
> >> (http://www.unidata.ucar.edu/software/ldm).   This system requests 
> >> weather data from a variety of systems using RPC calls over a reserved 
> >> TCP port (388), puts them into a memory mapped queue file, and then 
> >> sends the data out to a variety of downstream requesting systems, again 
> >> using RPC calls.  When the load is heavy, the 2.6.16.20 kernel falls way 
> >> behind with the data ingestion.  The 2.6.11.12 kernel does not.   I have 
> >> tried an experiment with a 2.6.17-rc6 system where it just does the 
> >> ingestion, and not the downstream distribution, and it is able to keep 
> >> up.   I would really appreciate any pointers as to where the problem may 
> >> be and how to diagnose it.  I have attached the config files from both 
> >> kernels and the sysctl.conf file I am using.   I have also included the 
> >> output from "netstat -s" on the 2.6.16.20 system during a time when it 
> >> was having problems.
> >>
> > 
> > (added netdev)
> > 
> > A quick grep indicates that it isn't using TCP_NODELAY - we've had problems
> > with that in the past.
> > 
> > Perhaps a tcpdump of the net traffic will help to determine what's going on.
> 

[ edit, edit - please don't top-post ]

> I assume you are talking about using TCP_NODELAY as a socket option within the 
> LDM software.  I could give that a try.

The use of TCP_NODELAY caused problems with the JVM debugger.  I'm not
suggesting that enabling it will fix anything here.

> 
> There is a lot of traffic on this node, on the order of 2000 packets in and out 
> per second, so the tcpdump output will grow pretty fast.  How long a tcpdump 
> would be useful, and what options would you suggest?

I don't know, frankly - first one needs to develop some sort of theory,
then use the diagnostic tools to prove or disprove that theory.  And I
don't have a theory.

I guess a simple one-second bare `tcpdump -i eth0' would be a starting
point.  Perhaps compare the output of that with the output from a
correctly-operating kernel, see if anything suggests itself.  That might
also give us something which the networking developers can use.


^ permalink raw reply

* Re: Network performance degradation from 2.6.11.12 to 2.6.16.20
From: Harry Edmon @ 2006-06-17 23:23 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, netdev
In-Reply-To: <20060617153511.53a129a3.akpm@osdl.org>

I assume you are talking about using TCP_NODELAY as a socket option within the 
LDM software.  I could give that a try.

There is a lot of traffic on this node, on the order of 2000 packets in and out 
per second, so the tcpdump output will grow pretty fast.  How long a tcpdump 
would be useful, and what options would you suggest?

I should also note that my network interfaces are Intel, using the latest e1000 
driver.


Andrew Morton wrote:
> On Fri, 16 Jun 2006 09:01:23 -0700
> Harry Edmon <harry@atmos.washington.edu> wrote:
> 
>> I have a system with a strange network performance degradation from 
>> 2.6.11.12 to most recent kernels including 2.6.16.20 and 2.6.17-rc6.   
>> The system is has Dual single core Xeons with hyperthreading on.   The 
>> application is the LDM system from UCAR/Unidata 
>> (http://www.unidata.ucar.edu/software/ldm).   This system requests 
>> weather data from a variety of systems using RPC calls over a reserved 
>> TCP port (388), puts them into a memory mapped queue file, and then 
>> sends the data out to a variety of downstream requesting systems, again 
>> using RPC calls.  When the load is heavy, the 2.6.16.20 kernel falls way 
>> behind with the data ingestion.  The 2.6.11.12 kernel does not.   I have 
>> tried an experiment with a 2.6.17-rc6 system where it just does the 
>> ingestion, and not the downstream distribution, and it is able to keep 
>> up.   I would really appreciate any pointers as to where the problem may 
>> be and how to diagnose it.  I have attached the config files from both 
>> kernels and the sysctl.conf file I am using.   I have also included the 
>> output from "netstat -s" on the 2.6.16.20 system during a time when it 
>> was having problems.
>>
> 
> (added netdev)
> 
> A quick grep indicates that it isn't using TCP_NODELAY - we've had problems
> with that in the past.
> 
> Perhaps a tcpdump of the net traffic will help to determine what's going on.


-- 
  Dr. Harry Edmon			E-MAIL: harry@atmos.washington.edu
  206-543-0547				harry@u.washington.edu
  Dept of Atmospheric Sciences		FAX:	206-543-0308
  University of Washington, Box 351640, Seattle, WA 98195-1640

^ permalink raw reply

* [PATCH] driver for PPTP, second edition
From: xeb @ 2006-06-17 22:56 UTC (permalink / raw)
  To: netdev

Hello.
I have developed the driver for Point-to-Point Tunneling Protocol (PPTP).
This driver works in pair with plugin for pppd.
It is enough to use pppd's plugin for start of the client.
Also there is a server (based on pptpd) which uses this driver.
By results of my testing the speed of transfer has increased on >50% and cpu usage has decreased on >50% in comparison with original pptpd and pptpclient.
I have published the project on http://accel-pptp.sourceforge.net/


diff -uprN linux-2.6.16.orig/drivers/net/Kconfig linux-2.6.16.pptp/drivers/net/Kconfig
--- linux-2.6.16.orig/drivers/net/Kconfig	2006-06-18 00:51:35.000000000 +0400
+++ linux-2.6.16.pptp/drivers/net/Kconfig	2006-06-18 01:10:19.000000000 +0400
@@ -2603,6 +2603,15 @@ config PPPOE
 	  which contains instruction on how to use this driver (under 
 	  the heading "Kernel mode PPPoE").
 
+config PPTP
+	tristate "PPTP (Point-to-Point Tunneling Protocol) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PPP
+	help
+	  Support for Microsoft Point-to-Point Tunneling Protocol.
+
+	  See http://accel-pptp.sourceforge.net/ for information on 
+	  configuring PPTP clients and servers to utilize this driver.
+
 config PPPOATM
 	tristate "PPP over ATM"
 	depends on ATM && PPP
diff -uprN linux-2.6.16.orig/drivers/net/Makefile linux-2.6.16.pptp/drivers/net/Makefile
--- linux-2.6.16.orig/drivers/net/Makefile	2006-06-18 00:51:34.000000000 +0400
+++ linux-2.6.16.pptp/drivers/net/Makefile	2006-06-18 00:57:02.000000000 +0400
@@ -118,6 +118,7 @@ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate
 obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+obj-$(CONFIG_PPTP) += pppox.o pptp.o
 
 obj-$(CONFIG_SLIP) += slip.o
 ifeq ($(CONFIG_SLIP_COMPRESSED),y)
diff -uprN linux-2.6.16.orig/drivers/net/pptp.c linux-2.6.16.pptp/drivers/net/pptp.c
--- linux-2.6.16.orig/drivers/net/pptp.c	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.16.pptp/drivers/net/pptp.c	2006-06-18 01:30:40.000000000 +0400
@@ -0,0 +1,928 @@
+/*
+ *  Point-to-Point Tunneling Protocol for Linux
+ *
+ *	Authors: Kozlov D. (xeb@mail.ru)
+ *
+ *	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.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppox.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
+
+#include <net/sock.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+
+#include <asm/uaccess.h>
+
+#define PPTP_DRIVER_VERSION "0.7"
+
+MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol for Linux");
+MODULE_AUTHOR("Kozlov D. (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+
+static int log_level=0;
+static int min_window=5;
+static int max_window=100;
+module_param(min_window,int,5);
+MODULE_PARM_DESC(min_window,"Minimum sliding window size (default=3)");
+module_param(max_window,int,100);
+MODULE_PARM_DESC(max_window,"Maximum sliding window size (default=100)");
+module_param(log_level,int,0);
+
+static struct proc_dir_entry* proc_dir;
+
+#define HASH_SIZE  16
+#define HASH(addr) ((addr^(addr>>4))&0xF)
+static DEFINE_RWLOCK(chan_lock);
+static struct pppox_sock *chans[HASH_SIZE];
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+static int read_proc(char *page, char **start, off_t off,int count,
+                     int *eof, void *data);
+static int __pptp_rcv(struct pppox_sock *po,struct sk_buff *skb,int new);
+
+static struct ppp_channel_ops pptp_chan_ops= {
+	.start_xmit = pptp_xmit,
+};
+
+/* gre header structure: -------------------------------------------- */
+
+#define PPTP_GRE_PROTO  0x880B
+#define PPTP_GRE_VER    0x1
+
+#define PPTP_GRE_FLAG_C	0x80
+#define PPTP_GRE_FLAG_R	0x40
+#define PPTP_GRE_FLAG_K	0x20
+#define PPTP_GRE_FLAG_S	0x10
+#define PPTP_GRE_FLAG_A	0x80
+
+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
+
+struct pptp_gre_header {
+  u_int8_t flags;		/* bitfield */
+  u_int8_t ver;			/* should be PPTP_GRE_VER (enhanced GRE) */
+  u_int16_t protocol;		/* should be PPTP_GRE_PROTO (ppp-encaps) */
+  u_int16_t payload_len;	/* size of ppp payload, not inc. gre header */
+  u_int16_t call_id;		/* peer's call_id for this session */
+  u_int32_t seq;		/* sequence number.  Present if S==1 */
+  u_int32_t ack;		/* seq number of highest packet recieved by */
+  				/*  sender in this session */
+};
+
+struct gre_statistics {
+  /* statistics for GRE receive */
+  unsigned int rx_accepted;  // data packet accepted
+  unsigned int rx_lost;      // data packet did not arrive before timeout
+  unsigned int rx_underwin;  // data packet was under window (arrived too late
+                             // or duplicate packet)
+  unsigned int rx_buffered;  // data packet arrived earlier than expected,
+                             // packet(s) before it were lost or reordered
+  unsigned int rx_errors;    // OS error on receive
+  unsigned int rx_truncated; // truncated packet
+  unsigned int rx_invalid;   // wrong protocol or invalid flags
+  unsigned int rx_acks;      // acknowledgement only
+
+  /* statistics for GRE transmit */
+  unsigned int tx_sent;      // data packet sent
+  unsigned int tx_failed;    //
+  unsigned int tx_acks;      // sent packet with just ACK
+
+  __u32 pt_seq;
+  struct timeval pt_time;
+  unsigned int rtt;
+};
+
+static struct pppox_sock * lookup_chan(__u16 call_id)
+{
+	struct pppox_sock *po;
+	read_lock_bh(&chan_lock);
+	for(po=chans[HASH(call_id)]; po; po=po->next)
+		if (po->proto.pptp.src_addr.call_id==call_id)
+			break;
+	read_unlock_bh(&chan_lock);
+	return po;
+}
+
+static void add_chan(struct pppox_sock *po)
+{
+	write_lock_bh(&chan_lock);
+	po->next=chans[HASH(po->proto.pptp.src_addr.call_id)];
+	chans[HASH(po->proto.pptp.src_addr.call_id)]=po;
+	write_unlock_bh(&chan_lock);
+}
+
+static void add_free_chan(struct pppox_sock *po)
+{
+	__u16 call_id=1;
+	struct pppox_sock *p;
+
+	write_lock_bh(&chan_lock);
+	for(call_id=1; call_id<65535; call_id++) {
+		for(p=chans[HASH(call_id)]; p; p=p->next)
+			if (p->proto.pptp.src_addr.call_id==call_id)
+				break;
+		if (!p){
+			po->proto.pptp.src_addr.call_id=call_id;
+			po->next=chans[HASH(call_id)];
+			chans[HASH(call_id)]=po;
+			break;
+		}
+	}
+	write_unlock_bh(&chan_lock);
+}
+
+static void del_chan(struct pppox_sock *po)
+{
+	struct pppox_sock *p1,*p2;
+	write_lock_bh(&chan_lock);
+	for(p2=NULL,p1=chans[HASH(po->proto.pptp.src_addr.call_id)]; p1 && p1!=po;
+				p2=p1,p1=p1->next);
+	if (p2) p2->next=p1->next;
+	else chans[HASH(po->proto.pptp.src_addr.call_id)]=p1->next;
+	write_unlock_bh(&chan_lock);
+}
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt=&po->proto.pptp;
+	struct pptp_gre_header *hdr;
+	unsigned int header_len=sizeof(*hdr);
+	int len=skb?skb->len:0;
+	int err=0;
+
+	struct rtable *rt;     			/* Route to the other host */
+	struct net_device *tdev;			/* Device to other host */
+	struct iphdr  *iph;			/* Our new IP header */
+	int    max_headroom;			/* The extra header space needed */
+
+
+	if (skb && opt->seq_sent-opt->ack_recv>opt->window){
+		opt->pause=1;
+		return 0;
+	}
+
+	{
+		struct flowi fl = { .oif = 0,
+				    .nl_u = { .ip4_u =
+					      { .daddr = opt->dst_addr.sin_addr.s_addr,
+						.saddr = opt->src_addr.sin_addr.s_addr,
+						.tos = RT_TOS(0) } },
+				    .proto = IPPROTO_GRE };
+		if ((err=ip_route_output_key(&rt, &fl))) {
+			goto tx_error;
+		}
+	}
+	tdev = rt->u.dst.dev;
+
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph)+sizeof(*hdr)+2;
+
+	if (!skb){
+		skb=dev_alloc_skb(max_headroom);
+		skb_reserve(skb,max_headroom-skb_headroom(skb));
+	}else if (skb_headroom(skb) < max_headroom ||
+						skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+		if (skb->sk)
+			skb_set_owner_w(new_skb, skb->sk);
+		dev_kfree_skb(skb);
+		skb = new_skb;
+	}
+
+	if (skb->len){
+		int islcp;
+		unsigned char *data=skb->data;
+		islcp=((data[0] << 8) + data[1])== PPP_LCP && 1 <= data[2] && data[2] <= 7;
+		if (islcp) {
+			data=skb_push(skb,2);
+			data[0]=0xff;
+			data[1]=0x03;
+		}
+	}
+	len=skb->len;
+
+	if (len==0) header_len-=sizeof(hdr->seq);
+	if (opt->ack_sent == opt->seq_recv) header_len-=sizeof(hdr->ack);
+
+	skb->nh.raw = skb_push(skb, sizeof(*iph)+header_len);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+			      IPSKB_REROUTED);
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/*
+	 *	Push down and install the IP header.
+	 */
+
+	iph 			=	skb->nh.iph;
+	iph->version		=	4;
+	iph->ihl		=	sizeof(struct iphdr) >> 2;
+	iph->frag_off		=	0;//df;
+	iph->protocol		=	IPPROTO_GRE;
+	iph->tos		=	0;
+	iph->daddr		=	rt->rt_dst;
+	iph->saddr		=	rt->rt_src;
+	iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
+
+	hdr=(struct pptp_gre_header *)(iph+1);
+	skb->h.raw = (char*)hdr;
+
+	hdr->flags       = PPTP_GRE_FLAG_K;
+	hdr->ver         = PPTP_GRE_VER;
+	hdr->protocol    = htons(PPTP_GRE_PROTO);
+	hdr->call_id     = htons(opt->dst_addr.call_id);
+
+	if (!len){
+		hdr->payload_len = 0;
+		hdr->ver |= PPTP_GRE_FLAG_A;
+		/* ack is in odd place because S == 0 */
+		hdr->seq = htonl(opt->seq_recv);
+		opt->ack_sent = opt->seq_recv;
+		opt->stat->tx_acks++;
+	}else {
+		if (!opt->seq_sent){
+			char unit[10];
+			sprintf(unit,"ppp%i",ppp_unit_number(&po->chan));
+			create_proc_read_entry(unit,0,proc_dir,read_proc,po);
+		}
+
+		hdr->flags |= PPTP_GRE_FLAG_S;
+		hdr->seq    = htonl(opt->seq_sent++);
+		if (log_level>=2)
+			printk("PPTP: send packet: seq=%i",opt->seq_sent);
+		if (opt->ack_sent != opt->seq_recv)	{
+		/* send ack with this message */
+			hdr->ver |= PPTP_GRE_FLAG_A;
+			hdr->ack  = htonl(opt->seq_recv);
+			opt->ack_sent = opt->seq_recv;
+			if (log_level>=2)
+				printk(" ack=%i",opt->seq_recv);
+		}
+		hdr->payload_len = htons(len);
+		if (log_level>=2)
+			printk("\n");
+	}
+
+	nf_reset(skb);
+
+	skb->ip_summed = CHECKSUM_NONE;
+	iph->tot_len = htons(skb->len);
+	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_send_check(iph);
+
+	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);
+	if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
+		opt->stat->tx_sent++;
+		if (!opt->stat->pt_seq){
+			opt->stat->pt_seq  = opt->seq_sent;
+			do_gettimeofday(&opt->stat->pt_time);
+		}
+	}else goto tx_error;
+
+	return 1;
+
+tx_error:
+	opt->stat->tx_failed++;
+	if (!len) dev_kfree_skb(skb);
+	return 1;
+}
+
+static void ack_work(struct pppox_sock *po)
+{
+	struct pptp_opt *opt=&po->proto.pptp;
+	if (opt->ack_sent != opt->seq_recv)
+		pptp_xmit(&po->chan,0);
+}
+
+static int get_seq(struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	u8 *payload;
+	struct pptp_gre_header *header;
+
+	iph = (struct iphdr*)skb->data;
+	payload = skb->data + (iph->ihl << 2);
+	header = (struct pptp_gre_header *)(payload);
+
+	return ntohl(header->seq);
+}
+static void buf_work(struct pppox_sock *po)
+{
+	struct timeval tv1,tv2;
+	struct sk_buff *skb;
+	struct pptp_opt *opt=&po->proto.pptp;
+	unsigned int t;
+
+	do_gettimeofday(&tv1);
+	spin_lock_bh(&opt->skb_buf_lock);
+	while((skb=skb_dequeue(&opt->skb_buf))){
+		if (!__pptp_rcv(po,skb,0)){
+			skb_get_timestamp(skb,&tv2);
+			t=(tv1.tv_sec-tv2.tv_sec)*1000000+(tv1.tv_usec-tv2.tv_usec);
+			if (t<opt->stat->rtt){
+				skb_queue_head(&opt->skb_buf,skb);
+				schedule_delayed_work(&opt->buf_work,t/100*HZ/10000);
+				goto exit;
+			}
+			t=get_seq(skb)-1;
+			opt->stat->rx_lost+=t-opt->seq_recv;
+			opt->seq_recv=t;
+			__pptp_rcv(po,skb,0);
+		}
+	}
+exit:
+	spin_unlock_bh(&opt->skb_buf_lock);
+}
+
+
+#define MISSING_WINDOW 20
+#define WRAPPED( curseq, lastseq) \
+    ((((curseq) & 0xffffff00) == 0) && \
+     (((lastseq) & 0xffffff00 ) == 0xffffff00))
+static int __pptp_rcv(struct pppox_sock *po,struct sk_buff *skb,int new)
+{
+	struct pptp_opt *opt=&po->proto.pptp;
+	int headersize,payload_len,seq;
+	__u8 *payload;
+	struct pptp_gre_header *header;
+
+	header = (struct pptp_gre_header *)(skb->data);
+
+	if (new){
+		/* test if acknowledgement present */
+		if (PPTP_GRE_IS_A(header->ver)){
+				__u32 ack = (PPTP_GRE_IS_S(header->flags))?
+						header->ack:header->seq; /* ack in different place if S = 0 */
+				ack = ntohl( ack);
+				if (ack > opt->ack_recv) opt->ack_recv = ack;
+				/* also handle sequence number wrap-around  */
+				if (WRAPPED(ack,opt->ack_recv)) opt->ack_recv = ack;
+				if (opt->stat->pt_seq && opt->ack_recv > opt->stat->pt_seq){
+					struct timeval tv;
+					unsigned int rtt;
+					do_gettimeofday(&tv);
+					rtt = (tv.tv_sec - opt->stat->pt_time.tv_sec)*1000000+
+						tv.tv_usec-opt->stat->pt_time.tv_usec;
+					opt->stat->rtt = (opt->stat->rtt + rtt) / 2;
+					if (opt->stat->rtt>opt->timeout) opt->stat->rtt=opt->timeout;
+					opt->stat->pt_seq=0;
+				}
+				if (opt->pause){
+					opt->pause=0;
+					ppp_output_wakeup(&po->chan);
+				}
+		}
+
+		/* test if payload present */
+		if (!PPTP_GRE_IS_S(header->flags)){
+			opt->stat->rx_acks++;
+			goto drop;
+		}
+	}
+
+	headersize  = sizeof(*header);
+	payload_len = ntohs(header->payload_len);
+	seq         = ntohl(header->seq);
+
+	/* no ack present? */
+	if (!PPTP_GRE_IS_A(header->ver)) headersize -= sizeof(header->ack);
+	/* check for incomplete packet (length smaller than expected) */
+	if (skb->len- headersize < payload_len){
+		if (log_level>=1)
+			printk("PPTP: discarding truncated packet (expected %d, got %d bytes)\n",
+						payload_len, skb->len- headersize);
+		opt->stat->rx_truncated++;
+		goto drop;
+	}
+
+	payload=skb->data+headersize;
+	/* check for expected sequence number */
+	if ((seq == opt->seq_recv + 1) || (!opt->timeout &&
+			(seq > opt->seq_recv + 1 || WRAPPED(seq, opt->seq_recv)))){
+		if ( log_level >= 2 )
+			printk("PPTP: accepting packet %d size=%i (%02x %02x %02x %02x %02x %02x)\n", seq,payload_len,
+				*(payload +0),
+				*(payload +1),
+				*(payload +2),
+				*(payload +3),
+				*(payload +4),
+				*(payload +5));
+		opt->stat->rx_accepted++;
+		opt->stat->rx_lost+=seq-(opt->seq_recv + 1);
+		opt->seq_recv = seq;
+		schedule_work(&opt->ack_work);
+
+		skb_pull(skb,headersize);
+
+		if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI){
+			/* chop off address/control */
+			if (skb->len < 3)
+				goto drop;
+			skb_pull(skb,2);
+		}
+
+		if ((*skb->data) & 1){
+			/* protocol is compressed */
+			skb_push(skb, 1)[0] = 0;
+		}
+
+		ppp_input(&po->chan,skb);
+
+		return 1;
+	/* out of order, check if the number is too low and discard the packet.
+	* (handle sequence number wrap-around, and try to do it right) */
+	}else if ( seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq) ){
+		if ( log_level >= 1)
+			printk("PPTP: discarding duplicate or old packet %d (expecting %d)\n",
+							seq, opt->seq_recv + 1);
+		opt->stat->rx_underwin++;
+	/* sequence number too high, is it reasonably close? */
+	}else if ( seq < opt->seq_recv + MISSING_WINDOW ||
+						 WRAPPED(seq, opt->seq_recv + MISSING_WINDOW) ){
+		opt->stat->rx_buffered++;
+		if ( log_level >= 1 && new )
+				printk("PPTP: buffering packet %d (expecting %d, lost or reordered)\n",
+						seq, opt->seq_recv+1);
+		return 0;
+	/* no, packet must be discarded */
+	}else{
+		if ( log_level >= 1 )
+			printk("PPTP: discarding bogus packet %d (expecting %d)\n",
+							seq, opt->seq_recv + 1);
+	}
+drop:
+	kfree_skb(skb);
+	return -1;
+}
+
+
+static int pptp_rcv(struct sk_buff *skb)
+{
+	struct pptp_gre_header *header;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop;
+
+	header = (struct pptp_gre_header *)skb->data;
+
+	if (    /* version should be 1 */
+					((header->ver & 0x7F) != PPTP_GRE_VER) ||
+					/* PPTP-GRE protocol for PPTP */
+					(ntohs(header->protocol) != PPTP_GRE_PROTO)||
+					/* flag C should be clear   */
+					PPTP_GRE_IS_C(header->flags) ||
+					/* flag R should be clear   */
+					PPTP_GRE_IS_R(header->flags) ||
+					/* flag K should be set     */
+					(!PPTP_GRE_IS_K(header->flags)) ||
+					/* routing and recursion ctrl = 0  */
+					((header->flags&0xF) != 0)){
+			/* if invalid, discard this packet */
+		if (log_level>=1)
+			printk("PPTP: Discarding GRE: %X %X %X %X %X %X\n",
+							header->ver&0x7F, ntohs(header->protocol),
+							PPTP_GRE_IS_C(header->flags),
+							PPTP_GRE_IS_R(header->flags),
+							PPTP_GRE_IS_K(header->flags),
+							header->flags & 0xF);
+		goto drop;
+	}
+
+	dst_release(skb->dst);
+	skb->dst = NULL;
+	nf_reset(skb);
+
+	if ((po=lookup_chan(htons(header->call_id)))) {
+		if (!(sk_pppox(po)->sk_state&PPPOX_BOUND))
+			goto drop;
+		if (__pptp_rcv(po,skb,1))
+			buf_work(po);
+		else{
+			struct timeval tv;
+			do_gettimeofday(&tv);
+			skb_set_timestamp(skb,&tv);
+			opt=&po->proto.pptp;
+			spin_lock(&opt->skb_buf_lock);
+			skb_queue_tail(&opt->skb_buf, skb);
+			spin_unlock(&opt->skb_buf_lock);
+			schedule_delayed_work(&opt->buf_work,opt->stat->rtt/100*HZ/10000);
+		}
+		goto out;
+	}else icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+
+drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+
+
+static int proc_output (struct pppox_sock *po,char *buf)
+{
+	struct gre_statistics *stat=po->proto.pptp.stat;
+	char *p=buf;
+	p+=sprintf(p,"rx accepted  = %d\n",stat->rx_accepted);
+	p+=sprintf(p,"rx lost      = %d\n",stat->rx_lost);
+	p+=sprintf(p,"rx under win = %d\n",stat->rx_underwin);
+	p+=sprintf(p,"rx buffered  = %d\n",stat->rx_buffered);
+	p+=sprintf(p,"rx invalid   = %d\n",stat->rx_invalid);
+	p+=sprintf(p,"rx acks      = %d\n",stat->rx_acks);
+	p+=sprintf(p,"tx sent      = %d\n",stat->tx_sent);
+	p+=sprintf(p,"tx failed    = %d\n",stat->tx_failed);
+	p+=sprintf(p,"tx acks      = %d\n",stat->tx_acks);
+
+	return p-buf;
+}
+static int read_proc(char *page, char **start, off_t off,int count, int *eof, void *data)
+{
+	struct pppox_sock *po = data;
+	int len = proc_output (po,page);
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+static int pptp_bind(struct socket *sock,struct sockaddr *uservaddr,int sockaddr_len)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt=&po->proto.pptp;
+	int error=0;
+
+	if (log_level>=1)
+		printk("PPTP: bind: addr=%X call_id=%i\n",sp->sa_addr.pptp.sin_addr.s_addr,
+						sp->sa_addr.pptp.call_id);
+	lock_sock(sk);
+
+	opt->src_addr=sp->sa_addr.pptp;
+	if (sp->sa_addr.pptp.call_id){
+		if (lookup_chan(sp->sa_addr.pptp.call_id)){
+			error=-EBUSY;
+			goto end;
+		}
+		add_chan(po);
+	}else{
+		add_free_chan(po);
+		if (!opt->src_addr.call_id)
+			error=-EBUSY;
+		if (log_level>=1)
+			printk("PPTP: using call_id %i\n",opt->src_addr.call_id);
+	}
+
+ end:
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+		  int sockaddr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt=&po->proto.pptp;
+	int error=0;
+
+	if (log_level>=1)
+		printk("PPTP: connect: addr=%X call_id=%i\n",
+						sp->sa_addr.pptp.sin_addr.s_addr,sp->sa_addr.pptp.call_id);
+
+	lock_sock(sk);
+
+	if (sp->sa_protocol != PX_PROTO_PPTP){
+		error = -EINVAL;
+		goto end;
+	}
+
+	/* Check for already bound sockets */
+	if (sk->sk_state & PPPOX_CONNECTED){
+		error = -EBUSY;
+		goto end;
+	}
+
+	/* Check for already disconnected sockets, on attempts to disconnect */
+	if (sk->sk_state & PPPOX_DEAD){
+		error = -EALREADY;
+		goto end;
+	}
+
+	if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr){
+		error = -EINVAL;
+		goto end;
+	}
+
+	po->chan.private=sk;
+	po->chan.ops=&pptp_chan_ops;
+	po->chan.mtu=PPP_MTU;
+	po->chan.hdrlen=2+sizeof(struct pptp_gre_header);
+	error = ppp_register_channel(&po->chan);
+	if (error){
+		printk(KERN_ERR "PPTP: failed to register PPP channel (%d)\n",error);
+		goto end;
+	}
+
+	opt->dst_addr=sp->sa_addr.pptp;
+	sk->sk_state = PPPOX_CONNECTED;
+
+ end:
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
+		  int *usockaddr_len, int peer)
+{
+	int len = sizeof(struct sockaddr_pppox);
+	struct sockaddr_pppox sp;
+
+	sp.sa_family	= AF_PPPOX;
+	sp.sa_protocol	= PX_PROTO_PPTP;
+	sp.sa_addr.pptp=pppox_sk(sock->sk)->proto.pptp.src_addr;
+
+	memcpy(uaddr, &sp, len);
+
+	*usockaddr_len = len;
+
+	return 0;
+}
+
+static int pptp_setsockopt(struct socket *sock, int level, int optname,
+	char* optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt=&po->proto.pptp;
+	int val;
+
+	if (optlen!=sizeof(int))
+		return -EINVAL;
+
+	if (get_user(val,(int __user*)optval))
+		return -EFAULT;
+
+	switch(optname) {
+		case PPTP_SO_TIMEOUT:
+			opt->timeout=val;
+			break;
+		case PPTP_SO_WINDOW:
+			opt->window=val;
+			break;
+		default:
+				return -ENOPROTOOPT;
+	}
+
+	return 0;
+}
+
+static int pptp_getsockopt(struct socket *sock, int level, int optname,
+	char* optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt=&po->proto.pptp;
+	int len,val;
+
+	if (get_user(len,(int __user*)optlen))
+		return -EFAULT;
+
+	if (len<sizeof(int))
+		return -EINVAL;
+
+	switch(optname) {
+		case PPTP_SO_TIMEOUT:
+			val=opt->timeout;
+			break;
+		case PPTP_SO_WINDOW:
+			val=opt->window;
+			break;
+		default:
+				return -ENOPROTOOPT;
+	}
+
+	if (put_user(sizeof(int),(int __user*)optlen))
+		return -EFAULT;
+
+	if (put_user(val,(int __user*)optval))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int pptp_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+	int error = 0;
+
+	if (!sk)
+		return 0;
+
+	if (sock_flag(sk, SOCK_DEAD))
+		return -EBADF;
+
+	po = pppox_sk(sk);
+	opt=&po->proto.pptp;
+	if (opt->src_addr.sin_addr.s_addr) {
+		cancel_delayed_work(&opt->buf_work);
+		flush_scheduled_work();
+		del_chan(po);
+		skb_queue_purge(&opt->skb_buf);
+
+		if (opt->seq_sent){
+			char unit[10];
+			sprintf(unit,"ppp%i",ppp_unit_number(&po->chan));
+			remove_proc_entry(unit,proc_dir);
+		}
+	}
+
+	pppox_unbind_sock(sk);
+
+	kfree(opt->stat);
+
+	/* Signal the death of the socket. */
+	sk->sk_state = PPPOX_DEAD;
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	skb_queue_purge(&sk->sk_receive_queue);
+	sock_put(sk);
+
+	return error;
+}
+
+
+static struct proto pptp_sk_proto = {
+	.name	  = "PPTP",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct pppox_sock),
+};
+
+static const struct proto_ops pptp_ops = {
+    .family		= AF_PPPOX,
+    .owner		= THIS_MODULE,
+    .release		= pptp_release,
+    .bind		=  pptp_bind,
+    .connect		= pptp_connect,
+    .socketpair		= sock_no_socketpair,
+    .accept		= sock_no_accept,
+    .getname		= pptp_getname,
+    .poll		= sock_no_poll,
+    .listen		= sock_no_listen,
+    .shutdown		= sock_no_shutdown,
+    .setsockopt		= pptp_setsockopt,
+    .getsockopt		= pptp_getsockopt,
+    .sendmsg		= sock_no_sendmsg,
+    .recvmsg		= sock_no_recvmsg,
+    .mmap		= sock_no_mmap,
+    .ioctl		= pppox_ioctl,
+};
+
+static int pptp_create(struct socket *sock)
+{
+	int error = -ENOMEM;
+	struct sock *sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+
+	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pptp_sk_proto, 1);
+	if (!sk)
+		goto out;
+
+	sock_init_data(sock, sk);
+
+	sock->state = SS_UNCONNECTED;
+	sock->ops   = &pptp_ops;
+
+	//sk->sk_backlog_rcv = pppoe_rcv_core;
+	sk->sk_state	   = PPPOX_NONE;
+	sk->sk_type	   = SOCK_STREAM;
+	sk->sk_family	   = PF_PPPOX;
+	sk->sk_protocol	   = PX_PROTO_PPTP;
+
+	po = pppox_sk(sk);
+	opt=&po->proto.pptp;
+
+	opt->window=min_window;
+	opt->timeout=0;
+	opt->seq_sent=0; opt->seq_recv=-1;
+	opt->ack_recv=0; opt->ack_sent=-1;
+	skb_queue_head_init(&opt->skb_buf);
+	opt->skb_buf_lock=SPIN_LOCK_UNLOCKED;
+	INIT_WORK(&opt->ack_work,(void(*)(void*))ack_work,sk);
+	INIT_WORK(&opt->buf_work,(void(*)(void*))buf_work,sk);
+	opt->stat=kzalloc(sizeof(*opt->stat),GFP_KERNEL);
+
+	error = 0;
+out:
+	return error;
+}
+
+
+static struct pppox_proto pppox_pptp_proto = {
+    .create	= pptp_create,
+    //.ioctl	= pptp_ioctl,
+    .owner	= THIS_MODULE,
+};
+
+static struct net_protocol net_pptp_protocol = {
+	.handler	= pptp_rcv,
+	//.err_handler	=	ipgre_err,
+};
+
+
+static int pptp_init_module(void)
+{
+	int err=0;
+	printk(KERN_INFO "PPTP driver version " PPTP_DRIVER_VERSION "\n");
+
+	if (inet_add_protocol(&net_pptp_protocol, IPPROTO_GRE) < 0) {
+		printk(KERN_INFO "PPTP: can't add protocol\n");
+		goto out;
+	}
+
+	err = proto_register(&pptp_sk_proto, 0);
+	if (err){
+		printk(KERN_INFO "PPTP: can't register sk_proto\n");
+		goto out_inet_del_protocol;
+	}
+
+ 	err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
+	if (err){
+		printk(KERN_INFO "PPTP: can't register pppox_proto\n");
+		goto out_unregister_sk_proto;
+	}
+
+	proc_dir=proc_mkdir("pptp",NULL);
+	if (!proc_dir){
+		printk(KERN_ERR "PPTP: failed to create proc dir\n");
+	}
+	//console_verbose();
+
+out:
+	return err;
+out_unregister_sk_proto:
+	proto_unregister(&pptp_sk_proto);
+out_inet_del_protocol:
+	inet_del_protocol(&net_pptp_protocol, IPPROTO_GRE);
+	goto out;
+}
+
+static void pptp_exit_module(void)
+{
+	unregister_pppox_proto(PX_PROTO_PPTP);
+	proto_unregister(&pptp_sk_proto);
+	inet_del_protocol(&net_pptp_protocol, IPPROTO_GRE);
+
+	if (proc_dir)
+		remove_proc_entry("pptp",NULL);
+}
+
+
+module_init(pptp_init_module);
+module_exit(pptp_exit_module);
diff -uprN linux-2.6.16.orig/include/linux/if_pppox.h linux-2.6.16.pptp/include/linux/if_pppox.h
--- linux-2.6.16.orig/include/linux/if_pppox.h	2006-06-18 00:52:01.000000000 +0400
+++ linux-2.6.16.pptp/include/linux/if_pppox.h	2006-06-17 23:45:05.000000000 +0400
@@ -1,6 +1,6 @@
 /***************************************************************************
  * Linux PPP over X - Generic PPP transport layer sockets
- * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) 
+ * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516)
  *
  * This file supplies definitions required by the PPP over Ethernet driver
  * (pppox.c).  All version information wrt this file is located in pppox.c
@@ -19,6 +19,7 @@
 
 #include <asm/types.h>
 #include <asm/byteorder.h>
+#include <linux/in.h>
 
 #ifdef  __KERNEL__
 #include <linux/if_ether.h>
@@ -36,29 +37,35 @@
 #define PF_PPPOX	AF_PPPOX
 #endif /* !(AF_PPPOX) */
 
-/************************************************************************ 
- * PPPoE addressing definition 
- */ 
-typedef __u16 sid_t; 
-struct pppoe_addr{ 
-       sid_t           sid;                    /* Session identifier */ 
-       unsigned char   remote[ETH_ALEN];       /* Remote address */ 
-       char            dev[IFNAMSIZ];          /* Local device to use */ 
-}; 
- 
-/************************************************************************ 
- * Protocols supported by AF_PPPOX 
- */ 
+/************************************************************************
+ * PPPoE addressing definition
+ */
+typedef __u16 sid_t;
+struct pppoe_addr{
+       sid_t           sid;                    /* Session identifier */
+       unsigned char   remote[ETH_ALEN];       /* Remote address */
+       char            dev[IFNAMSIZ];          /* Local device to use */
+};
+
+struct pptp_addr{
+       __u16           call_id;
+       struct in_addr  sin_addr;
+};
+/************************************************************************
+ * Protocols supported by AF_PPPOX
+ */
 #define PX_PROTO_OE    0 /* Currently just PPPoE */
-#define PX_MAX_PROTO   1	
- 
-struct sockaddr_pppox { 
-       sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
-       unsigned int    sa_protocol;          /* protocol identifier */ 
-       union{ 
-               struct pppoe_addr       pppoe; 
-       }sa_addr; 
-}__attribute__ ((packed)); 
+#define PX_PROTO_PPTP  1
+#define PX_MAX_PROTO   2
+
+struct sockaddr_pppox {
+       sa_family_t     sa_family;            /* address family, AF_PPPOX */
+       unsigned int    sa_protocol;          /* protocol identifier */
+       union{
+               struct pppoe_addr       pppoe;
+	       			 struct pptp_addr        pptp;
+       }sa_addr;
+}__attribute__ ((packed));
 
 
 /*********************************************************************
@@ -111,6 +118,12 @@ struct pppoe_hdr {
 	struct pppoe_tag tag[0];
 } __attribute__ ((packed));
 
+
+/* Socket options */
+#define PPTP_SO_TIMEOUT 1
+#define PPTP_SO_WINDOW  2
+
+
 #ifdef __KERNEL__
 struct pppoe_opt {
 	struct net_device      *dev;	  /* device associated with socket*/
@@ -118,6 +131,20 @@ struct pppoe_opt {
 	struct sockaddr_pppox	relay;	  /* what socket data will be
 					     relayed to (PPPoE relaying) */
 };
+struct pptp_opt {
+	struct pptp_addr	src_addr;
+	struct pptp_addr	dst_addr;
+	int timeout;
+	int window;
+	__u32 ack_sent, ack_recv;
+	__u32 seq_sent, seq_recv;
+	int pause;
+	spinlock_t skb_buf_lock;
+	struct sk_buff_head skb_buf;
+	struct work_struct ack_work;  //send ack work
+	struct work_struct buf_work; //check bufferd packets work
+	struct gre_statistics *stat;
+};
 
 #include <net/sock.h>
 
@@ -128,6 +155,7 @@ struct pppox_sock {
 	struct pppox_sock	*next;	  /* for hash table */
 	union {
 		struct pppoe_opt pppoe;
+		struct pptp_opt pptp;
 	} proto;
 	unsigned short		num;
 };
diff -uprN linux-2.6.16.orig/MAINTAINERS linux-2.6.16.pptp/MAINTAINERS
--- linux-2.6.16.orig/MAINTAINERS	2006-06-18 00:52:00.000000000 +0400
+++ linux-2.6.16.pptp/MAINTAINERS	2006-06-18 01:26:45.000000000 +0400
@@ -2118,6 +2118,11 @@ P:	Michal Ostrowski
 M:	mostrows@speakeasy.net
 S:	Maintained
 
+PPTP
+P:      Dmitry Kozlov
+M:      xeb@mail.ru
+S:      Maintained
+
 PREEMPTIBLE KERNEL
 P:	Robert Love
 M:	rml@tech9.net


^ permalink raw reply

* [PATCH 9/9 v3] Add Vitesse 8244 PHY for MPC8641 HPCN platform.
From: Jon Loeliger @ 2006-06-17 22:52 UTC (permalink / raw)
  To: linuxppc-dev, netdev, jeff

Signed-off-by: Kriston Carson <KristonCarson@freescale.com>
Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Acked-by: Jeff Garzik <jeff@garzik.org>

---

 drivers/net/Kconfig       |    6 +-
 drivers/net/phy/Kconfig   |    5 ++
 drivers/net/phy/Makefile  |    1
 drivers/net/phy/vitesse.c |  112 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bdaaad8..c1c2758 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2179,11 +2179,11 @@ config SPIDER_NET
 
 config GIANFAR
 	tristate "Gianfar Ethernet"
-	depends on 85xx || 83xx
+	depends on 85xx || 83xx || PPC_86xx
 	select PHYLIB
 	help
-	  This driver supports the Gigabit TSEC on the MPC85xx 
-	  family of chips, and the FEC on the 8540
+	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+	  and MPC86xx family of chips, and the FEC on the 8540.
 
 config GFAR_NAPI
 	bool "NAPI Support"
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index fa39b94..76e51b1 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -44,6 +44,11 @@ config CICADA_PHY
 	depends on PHYLIB
 	---help---
 	  Currently supports the cis8204
+config VITESSE_PHY
+        tristate "Drivers for the Vitesse PHYs"
+        depends on PHYLIB
+        ---help---
+          Currently supports the vsc8244
 
 endmenu
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e4116a5..a8d066e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
 obj-$(CONFIG_CICADA_PHY)	+= cicada.o
 obj-$(CONFIG_LXT_PHY)		+= lxt.o
 obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
+obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
new file mode 100644
index 0000000..ffd215d
--- /dev/null
+++ b/drivers/net/phy/vitesse.c
@@ -0,0 +1,112 @@
+/*
+ * Driver for Vitesse PHYs
+ *
+ * Author: Kriston Carson
+ *
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+/* Vitesse Extended Control Register 1 */
+#define MII_VSC8244_EXT_CON1           0x17
+#define MII_VSC8244_EXTCON1_INIT       0x0000
+
+/* Vitesse Interrupt Mask Register */
+#define MII_VSC8244_IMASK		0x19
+#define MII_VSC8244_IMASK_IEN		0x8000
+#define MII_VSC8244_IMASK_SPEED		0x4000
+#define MII_VSC8244_IMASK_LINK		0x2000
+#define MII_VSC8244_IMASK_DUPLEX	0x1000
+#define MII_VSC8244_IMASK_MASK		0xf000
+
+/* Vitesse Interrupt Status Register */
+#define MII_VSC8244_ISTAT		0x1a
+#define MII_VSC8244_ISTAT_STATUS	0x8000
+#define MII_VSC8244_ISTAT_SPEED		0x4000
+#define MII_VSC8244_ISTAT_LINK		0x2000
+#define MII_VSC8244_ISTAT_DUPLEX	0x1000
+
+/* Vitesse Auxiliary Control/Status Register */
+#define MII_VSC8244_AUX_CONSTAT        	0x1c
+#define MII_VSC8244_AUXCONSTAT_INIT    	0x0004
+#define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
+#define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
+#define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
+#define MII_VSC8244_AUXCONSTAT_100     	0x0008
+
+MODULE_DESCRIPTION("Vitesse PHY driver");
+MODULE_AUTHOR("Kriston Carson");
+MODULE_LICENSE("GPL");
+
+static int vsc824x_config_init(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+			MII_VSC8244_AUXCONSTAT_INIT);
+	if (err < 0)
+		return err;
+
+	err = phy_write(phydev, MII_VSC8244_EXT_CON1,
+			MII_VSC8244_EXTCON1_INIT);
+	return err;
+}
+
+static int vsc824x_ack_interrupt(struct phy_device *phydev)
+{
+	int err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+	return (err < 0) ? err : 0;
+}
+
+static int vsc824x_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, MII_VSC8244_IMASK,
+				MII_VSC8244_IMASK_MASK);
+	else
+		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+	return err;
+}
+
+/* Vitesse 824x */
+static struct phy_driver vsc8244_driver = {
+	.phy_id		= 0x000fc6c2,
+	.name		= "Vitesse VSC8244",
+	.phy_id_mask	= 0x000fffc0,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &vsc824x_config_init,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &vsc824x_ack_interrupt,
+	.config_intr	= &vsc824x_config_intr,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init vsc8244_init(void)
+{
+	return phy_driver_register(&vsc8244_driver);
+}
+
+static void __exit vsc8244_exit(void)
+{
+	phy_driver_unregister(&vsc8244_driver);
+}
+
+module_init(vsc8244_init);
+module_exit(vsc8244_exit);

^ permalink raw reply related

* Re: Network performance degradation from 2.6.11.12 to 2.6.16.20
From: Andrew Morton @ 2006-06-17 22:35 UTC (permalink / raw)
  To: Harry Edmon; +Cc: linux-kernel, netdev
In-Reply-To: <4492D5D3.4000303@atmos.washington.edu>

On Fri, 16 Jun 2006 09:01:23 -0700
Harry Edmon <harry@atmos.washington.edu> wrote:

> I have a system with a strange network performance degradation from 
> 2.6.11.12 to most recent kernels including 2.6.16.20 and 2.6.17-rc6.   
> The system is has Dual single core Xeons with hyperthreading on.   The 
> application is the LDM system from UCAR/Unidata 
> (http://www.unidata.ucar.edu/software/ldm).   This system requests 
> weather data from a variety of systems using RPC calls over a reserved 
> TCP port (388), puts them into a memory mapped queue file, and then 
> sends the data out to a variety of downstream requesting systems, again 
> using RPC calls.  When the load is heavy, the 2.6.16.20 kernel falls way 
> behind with the data ingestion.  The 2.6.11.12 kernel does not.   I have 
> tried an experiment with a 2.6.17-rc6 system where it just does the 
> ingestion, and not the downstream distribution, and it is able to keep 
> up.   I would really appreciate any pointers as to where the problem may 
> be and how to diagnose it.  I have attached the config files from both 
> kernels and the sysctl.conf file I am using.   I have also included the 
> output from "netstat -s" on the 2.6.16.20 system during a time when it 
> was having problems.
> 

(added netdev)

A quick grep indicates that it isn't using TCP_NODELAY - we've had problems
with that in the past.

Perhaps a tcpdump of the net traffic will help to determine what's going on.

^ permalink raw reply

* Re: recommend a network card
From: Michael Buesch @ 2006-06-17 21:23 UTC (permalink / raw)
  To: bastard operater; +Cc: netdev
In-Reply-To: <BAY101-F7A407E434F2393EB259C6C8800@phx.gbl>

On Saturday 17 June 2006 23:12, bastard operater wrote:
                                ^^^^^^^^^^^^^^^^
People on this list like Real Names and are more
motivated to help, if they know your name.

> My 3Com 3C905B-TX is starting to malfunction and it is getting worse.  So I 

I never had a malfunctioning NIC. What does it look like?
Broken packages?

> am in the market for a new NIC.  The card has to work on Linux (natively) 
> and windows.  I thought I would ask the experts if you have any 
> recommendations for a good 100MB PCI card?

I have mostly RTL based cards (ranging from 10 to 1000 mbit).
No problems so far. (But also no problem with my 3c905 since
quite some time ;) )

-- 
Greetings Michael.

^ permalink raw reply

* [PATCH] d80211: allow NULL for control in beacon_get
From: Michael Buesch @ 2006-06-17 21:10 UTC (permalink / raw)
  To: linville, Jiri Benc; +Cc: netdev, bcm43xx-dev

bcm43xx has no use for the "control" data provided by
ieee80211_beacon_get(), so allow passing a NULL pointer
to avoid setting up a dummy struct and throwing the data
away afterwards in the driver.

Signed-off-by: Michael Buesch <mb@bu3sch.de>

Index: wireless-dev/net/d80211/ieee80211.c
===================================================================
--- wireless-dev.orig/net/d80211/ieee80211.c	2006-06-17 22:51:20.000000000 +0200
+++ wireless-dev/net/d80211/ieee80211.c	2006-06-17 23:03:54.000000000 +0200
@@ -1683,28 +1683,30 @@
 		memcpy(skb_put(skb, bt_len), b_tail, bt_len);
 	}
 
-	memset(&extra, 0, sizeof(extra));
-	extra.endidx = local->num_curr_rates;
+	if (control) {
+		memset(&extra, 0, sizeof(extra));
+		extra.endidx = local->num_curr_rates;
 
-	rate = rate_control_get_rate(dev, skb, &extra);
-	if (rate == NULL) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-			       "found\n", dev->name);
+		rate = rate_control_get_rate(dev, skb, &extra);
+		if (rate == NULL) {
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
+				       "found\n", dev->name);
+			}
+			dev_kfree_skb(skb);
+			return NULL;
 		}
-		dev_kfree_skb(skb);
-		return NULL;
-	}
 
-	control->tx_rate = (local->short_preamble &&
-			    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-		rate->val2 : rate->val;
-	control->antenna_sel = local->conf.antenna_sel;
-	control->power_level = local->conf.power_level;
-	control->no_ack = 1;
-	control->retry_limit = 1;
-	control->rts_cts_duration = 0;
-	control->clear_dst_mask = 1;
+		control->tx_rate = (local->short_preamble &&
+				    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+			rate->val2 : rate->val;
+		control->antenna_sel = local->conf.antenna_sel;
+		control->power_level = local->conf.power_level;
+		control->no_ack = 1;
+		control->retry_limit = 1;
+		control->rts_cts_duration = 0;
+		control->clear_dst_mask = 1;
+	}
 
 	ap->num_beacons++;
 	return skb;


-- 
Greetings Michael.

^ permalink raw reply

* recommend a network card
From: bastard operater @ 2006-06-17 21:12 UTC (permalink / raw)
  To: netdev

Hello,

My 3Com 3C905B-TX is starting to malfunction and it is getting worse.  So I 
am in the market for a new NIC.  The card has to work on Linux (natively) 
and windows.  I thought I would ask the experts if you have any 
recommendations for a good 100MB PCI card?

Thanks,



^ permalink raw reply

* Dear Friend
From: Duoala Mbale @ 2006-06-17 19:03 UTC (permalink / raw)
  To: netdev



My Dear Friend, 

 

 I am interested in a partnership investment programme with your 

self/corporation. 

 

 

 There is this huge amount of Five million Seven hundred and fifthy 

thousand U.S dollars($5,750,000.00)which my late father kept in a 

security/financial company before he was assasinated by unknown persons, 

during a political crisis in my country. 

My father deposited it as a family treasure and that was before his 

death. 

 

Now I and mother left Angola to Senegal,through the help of my late 

father's good friend.Right now we are in refugee camp and 

wehave  decided to invest these money in your country or anywhere safe enough outside my country Angola and the whole of Africa for security and political reasons. 

We would want you to assist us to transfer this fund to your country 

for safty and investment purposes on the followings below: 

 

 1).Telecommunication 

 2).Manufacturing 

 3).Real Estate Business 

 

 If you  will be able of rendering an assistance to us we will 

adequately compensate you 25% Of the total fund. 

 

 We will arrange all the necessary procedures in ensuring a smooth 

process for the funds to get to you.We will also appreciate if you contact 

me once you receive this mail to enable me give you more details.This 

matter requires your urgent attention ,confidentiality and discretion no 

matter what your decision maybe. 

 

 Thank you and God bless you. 

 Your's Sincerely, 

 Duoala Mbale 





^ permalink raw reply

* Re: tg3 timeouts with 2.6.17-rc6
From: Michael Chan @ 2006-06-17 18:23 UTC (permalink / raw)
  To: David Miller; +Cc: jk, linux-kernel, netdev
In-Reply-To: <1551EAE59135BE47B544934E30FC4FC041BD1E@NT-IRVA-0751.brcm.ad.broadcom.com>

On Fri, 2006-06-16 at 20:37 -0700, Michael Chan wrote:
> David Miller wrote:
> 
> > From: "Michael Chan" <mchan@broadcom.com>
> > Date: Fri, 16 Jun 2006 18:27:32 -0700
> > 
> > > In the meantime, I wonder if we should disable TSO by default on the
> > > 5780 chip for 2.6.17.
> > 
> > Sounds reasonable.  Would we disable it for all chips that set
> > TG3_FLG2_5780_CLASS or a specific variant?
> > 
> Yes, let's disable it for all TG3_FLG2_5780_CLASS chips for now
> until we figure out what's going on.

David, Here's the patch if you haven't already made one:

[TG3]: Disable TSO by default on 5780 class chips.

Disable TSO by default on 5780, 5714, and 5715 chips for now while we
investigate the reported tx timeouts by Juergen Kreileder.  Thanks to
Juergen for reporting the problem.

Update version to 3.60.

Signed-off-by: Michael Chan <mchan@broadcom.com>


diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 862c226..607d87e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.59"
-#define DRV_MODULE_RELDATE	"June 8, 2006"
+#define DRV_MODULE_VERSION	"3.60"
+#define DRV_MODULE_RELDATE	"June 17, 2006"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -11385,7 +11385,11 @@ static int __devinit tg3_init_one(struct
 	 * Firmware TSO on older chips gives lower performance, so it
 	 * is off by default, but can be enabled using ethtool.
 	 */
-	if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+	/* Disable TSO by default on all 5780 class chips because
+	 * of reported tx timeouts.
+	 */
+	if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) &&
+	   !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
 		dev->features |= NETIF_F_TSO;
 
 #endif



^ permalink raw reply related

* [IOC3] IP27: Really set PCI64_ATTR_VIRTUAL, not PCI64_ATTR_PREC.
From: Ralf Baechle @ 2006-06-17 17:57 UTC (permalink / raw)
  To: netdev, Jeff Garzik

IOC3's homegrown DMA mapping functions that are used to optimize things
a little on IP27 set the wrong bit.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index ae71ed5..e76e6e7 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_allo
 static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
 {
 #ifdef CONFIG_SGI_IP27
-	vdev <<= 58;   /* Shift to PCI64_ATTR_VIRTUAL */
+	vdev <<= 57;   /* Shift to PCI64_ATTR_VIRTUAL */
 
 	return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF |
 	       ((unsigned long)ptr & TO_PHYS_MASK);

^ permalink raw reply related

* [PATCH, RFT] bcm43xx: Busting the 1G limit
From: Michael Buesch @ 2006-06-17 17:28 UTC (permalink / raw)
  To: bcm43xx-dev, netdev

Hi,

This patch adds full 32-bit and 64-bit DMA support
to the bcm43xx driver. Well, it _should_ do this. I can
not test it, as I don't have a machine to trigger the 1G
limit.
The 1G limit should be exploitable on an AMD64 machine
with more than 1G RAM.

Please test and report, if it works or not. In the
case of "works not", please provide full dmesg log.

Note that I am not sure which cards actually support
full 32-bit or even 64-bit mode. Older cards might still
only support 30-bit DMA.

Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx.h	2006-06-17 17:48:26.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx.h	2006-06-17 18:01:34.000000000 +0200
@@ -32,14 +32,18 @@
 #define BCM43xx_PCICFG_ICR		0x94
 
 /* MMIO offsets */
-#define BCM43xx_MMIO_DMA1_REASON	0x20
-#define BCM43xx_MMIO_DMA1_IRQ_MASK	0x24
-#define BCM43xx_MMIO_DMA2_REASON	0x28
-#define BCM43xx_MMIO_DMA2_IRQ_MASK	0x2C
-#define BCM43xx_MMIO_DMA3_REASON	0x30
-#define BCM43xx_MMIO_DMA3_IRQ_MASK	0x34
-#define BCM43xx_MMIO_DMA4_REASON	0x38
-#define BCM43xx_MMIO_DMA4_IRQ_MASK	0x3C
+#define BCM43xx_MMIO_DMA0_REASON	0x20
+#define BCM43xx_MMIO_DMA0_IRQ_MASK	0x24
+#define BCM43xx_MMIO_DMA1_REASON	0x28
+#define BCM43xx_MMIO_DMA1_IRQ_MASK	0x2C
+#define BCM43xx_MMIO_DMA2_REASON	0x30
+#define BCM43xx_MMIO_DMA2_IRQ_MASK	0x34
+#define BCM43xx_MMIO_DMA3_REASON	0x38
+#define BCM43xx_MMIO_DMA3_IRQ_MASK	0x3C
+#define BCM43xx_MMIO_DMA4_REASON	0x40
+#define BCM43xx_MMIO_DMA4_IRQ_MASK	0x44
+#define BCM43xx_MMIO_DMA5_REASON	0x48
+#define BCM43xx_MMIO_DMA5_IRQ_MASK	0x4C
 #define BCM43xx_MMIO_STATUS_BITFIELD	0x120
 #define BCM43xx_MMIO_STATUS2_BITFIELD	0x124
 #define BCM43xx_MMIO_GEN_IRQ_REASON	0x128
@@ -55,14 +59,27 @@
 #define BCM43xx_MMIO_XMITSTAT_1		0x174
 #define BCM43xx_MMIO_REV3PLUS_TSF_LOW	0x180 /* core rev >= 3 only */
 #define BCM43xx_MMIO_REV3PLUS_TSF_HIGH	0x184 /* core rev >= 3 only */
-#define BCM43xx_MMIO_DMA1_BASE		0x200
-#define BCM43xx_MMIO_DMA2_BASE		0x220
-#define BCM43xx_MMIO_DMA3_BASE		0x240
-#define BCM43xx_MMIO_DMA4_BASE		0x260
+
+/* 32-bit DMA */
+#define BCM43xx_MMIO_DMA32_BASE0	0x200
+#define BCM43xx_MMIO_DMA32_BASE1	0x220
+#define BCM43xx_MMIO_DMA32_BASE2	0x240
+#define BCM43xx_MMIO_DMA32_BASE3	0x260
+#define BCM43xx_MMIO_DMA32_BASE4	0x280
+#define BCM43xx_MMIO_DMA32_BASE5	0x2A0
+/* 64-bit DMA */
+#define BCM43xx_MMIO_DMA64_BASE0	0x200
+#define BCM43xx_MMIO_DMA64_BASE1	0x240
+#define BCM43xx_MMIO_DMA64_BASE2	0x280
+#define BCM43xx_MMIO_DMA64_BASE3	0x2C0
+#define BCM43xx_MMIO_DMA64_BASE4	0x300
+#define BCM43xx_MMIO_DMA64_BASE5	0x340
+/* PIO */
 #define BCM43xx_MMIO_PIO1_BASE		0x300
 #define BCM43xx_MMIO_PIO2_BASE		0x310
 #define BCM43xx_MMIO_PIO3_BASE		0x320
 #define BCM43xx_MMIO_PIO4_BASE		0x330
+
 #define BCM43xx_MMIO_PHY_VER		0x3E0
 #define BCM43xx_MMIO_PHY_RADIO		0x3E2
 #define BCM43xx_MMIO_ANTENNA		0x3E8
@@ -231,8 +248,14 @@
 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK	0x20000
 
 /* sbtmstatehigh state flags */
-#define BCM43xx_SBTMSTATEHIGH_SERROR		0x1
-#define BCM43xx_SBTMSTATEHIGH_BUSY		0x4
+#define BCM43xx_SBTMSTATEHIGH_SERROR		0x00000001
+#define BCM43xx_SBTMSTATEHIGH_BUSY		0x00000004
+#define BCM43xx_SBTMSTATEHIGH_TIMEOUT		0x00000020
+#define BCM43xx_SBTMSTATEHIGH_COREFLAGS		0x1FFF0000
+#define BCM43xx_SBTMSTATEHIGH_DMA64BIT		0x10000000
+#define BCM43xx_SBTMSTATEHIGH_GATEDCLK		0x20000000
+#define BCM43xx_SBTMSTATEHIGH_BISTFAILED	0x40000000
+#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE	0x80000000
 
 /* sbimstate flags */
 #define BCM43xx_SBIMSTATE_IB_ERROR		0x20000
@@ -566,8 +589,11 @@
 	struct bcm43xx_dmaring *tx_ring1;
 	struct bcm43xx_dmaring *tx_ring2;
 	struct bcm43xx_dmaring *tx_ring3;
+	struct bcm43xx_dmaring *tx_ring4;
+	struct bcm43xx_dmaring *tx_ring5;
+
 	struct bcm43xx_dmaring *rx_ring0;
-	struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
+	struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
 };
 
 /* Data structures for PIO transmission, per 80211 core. */
@@ -708,7 +734,7 @@
 
 	/* Reason code of the last interrupt. */
 	u32 irq_reason;
-	u32 dma_reason[4];
+	u32 dma_reason[6];
 	/* saved irq enable/disable state bitfield. */
 	u32 irq_savedstate;
 	/* Link Quality calculation context. */
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	2006-06-17 17:48:26.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_dma.c	2006-06-17 19:18:41.000000000 +0200
@@ -4,7 +4,7 @@
 
   DMA ringbuffer and descriptor allocation/management
 
-  Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+  Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
 
   Some code in this file is derived from the b44.c driver
   Copyright (C) 2002 David S. Miller
@@ -109,6 +109,35 @@
 	}
 }
 
+u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
+{
+	static const u16 map64[] = {
+		BCM43xx_MMIO_DMA64_BASE0,
+		BCM43xx_MMIO_DMA64_BASE1,
+		BCM43xx_MMIO_DMA64_BASE2,
+		BCM43xx_MMIO_DMA64_BASE3,
+		BCM43xx_MMIO_DMA64_BASE4,
+		BCM43xx_MMIO_DMA64_BASE5,
+	};
+	static const u16 map32[] = {
+		BCM43xx_MMIO_DMA32_BASE0,
+		BCM43xx_MMIO_DMA32_BASE1,
+		BCM43xx_MMIO_DMA32_BASE2,
+		BCM43xx_MMIO_DMA32_BASE3,
+		BCM43xx_MMIO_DMA32_BASE4,
+		BCM43xx_MMIO_DMA32_BASE5,
+	};
+
+	if (dma64bit) {
+		assert(controller_idx >= 0 ||
+		       controller_idx < ARRAY_SIZE(map64));
+		return map64[controller_idx];
+	}
+	assert(controller_idx >= 0 ||
+	       controller_idx < ARRAY_SIZE(map32));
+	return map32[controller_idx];
+}
+
 static inline
 dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  unsigned char *buf,
@@ -172,7 +201,6 @@
 /* Unmap and free a descriptor buffer. */
 static inline
 void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
-			    struct bcm43xx_dmadesc *desc,
 			    struct bcm43xx_dmadesc_meta *meta,
 			    int irq_context)
 {
@@ -188,23 +216,13 @@
 {
 	struct device *dev = &(ring->bcm->pci_dev->dev);
 
-	ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					 &(ring->dmabase), GFP_KERNEL);
-	if (!ring->vbase) {
+	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase), GFP_KERNEL);
+	if (!ring->descbase) {
 		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
 	}
-	if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
-		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RINGMEMORY >1G "
-				    "(0x%llx, len: %lu)\n",
-				(unsigned long long)ring->dmabase,
-				BCM43xx_DMA_RINGMEMSIZE);
-		dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-				  ring->vbase, ring->dmabase);
-		return -ENOMEM;
-	}
-	assert(!(ring->dmabase & 0x000003FF));
-	memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
 }
@@ -214,26 +232,34 @@
 	struct device *dev = &(ring->bcm->pci_dev->dev);
 
 	dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-			  ring->vbase, ring->dmabase);
+			  ring->descbase, ring->dmabase);
 }
 
 /* Reset the RX DMA channel */
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-				   u16 mmio_base)
+				   u16 mmio_base, int dma64)
 {
 	int i;
 	u32 value;
+	u16 offset;
 
-	bcm43xx_write32(bcm,
-			mmio_base + BCM43xx_DMA_RX_CONTROL,
-			0x00000000);
+	offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
+	bcm43xx_write32(bcm, mmio_base + offset, 0);
 	for (i = 0; i < 1000; i++) {
-		value = bcm43xx_read32(bcm,
-				       mmio_base + BCM43xx_DMA_RX_STATUS);
-		value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
-		if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
-			i = -1;
-			break;
+		offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
+		value = bcm43xx_read32(bcm, mmio_base + offset);
+		if (dma64) {
+			value &= BCM43xx_DMA64_RXSTAT;
+			if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= BCM43xx_DMA32_RXSTATE;
+			if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
 		}
 		udelay(10);
 	}
@@ -247,31 +273,47 @@
 
 /* Reset the RX DMA channel */
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-				   u16 mmio_base)
+				   u16 mmio_base, int dma64)
 {
 	int i;
 	u32 value;
+	u16 offset;
 
 	for (i = 0; i < 1000; i++) {
-		value = bcm43xx_read32(bcm,
-				       mmio_base + BCM43xx_DMA_TX_STATUS);
-		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
-		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
-		    value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
-		    value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
-			break;
+		offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+		value = bcm43xx_read32(bcm, mmio_base + offset);
+		if (dma64) {
+			value &= BCM43xx_DMA64_TXSTAT;
+			if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
+			    value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
+			    value == BCM43xx_DMA64_TXSTAT_STOPPED)
+				break;
+		} else {
+			value &= BCM43xx_DMA32_TXSTATE;
+			if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
+			    value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
+			    value == BCM43xx_DMA32_TXSTAT_STOPPED)
+				break;
+		}
 		udelay(10);
 	}
-	bcm43xx_write32(bcm,
-			mmio_base + BCM43xx_DMA_TX_CONTROL,
-			0x00000000);
+	offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
+	bcm43xx_write32(bcm, mmio_base + offset, 0);
 	for (i = 0; i < 1000; i++) {
-		value = bcm43xx_read32(bcm,
-				       mmio_base + BCM43xx_DMA_TX_STATUS);
-		value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
-		if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
-			i = -1;
-			break;
+		offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+		value = bcm43xx_read32(bcm, mmio_base + offset);
+		if (dma64) {
+			value &= BCM43xx_DMA64_TXSTAT;
+			if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= BCM43xx_DMA32_TXSTATE;
+			if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
 		}
 		udelay(10);
 	}
@@ -285,47 +327,98 @@
 	return 0;
 }
 
+static void fill_descriptor(struct bcm43xx_dmaring *ring,
+			    struct bcm43xx_dmadesc_generic *desc,
+			    dma_addr_t dmaaddr,
+			    u16 bufsize,
+			    int start, int end, int irq)
+{
+	int slot;
+
+	slot = bcm43xx_dma_desc2idx(ring, desc);
+	assert(slot >= 0 && slot < ring->nr_slots);
+
+	if (ring->dma64) {
+		u32 ctl0 = 0, ctl1 = 0;
+		u32 addrlo, addrhi;
+		u32 addrext;
+
+		addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+		addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
+		addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+		addrhi |= ring->routing;
+		if (slot == ring->nr_slots - 1)
+			ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
+		if (start)
+			ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
+		if (end)
+			ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
+		if (irq)
+			ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
+		ctl1 |= (bufsize - ring->frameoffset)
+			& BCM43xx_DMA64_DCTL1_BYTECNT;
+		ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
+			& BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
+
+		desc->dma64.control0 = cpu_to_le32(ctl0);
+		desc->dma64.control1 = cpu_to_le32(ctl1);
+		desc->dma64.address_low = cpu_to_le32(addrlo);
+		desc->dma64.address_high = cpu_to_le32(addrhi);
+	} else {
+		u32 ctl;
+		u32 addr;
+		u32 addrext;
+
+		addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
+		addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
+			   >> BCM43xx_DMA32_ROUTING_SHIFT;
+		addr |= ring->routing;
+		ctl = (bufsize - ring->frameoffset)
+		      & BCM43xx_DMA32_DCTL_BYTECNT;
+		if (slot == ring->nr_slots - 1)
+			ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
+		if (start)
+			ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
+		if (end)
+			ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
+		if (irq)
+			ctl |= BCM43xx_DMA32_DCTL_IRQ;
+		ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
+		       & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
+
+		desc->dma32.control = cpu_to_le32(ctl);
+		desc->dma32.address = cpu_to_le32(addr);
+	}
+}
+
 static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
-			       struct bcm43xx_dmadesc *desc,
+			       struct bcm43xx_dmadesc_generic *desc,
 			       struct bcm43xx_dmadesc_meta *meta,
 			       gfp_t gfp_flags)
 {
 	struct bcm43xx_rxhdr *rxhdr;
+	struct bcm43xx_hwxmitstatus *xmitstat;
 	dma_addr_t dmaaddr;
-	u32 desc_addr;
-	u32 desc_ctl;
-	const int slot = (int)(desc - ring->vbase);
 	struct sk_buff *skb;
 
-	assert(slot >= 0 && slot < ring->nr_slots);
 	assert(!ring->tx);
 
 	skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-	if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
-		unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
-		dev_kfree_skb_any(skb);
-		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA RX SKB >1G "
-				    "(0x%llx, len: %u)\n",
-			(unsigned long long)dmaaddr, ring->rx_buffersize);
-		return -ENOMEM;
-	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
-	desc_addr = (u32)(dmaaddr + ring->memoffset);
-	desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
-		    (u32)(ring->rx_buffersize - ring->frameoffset));
-	if (slot == ring->nr_slots - 1)
-		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
-	set_desc_addr(desc, desc_addr);
-	set_desc_ctl(desc, desc_ctl);
+
+	fill_descriptor(ring, desc, dmaaddr,
+			ring->rx_buffersize, 0, 0, 0);
 
 	rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
 	rxhdr->frame_length = 0;
 	rxhdr->flags1 = 0;
+	xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
+	xmitstat->cookie = 0;
 
 	return 0;
 }
@@ -336,17 +429,17 @@
 static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
 {
 	int i, err = -ENOMEM;
-	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 
 	for (i = 0; i < ring->nr_slots; i++) {
-		desc = ring->vbase + i;
-		meta = ring->meta + i;
+		desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
 		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
 		if (err)
 			goto err_unwind;
 	}
+	mb();
 	ring->used_slots = ring->nr_slots;
 	err = 0;
 out:
@@ -354,8 +447,7 @@
 
 err_unwind:
 	for (i--; i >= 0; i--) {
-		desc = ring->vbase + i;
-		meta = ring->meta + i;
+		desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
 		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
 		dev_kfree_skb(meta->skb);
@@ -371,27 +463,67 @@
 {
 	int err = 0;
 	u32 value;
+	u32 addrext;
 
 	if (ring->tx) {
-		/* Set Transmit Control register to "transmit enable" */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-				  BCM43xx_DMA_TXCTRL_ENABLE);
-		/* Set Transmit Descriptor ring address. */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
-				  ring->dmabase + ring->memoffset);
+		if (ring->dma64) {
+			u64 ringbase = (u64)(ring->dmabase);
+
+			addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+			value = BCM43xx_DMA64_TXENABLE;
+			value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
+				& BCM43xx_DMA64_TXADDREXT_MASK;
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
+					(ringbase & 0xFFFFFFFF));
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
+					((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+					| ring->routing);
+		} else {
+			u32 ringbase = (u32)(ring->dmabase);
+
+			addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+			value = BCM43xx_DMA32_TXENABLE;
+			value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
+				& BCM43xx_DMA32_TXADDREXT_MASK;
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
+					(ringbase & ~BCM43xx_DMA32_ROUTING)
+					| ring->routing);
+		}
 	} else {
 		err = alloc_initial_descbuffers(ring);
 		if (err)
 			goto out;
-		/* Set Receive Control "receive enable" and frame offset */
-		value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
-		value |= BCM43xx_DMA_RXCTRL_ENABLE;
-		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
-		/* Set Receive Descriptor ring address. */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
-				  ring->dmabase + ring->memoffset);
-		/* Init the descriptor pointer. */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
+		if (ring->dma64) {
+			u64 ringbase = (u64)(ring->dmabase);
+
+			addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+			value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
+			value |= BCM43xx_DMA64_RXENABLE;
+			value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
+				& BCM43xx_DMA64_RXADDREXT_MASK;
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
+					(ringbase & 0xFFFFFFFF));
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
+					((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+					| ring->routing);
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
+		} else {
+			u32 ringbase = (u32)(ring->dmabase);
+
+			addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+			value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
+			value |= BCM43xx_DMA32_RXENABLE;
+			value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
+				& BCM43xx_DMA32_RXADDREXT_MASK;
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
+					(ringbase & ~BCM43xx_DMA32_ROUTING)
+					| ring->routing);
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
+		}
 	}
 
 out:
@@ -402,27 +534,32 @@
 static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
 {
 	if (ring->tx) {
-		bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
-		/* Zero out Transmit Descriptor ring address. */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
+		bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+		if (ring->dma64) {
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
+		} else
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
 	} else {
-		bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
-		/* Zero out Receive Descriptor ring address. */
-		bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
+		bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+		if (ring->dma64) {
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
+			bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
+		} else
+			bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
 	}
 }
 
 static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
 {
-	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	int i;
 
 	if (!ring->used_slots)
 		return;
 	for (i = 0; i < ring->nr_slots; i++) {
-		desc = ring->vbase + i;
-		meta = ring->meta + i;
+		desc = bcm43xx_dma_idx2desc(ring, i, &meta);
 
 		if (!meta->skb) {
 			assert(ring->tx);
@@ -430,62 +567,67 @@
 		}
 		if (ring->tx) {
 			unmap_descbuffer(ring, meta->dmaaddr,
-					 meta->skb->len, 1);
+					meta->skb->len, 1);
 		} else {
 			unmap_descbuffer(ring, meta->dmaaddr,
-					 ring->rx_buffersize, 0);
+					ring->rx_buffersize, 0);
 		}
-		free_descriptor_buffer(ring, desc, meta, 0);
+		free_descriptor_buffer(ring, meta, 0);
 	}
 }
 
 /* Main initialization function. */
 static
 struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
-					       u16 dma_controller_base,
-					       int nr_descriptor_slots,
-					       int tx)
+					       int controller_index,
+					       int for_tx,
+					       int dma64)
 {
 	struct bcm43xx_dmaring *ring;
 	int err;
+	int nr_slots;
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring)
 		goto out;
 
-	ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
-			     GFP_KERNEL);
+	nr_slots = BCM43xx_RXRING_SLOTS;
+	if (for_tx)
+		nr_slots = BCM43xx_TXRING_SLOTS;
+
+	ring->meta = kzalloc(sizeof(*ring->meta) * nr_slots,
+			GFP_KERNEL);
 	if (!ring->meta)
 		goto err_kfree_ring;
 
-	ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
+	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
+	if (dma64)
+		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
 #ifdef CONFIG_BCM947XX
 	if (bcm->pci_dev->bus->number == 0)
-		ring->memoffset = 0;
+		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
 #endif
 
 	ring->bcm = bcm;
-	ring->nr_slots = nr_descriptor_slots;
+	ring->nr_slots = nr_slots;
 	ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
 	ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
 	assert(ring->suspend_mark < ring->resume_mark);
-	ring->mmio_base = dma_controller_base;
-	if (tx) {
+	ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
+	ring->index = controller_index;
+	ring->dma64 = !!dma64;
+	if (for_tx) {
 		ring->tx = 1;
 		ring->current_slot = -1;
 	} else {
-		switch (dma_controller_base) {
-		case BCM43xx_MMIO_DMA1_BASE:
-			ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
-			ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
-			break;
-		case BCM43xx_MMIO_DMA4_BASE:
-			ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
-			ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
-			break;
-		default:
+		if (ring->index == 0) {
+			ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
+		} else if (ring->index == 3) {
+			ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
+			ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
+		} else
 			assert(0);
-		}
 	}
 
 	err = alloc_ringmemory(ring);
@@ -514,7 +656,8 @@
 	if (!ring)
 		return;
 
-	dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
+	dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+		(ring->dma64) ? "64" : "32",
 		ring->mmio_base,
 		(ring->tx) ? "TX" : "RX",
 		ring->max_used_slots, ring->nr_slots);
@@ -537,10 +680,15 @@
 		return;
 	dma = bcm43xx_current_dma(bcm);
 
-	bcm43xx_destroy_dmaring(dma->rx_ring1);
-	dma->rx_ring1 = NULL;
+	bcm43xx_destroy_dmaring(dma->rx_ring3);
+	dma->rx_ring3 = NULL;
 	bcm43xx_destroy_dmaring(dma->rx_ring0);
 	dma->rx_ring0 = NULL;
+
+	bcm43xx_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+	bcm43xx_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
 	bcm43xx_destroy_dmaring(dma->tx_ring3);
 	dma->tx_ring3 = NULL;
 	bcm43xx_destroy_dmaring(dma->tx_ring2);
@@ -556,48 +704,59 @@
 	struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
+	int dma64 = 0;
+	u32 sbtmstatehi;
+
+	sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+	if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+		dma64 = 1;
 
 	/* setup TX DMA channels. */
-	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
-				     BCM43xx_TXRING_SLOTS, 1);
+	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
 	if (!ring)
 		goto out;
 	dma->tx_ring0 = ring;
 
-	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
-				     BCM43xx_TXRING_SLOTS, 1);
+	ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
 	if (!ring)
 		goto err_destroy_tx0;
 	dma->tx_ring1 = ring;
 
-	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
-				     BCM43xx_TXRING_SLOTS, 1);
+	ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
 	if (!ring)
 		goto err_destroy_tx1;
 	dma->tx_ring2 = ring;
 
-	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
-				     BCM43xx_TXRING_SLOTS, 1);
+	ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
 	if (!ring)
 		goto err_destroy_tx2;
 	dma->tx_ring3 = ring;
 
-	/* setup RX DMA channels. */
-	ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
-				     BCM43xx_RXRING_SLOTS, 0);
+	ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
 	if (!ring)
 		goto err_destroy_tx3;
+	dma->tx_ring4 = ring;
+
+	ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx4;
+	dma->tx_ring5 = ring;
+
+	/* setup RX DMA channels. */
+	ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
+	if (!ring)
+		goto err_destroy_tx5;
 	dma->rx_ring0 = ring;
 
 	if (bcm->current_core->rev < 5) {
-		ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
-					     BCM43xx_RXRING_SLOTS, 0);
+		ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
 		if (!ring)
 			goto err_destroy_rx0;
-		dma->rx_ring1 = ring;
+		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "DMA initialized\n");
+	dprintk(KERN_INFO PFX "%s DMA initialized\n",
+			dma64 ? "64-bit" : "32-bit");
 	err = 0;
 out:
 	return err;
@@ -605,6 +764,12 @@
 err_destroy_rx0:
 	bcm43xx_destroy_dmaring(dma->rx_ring0);
 	dma->rx_ring0 = NULL;
+err_destroy_tx5:
+	bcm43xx_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+err_destroy_tx4:
+	bcm43xx_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
 err_destroy_tx3:
 	bcm43xx_destroy_dmaring(dma->tx_ring3);
 	dma->tx_ring3 = NULL;
@@ -624,7 +789,7 @@
 static u16 generate_cookie(struct bcm43xx_dmaring *ring,
 			   int slot)
 {
-	u16 cookie = 0xF000;
+	u16 cookie = 0x1000;
 
 	/* Use the upper 4 bits of the cookie as
 	 * DMA controller ID and store the slot number
@@ -632,21 +797,25 @@
 	 * Note that the cookie must never be 0, as this
 	 * is a special value used in RX path.
 	 */
-	switch (ring->mmio_base) {
-	default:
-		assert(0);
-	case BCM43xx_MMIO_DMA1_BASE:
+	switch (ring->index) {
+	case 0:
 		cookie = 0xA000;
 		break;
-	case BCM43xx_MMIO_DMA2_BASE:
+	case 1:
 		cookie = 0xB000;
 		break;
-	case BCM43xx_MMIO_DMA3_BASE:
+	case 2:
 		cookie = 0xC000;
 		break;
-	case BCM43xx_MMIO_DMA4_BASE:
+	case 3:
 		cookie = 0xD000;
 		break;
+	case 4:
+		cookie = 0xE000;
+		break;
+	case 5:
+		cookie = 0xF000;
+		break;
 	}
 	assert(((u16)slot & 0xF000) == 0x0000);
 	cookie |= (u16)slot;
@@ -675,6 +844,12 @@
 	case 0xD000:
 		ring = dma->tx_ring3;
 		break;
+	case 0xE000:
+		ring = dma->tx_ring4;
+		break;
+	case 0xF000:
+		ring = dma->tx_ring5;
+		break;
 	default:
 		assert(0);
 	}
@@ -687,6 +862,9 @@
 static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
 				  int slot)
 {
+	u16 offset;
+	int descsize;
+
 	/* Everything is ready to start. Buffers are DMA mapped and
 	 * associated with slots.
 	 * "slot" is the last slot of the new frame we want to transmit.
@@ -694,25 +872,26 @@
 	 */
 	wmb();
 	slot = next_slot(ring, slot);
-	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
-			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+	offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
+	descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
+		: sizeof(struct bcm43xx_dmadesc32);
+	bcm43xx_dma_write(ring, offset,
+			(u32)(slot * descsize));
 }
 
-static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
-			   struct sk_buff *skb,
-			   u8 cur_frag)
+static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
+			    struct sk_buff *skb,
+			    u8 cur_frag)
 {
 	int slot;
-	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
-	u32 desc_ctl;
-	u32 desc_addr;
+	dma_addr_t dmaaddr;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
 	slot = request_slot(ring);
-	desc = ring->vbase + slot;
-	meta = ring->meta + slot;
+	desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
 
 	/* Add a device specific TX header. */
 	assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
@@ -729,29 +908,14 @@
 			       generate_cookie(ring, slot));
 
 	meta->skb = skb;
-	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-	if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
-		return_slot(ring, slot);
-		printk(KERN_ERR PFX ">>>FATAL ERROR<<<  DMA TX SKB >1G "
-				    "(0x%llx, len: %u)\n",
-			(unsigned long long)meta->dmaaddr, skb->len);
-		return -ENOMEM;
-	}
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	meta->dmaaddr = dmaaddr;
 
-	desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
-	desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
-	desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
-	desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
-		     (u32)(meta->skb->len - ring->frameoffset));
-	if (slot == ring->nr_slots - 1)
-		desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+	fill_descriptor(ring, desc, dmaaddr,
+			skb->len, 1, 1, 1);
 
-	set_desc_ctl(desc, desc_ctl);
-	set_desc_addr(desc, desc_addr);
 	/* Now transfer the whole frame. */
 	dmacontroller_poke_tx(ring, slot);
-
-	return 0;
 }
 
 int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
@@ -781,7 +945,6 @@
 		/* Take skb from ieee80211_txb_free */
 		txb->fragments[i] = NULL;
 		dma_tx_fragment(ring, skb, i);
-		//TODO: handle failure of dma_tx_fragment
 	}
 	ieee80211_txb_free(txb);
 
@@ -792,23 +955,28 @@
 				   struct bcm43xx_xmitstatus *status)
 {
 	struct bcm43xx_dmaring *ring;
-	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	int is_last_fragment;
 	int slot;
+	u32 tmp;
 
 	ring = parse_cookie(bcm, status->cookie, &slot);
 	assert(ring);
 	assert(ring->tx);
-	assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
 	while (1) {
 		assert(slot >= 0 && slot < ring->nr_slots);
-		desc = ring->vbase + slot;
-		meta = ring->meta + slot;
+		desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
 
-		is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
+		if (ring->dma64) {
+			tmp = le32_to_cpu(desc->dma64.control0);
+			is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
+		} else {
+			tmp = le32_to_cpu(desc->dma32.control);
+			is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
+		}
 		unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
-		free_descriptor_buffer(ring, desc, meta, 1);
+		free_descriptor_buffer(ring, meta, 1);
 		/* Everything belonging to the slot is unmapped
 		 * and freed, so we can return it.
 		 */
@@ -824,7 +992,7 @@
 static void dma_rx(struct bcm43xx_dmaring *ring,
 		   int *slot)
 {
-	struct bcm43xx_dmadesc *desc;
+	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	struct bcm43xx_rxhdr *rxhdr;
 	struct sk_buff *skb;
@@ -832,13 +1000,12 @@
 	int err;
 	dma_addr_t dmaaddr;
 
-	desc = ring->vbase + *slot;
-	meta = ring->meta + *slot;
+	desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
 
 	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
 	skb = meta->skb;
 
-	if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
+	if (ring->index == 3) {
 		/* We received an xmit status. */
 		struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
 		struct bcm43xx_xmitstatus stat;
@@ -894,8 +1061,7 @@
 		s32 tmp = len;
 
 		while (1) {
-			desc = ring->vbase + *slot;
-			meta = ring->meta + *slot;
+			desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
 			/* recycle the descriptor buffer. */
 			sync_descbuffer_for_device(ring, meta->dmaaddr,
 						   ring->rx_buffersize);
@@ -906,8 +1072,8 @@
 				break;
 		}
 		printkl(KERN_ERR PFX "DMA RX buffer too small "
-				     "(len: %u, buffer: %u, nr-dropped: %d)\n",
-		        len, ring->rx_buffersize, cnt);
+			"(len: %u, buffer: %u, nr-dropped: %d)\n",
+			len, ring->rx_buffersize, cnt);
 		goto drop;
 	}
 	len -= IEEE80211_FCS_LEN;
@@ -945,9 +1111,15 @@
 #endif
 
 	assert(!ring->tx);
-	status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
-	descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
-	current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
+	if (ring->dma64) {
+		status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
+		descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
+		current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
+	} else {
+		status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
+		descptr = (status & BCM43xx_DMA32_RXDPTR);
+		current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
+	}
 	assert(current_slot >= 0 && current_slot < ring->nr_slots);
 
 	slot = ring->current_slot;
@@ -958,8 +1130,13 @@
 			ring->max_used_slots = used_slots;
 #endif
 	}
-	bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
-			  (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+	if (ring->dma64) {
+		bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
+				(u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
+	} else {
+		bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
+				(u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
+	}
 	ring->current_slot = slot;
 }
 
@@ -967,16 +1144,28 @@
 {
 	assert(ring->tx);
 	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
-	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
-			  | BCM43xx_DMA_TXCTRL_SUSPEND);
+	if (ring->dma64) {
+		bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+				bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+				| BCM43xx_DMA64_TXSUSPEND);
+	} else {
+		bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+				bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+				| BCM43xx_DMA32_TXSUSPEND);
+	}
 }
 
 void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
 {
 	assert(ring->tx);
-	bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
-			  bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
-			  & ~BCM43xx_DMA_TXCTRL_SUSPEND);
+	if (ring->dma64) {
+		bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+				bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+				& ~BCM43xx_DMA64_TXSUSPEND);
+	} else {
+		bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+				bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+				& ~BCM43xx_DMA32_TXSUSPEND);
+	}
 	bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
 }
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_dma.h	2006-06-17 17:48:26.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_dma.h	2006-06-17 19:09:40.000000000 +0200
@@ -14,63 +14,179 @@
 #define BCM43xx_DMAIRQ_NONFATALMASK	(1 << 13)
 #define BCM43xx_DMAIRQ_RX_DONE		(1 << 16)
 
-/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
-#define BCM43xx_DMA_TX_CONTROL		0x00
-#define BCM43xx_DMA_TX_DESC_RING	0x04
-#define BCM43xx_DMA_TX_DESC_INDEX	0x08
-#define BCM43xx_DMA_TX_STATUS		0x0c
-#define BCM43xx_DMA_RX_CONTROL		0x10
-#define BCM43xx_DMA_RX_DESC_RING	0x14
-#define BCM43xx_DMA_RX_DESC_INDEX	0x18
-#define BCM43xx_DMA_RX_STATUS		0x1c
-
-/* DMA controller channel control word values. */
-#define BCM43xx_DMA_TXCTRL_ENABLE		(1 << 0)
-#define BCM43xx_DMA_TXCTRL_SUSPEND		(1 << 1)
-#define BCM43xx_DMA_TXCTRL_LOOPBACK		(1 << 2)
-#define BCM43xx_DMA_TXCTRL_FLUSH		(1 << 4)
-#define BCM43xx_DMA_RXCTRL_ENABLE		(1 << 0)
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK	0x000000fe
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT	1
-#define BCM43xx_DMA_RXCTRL_PIO			(1 << 8)
-/* DMA controller channel status word values. */
-#define BCM43xx_DMA_TXSTAT_DPTR_MASK		0x00000fff
-#define BCM43xx_DMA_TXSTAT_STAT_MASK		0x0000f000
-#define BCM43xx_DMA_TXSTAT_STAT_DISABLED	0x00000000
-#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE		0x00001000
-#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT	0x00002000
-#define BCM43xx_DMA_TXSTAT_STAT_STOPPED		0x00003000
-#define BCM43xx_DMA_TXSTAT_STAT_SUSP		0x00004000
-#define BCM43xx_DMA_TXSTAT_ERROR_MASK		0x000f0000
-#define BCM43xx_DMA_TXSTAT_FLUSHED		(1 << 20)
-#define BCM43xx_DMA_RXSTAT_DPTR_MASK		0x00000fff
-#define BCM43xx_DMA_RXSTAT_STAT_MASK		0x0000f000
-#define BCM43xx_DMA_RXSTAT_STAT_DISABLED	0x00000000
-#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE		0x00001000
-#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT	0x00002000
-#define BCM43xx_DMA_RXSTAT_STAT_RESERVED	0x00003000
-#define BCM43xx_DMA_RXSTAT_STAT_ERRORS		0x00004000
-#define BCM43xx_DMA_RXSTAT_ERROR_MASK		0x000f0000
-
-/* DMA descriptor control field values. */
-#define BCM43xx_DMADTOR_BYTECNT_MASK		0x00001fff
-#define BCM43xx_DMADTOR_DTABLEEND		(1 << 28) /* End of descriptor table */
-#define BCM43xx_DMADTOR_COMPIRQ			(1 << 29) /* IRQ on completion request */
-#define BCM43xx_DMADTOR_FRAMEEND		(1 << 30)
-#define BCM43xx_DMADTOR_FRAMESTART		(1 << 31)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define BCM43xx_DMA32_TXCTL				0x00
+#define		BCM43xx_DMA32_TXENABLE			0x00000001
+#define		BCM43xx_DMA32_TXSUSPEND			0x00000002
+#define		BCM43xx_DMA32_TXLOOPBACK		0x00000004
+#define		BCM43xx_DMA32_TXFLUSH			0x00000010
+#define		BCM43xx_DMA32_TXADDREXT_MASK		0x00030000
+#define		BCM43xx_DMA32_TXADDREXT_SHIFT		16
+#define BCM43xx_DMA32_TXRING				0x04
+#define BCM43xx_DMA32_TXINDEX				0x08
+#define BCM43xx_DMA32_TXSTATUS				0x0C
+#define		BCM43xx_DMA32_TXDPTR			0x00000FFF
+#define		BCM43xx_DMA32_TXSTATE			0x0000F000
+#define			BCM43xx_DMA32_TXSTAT_DISABLED	0x00000000
+#define			BCM43xx_DMA32_TXSTAT_ACTIVE	0x00001000
+#define			BCM43xx_DMA32_TXSTAT_IDLEWAIT	0x00002000
+#define			BCM43xx_DMA32_TXSTAT_STOPPED	0x00003000
+#define			BCM43xx_DMA32_TXSTAT_SUSP	0x00004000
+#define		BCM43xx_DMA32_TXERROR			0x000F0000
+#define			BCM43xx_DMA32_TXERR_NOERR	0x00000000
+#define			BCM43xx_DMA32_TXERR_PROT	0x00010000
+#define			BCM43xx_DMA32_TXERR_UNDERRUN	0x00020000
+#define			BCM43xx_DMA32_TXERR_BUFREAD	0x00030000
+#define			BCM43xx_DMA32_TXERR_DESCREAD	0x00040000
+#define		BCM43xx_DMA32_TXACTIVE			0xFFF00000
+#define BCM43xx_DMA32_RXCTL				0x10
+#define		BCM43xx_DMA32_RXENABLE			0x00000001
+#define		BCM43xx_DMA32_RXFROFF_MASK		0x000000FE
+#define		BCM43xx_DMA32_RXFROFF_SHIFT		1
+#define		BCM43xx_DMA32_RXDIRECTFIFO		0x00000100
+#define		BCM43xx_DMA32_RXADDREXT_MASK		0x00030000
+#define		BCM43xx_DMA32_RXADDREXT_SHIFT		16
+#define BCM43xx_DMA32_RXRING				0x14
+#define BCM43xx_DMA32_RXINDEX				0x18
+#define BCM43xx_DMA32_RXSTATUS				0x1C
+#define		BCM43xx_DMA32_RXDPTR			0x00000FFF
+#define		BCM43xx_DMA32_RXSTATE			0x0000F000
+#define			BCM43xx_DMA32_RXSTAT_DISABLED	0x00000000
+#define			BCM43xx_DMA32_RXSTAT_ACTIVE	0x00001000
+#define			BCM43xx_DMA32_RXSTAT_IDLEWAIT	0x00002000
+#define			BCM43xx_DMA32_RXSTAT_STOPPED	0x00003000
+#define		BCM43xx_DMA32_RXERROR			0x000F0000
+#define			BCM43xx_DMA32_RXERR_NOERR	0x00000000
+#define			BCM43xx_DMA32_RXERR_PROT	0x00010000
+#define			BCM43xx_DMA32_RXERR_OVERFLOW	0x00020000
+#define			BCM43xx_DMA32_RXERR_BUFWRITE	0x00030000
+#define			BCM43xx_DMA32_RXERR_DESCREAD	0x00040000
+#define		BCM43xx_DMA32_RXACTIVE			0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct bcm43xx_dmadesc32 {
+	__le32 control;
+	__le32 address;
+} __attribute__((__packed__));
+#define BCM43xx_DMA32_DCTL_BYTECNT		0x00001FFF
+#define BCM43xx_DMA32_DCTL_ADDREXT_MASK		0x00030000
+#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT	16
+#define BCM43xx_DMA32_DCTL_DTABLEEND		0x10000000
+#define BCM43xx_DMA32_DCTL_IRQ			0x20000000
+#define BCM43xx_DMA32_DCTL_FRAMEEND		0x40000000
+#define BCM43xx_DMA32_DCTL_FRAMESTART		0x80000000
+
+/* Address field Routing value. */
+#define BCM43xx_DMA32_ROUTING			0xC0000000
+#define BCM43xx_DMA32_ROUTING_SHIFT		30
+#define		BCM43xx_DMA32_NOTRANS		0x00000000
+#define		BCM43xx_DMA32_CLIENTTRANS	0x40000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define BCM43xx_DMA64_TXCTL				0x00
+#define		BCM43xx_DMA64_TXENABLE			0x00000001
+#define		BCM43xx_DMA64_TXSUSPEND			0x00000002
+#define		BCM43xx_DMA64_TXLOOPBACK		0x00000004
+#define		BCM43xx_DMA64_TXFLUSH			0x00000010
+#define		BCM43xx_DMA64_TXADDREXT_MASK		0x00030000
+#define		BCM43xx_DMA64_TXADDREXT_SHIFT		16
+#define BCM43xx_DMA64_TXINDEX				0x04
+#define BCM43xx_DMA64_TXRINGLO				0x08
+#define BCM43xx_DMA64_TXRINGHI				0x0C
+#define BCM43xx_DMA64_TXSTATUS				0x10
+#define		BCM43xx_DMA64_TXSTATDPTR		0x00001FFF
+#define		BCM43xx_DMA64_TXSTAT			0xF0000000
+#define			BCM43xx_DMA64_TXSTAT_DISABLED	0x00000000
+#define			BCM43xx_DMA64_TXSTAT_ACTIVE	0x10000000
+#define			BCM43xx_DMA64_TXSTAT_IDLEWAIT	0x20000000
+#define			BCM43xx_DMA64_TXSTAT_STOPPED	0x30000000
+#define			BCM43xx_DMA64_TXSTAT_SUSP	0x40000000
+#define BCM43xx_DMA64_TXERROR				0x14
+#define		BCM43xx_DMA64_TXERRDPTR			0x0001FFFF
+#define		BCM43xx_DMA64_TXERR			0xF0000000
+#define			BCM43xx_DMA64_TXERR_NOERR	0x00000000
+#define			BCM43xx_DMA64_TXERR_PROT	0x10000000
+#define			BCM43xx_DMA64_TXERR_UNDERRUN	0x20000000
+#define			BCM43xx_DMA64_TXERR_TRANSFER	0x30000000
+#define			BCM43xx_DMA64_TXERR_DESCREAD	0x40000000
+#define			BCM43xx_DMA64_TXERR_CORE	0x50000000
+#define BCM43xx_DMA64_RXCTL				0x20
+#define		BCM43xx_DMA64_RXENABLE			0x00000001
+#define		BCM43xx_DMA64_RXFROFF_MASK		0x000000FE
+#define		BCM43xx_DMA64_RXFROFF_SHIFT		1
+#define		BCM43xx_DMA64_RXDIRECTFIFO		0x00000100
+#define		BCM43xx_DMA64_RXADDREXT_MASK		0x00030000
+#define		BCM43xx_DMA64_RXADDREXT_SHIFT		16
+#define BCM43xx_DMA64_RXINDEX				0x24
+#define BCM43xx_DMA64_RXRINGLO				0x28
+#define BCM43xx_DMA64_RXRINGHI				0x2C
+#define BCM43xx_DMA64_RXSTATUS				0x30
+#define		BCM43xx_DMA64_RXSTATDPTR		0x00001FFF
+#define		BCM43xx_DMA64_RXSTAT			0xF0000000
+#define			BCM43xx_DMA64_RXSTAT_DISABLED	0x00000000
+#define			BCM43xx_DMA64_RXSTAT_ACTIVE	0x10000000
+#define			BCM43xx_DMA64_RXSTAT_IDLEWAIT	0x20000000
+#define			BCM43xx_DMA64_RXSTAT_STOPPED	0x30000000
+#define			BCM43xx_DMA64_RXSTAT_SUSP	0x40000000
+#define BCM43xx_DMA64_RXERROR				0x34
+#define		BCM43xx_DMA64_RXERRDPTR			0x0001FFFF
+#define		BCM43xx_DMA64_RXERR			0xF0000000
+#define			BCM43xx_DMA64_RXERR_NOERR	0x00000000
+#define			BCM43xx_DMA64_RXERR_PROT	0x10000000
+#define			BCM43xx_DMA64_RXERR_UNDERRUN	0x20000000
+#define			BCM43xx_DMA64_RXERR_TRANSFER	0x30000000
+#define			BCM43xx_DMA64_RXERR_DESCREAD	0x40000000
+#define			BCM43xx_DMA64_RXERR_CORE	0x50000000
+
+/* 64-bit DMA descriptor. */
+struct bcm43xx_dmadesc64 {
+	__le32 control0;
+	__le32 control1;
+	__le32 address_low;
+	__le32 address_high;
+} __attribute__((__packed__));
+#define BCM43xx_DMA64_DCTL0_DTABLEEND		0x10000000
+#define BCM43xx_DMA64_DCTL0_IRQ			0x20000000
+#define BCM43xx_DMA64_DCTL0_FRAMEEND		0x40000000
+#define BCM43xx_DMA64_DCTL0_FRAMESTART		0x80000000
+#define BCM43xx_DMA64_DCTL1_BYTECNT		0x00001FFF
+#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK	0x00030000
+#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT	16
+
+/* Address field Routing value. */
+#define BCM43xx_DMA64_ROUTING			0xC0000000
+#define BCM43xx_DMA64_ROUTING_SHIFT		30
+#define		BCM43xx_DMA64_NOTRANS		0x00000000
+#define		BCM43xx_DMA64_CLIENTTRANS	0x80000000
+
+
+
+struct bcm43xx_dmadesc_generic {
+	union {
+		struct bcm43xx_dmadesc32 dma32;
+		struct bcm43xx_dmadesc64 dma64;
+	} __attribute__((__packed__));
+} __attribute__((__packed__));
+
 
 /* Misc DMA constants */
 #define BCM43xx_DMA_RINGMEMSIZE		PAGE_SIZE
-#define BCM43xx_DMA_BUSADDRMAX		0x3FFFFFFF
-#define BCM43xx_DMA_DMABUSADDROFFSET	(1 << 30)
-#define BCM43xx_DMA1_RX_FRAMEOFFSET	30
-#define BCM43xx_DMA4_RX_FRAMEOFFSET	0
+#define BCM43xx_DMA0_RX_FRAMEOFFSET	30
+#define BCM43xx_DMA3_RX_FRAMEOFFSET	0
+
 
 /* DMA engine tuning knobs */
 #define BCM43xx_TXRING_SLOTS		512
 #define BCM43xx_RXRING_SLOTS		64
-#define BCM43xx_DMA1_RXBUFFERSIZE	(2304 + 100)
-#define BCM43xx_DMA4_RXBUFFERSIZE	16
+#define BCM43xx_DMA0_RX_BUFFERSIZE	(2304 + 100)
+#define BCM43xx_DMA3_RX_BUFFERSIZE	16
 /* Suspend the tx queue, if less than this percent slots are free. */
 #define BCM43xx_TXSUSPEND_PERCENT	20
 /* Resume the tx queue, if more than this percent slots are free. */
@@ -86,17 +202,6 @@
 struct bcm43xx_xmitstatus;
 
 
-struct bcm43xx_dmadesc {
-	__le32 _control;
-	__le32 _address;
-} __attribute__((__packed__));
-
-/* Macros to access the bcm43xx_dmadesc struct */
-#define get_desc_ctl(desc)		le32_to_cpu((desc)->_control)
-#define set_desc_ctl(desc, ctl)		do { (desc)->_control = cpu_to_le32(ctl); } while (0)
-#define get_desc_addr(desc)		le32_to_cpu((desc)->_address)
-#define set_desc_addr(desc, addr)	do { (desc)->_address = cpu_to_le32(addr); } while (0)
-
 struct bcm43xx_dmadesc_meta {
 	/* The kernel DMA-able buffer. */
 	struct sk_buff *skb;
@@ -105,15 +210,14 @@
 };
 
 struct bcm43xx_dmaring {
-	struct bcm43xx_private *bcm;
 	/* Kernel virtual base address of the ring memory. */
-	struct bcm43xx_dmadesc *vbase;
-	/* DMA memory offset */
-	dma_addr_t memoffset;
-	/* (Unadjusted) DMA base bus-address of the ring memory. */
-	dma_addr_t dmabase;
+	void *descbase;
 	/* Meta data about all descriptors. */
 	struct bcm43xx_dmadesc_meta *meta;
+	/* DMA Routing value. */
+	u32 routing;
+	/* (Unadjusted) DMA base bus-address of the ring memory. */
+	dma_addr_t dmabase;
 	/* Number of descriptor slots in the ring. */
 	int nr_slots;
 	/* Number of used descriptor slots. */
@@ -127,12 +231,14 @@
 	u32 frameoffset;
 	/* Descriptor buffer size. */
 	u16 rx_buffersize;
-	/* The MMIO base register of the DMA controller, this
-	 * ring is posted to.
-	 */
+	/* The MMIO base register of the DMA controller. */
 	u16 mmio_base;
+	/* DMA controller index number (0-5). */
+	int index;
 	u8 tx:1,	/* TRUE, if this is a TX ring. */
+	   dma64:1,	/* TRUE, if 64-bit DMA is enabled (FALSE if 32bit). */
 	   suspended:1;	/* TRUE, if transfers are suspended on this ring. */
+	struct bcm43xx_private *bcm;
 #ifdef CONFIG_BCM43XX_DEBUG
 	/* Maximum number of used slots. */
 	int max_used_slots;
@@ -141,6 +247,34 @@
 
 
 static inline
+int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
+			 struct bcm43xx_dmadesc_generic *desc)
+{
+	if (ring->dma64) {
+		struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+		return (int)(&(desc->dma64) - dd64);
+	} else {
+		struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+		return (int)(&(desc->dma32) - dd32);
+	}
+}
+
+static inline
+struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
+						      int slot,
+						      struct bcm43xx_dmadesc_meta **meta)
+{
+	*meta = &(ring->meta[slot]);
+	if (ring->dma64) {
+		struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+		return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
+	} else {
+		struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+		return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
+	}
+}
+
+static inline
 u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
 		     u16 offset)
 {
@@ -159,9 +293,13 @@
 void bcm43xx_dma_free(struct bcm43xx_private *bcm);
 
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-				   u16 dmacontroller_mmio_base);
+				   u16 dmacontroller_mmio_base,
+				   int dma64);
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-				   u16 dmacontroller_mmio_base);
+				   u16 dmacontroller_mmio_base,
+				   int dma64);
+
+u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
 
 void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
 void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
@@ -173,7 +311,6 @@
 		   struct ieee80211_txb *txb);
 void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
 
-
 #else /* CONFIG_BCM43XX_DMA */
 
 
@@ -188,13 +325,15 @@
 }
 static inline
 int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
-				   u16 dmacontroller_mmio_base)
+				   u16 dmacontroller_mmio_base,
+				   int dma64)
 {
 	return 0;
 }
 static inline
 int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
-				   u16 dmacontroller_mmio_base)
+				   u16 dmacontroller_mmio_base,
+				   int dma64)
 {
 	return 0;
 }
Index: wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-dev.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c	2006-06-17 17:48:26.000000000 +0200
+++ wireless-dev/drivers/net/wireless/bcm43xx/bcm43xx_main.c	2006-06-17 18:15:31.000000000 +0200
@@ -1376,6 +1376,7 @@
 	if ((bcm43xx_core_enabled(bcm)) &&
 	    !bcm43xx_using_pio(bcm)) {
 //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
+#if 0
 #ifndef CONFIG_BCM947XX
 		/* reset all used DMA controllers. */
 		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
@@ -1386,6 +1387,7 @@
 		if (bcm->current_core->rev < 5)
 			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
 #endif
+#endif
 	}
 	if (bcm->shutting_down) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -1696,8 +1698,9 @@
 static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
 {
 	u32 reason;
-	u32 dma_reason[4];
-	int activity = 0;
+	u32 dma_reason[6];
+	u32 merged_dma_reason = 0;
+	int i, activity = 0;
 	unsigned long flags;
 
 #ifdef CONFIG_BCM43XX_DEBUG
@@ -1709,10 +1712,10 @@
 
 	bcm43xx_lock_mmio(bcm, flags);
 	reason = bcm->irq_reason;
-	dma_reason[0] = bcm->dma_reason[0];
-	dma_reason[1] = bcm->dma_reason[1];
-	dma_reason[2] = bcm->dma_reason[2];
-	dma_reason[3] = bcm->dma_reason[3];
+	for (i = 5; i >= 0; i--) {
+		dma_reason[i] = bcm->dma_reason[i];
+		merged_dma_reason |= dma_reason[i];
+	}
 
 	if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
 		/* TX error. We get this when Template Ram is written in wrong endianess
@@ -1723,26 +1726,24 @@
 		printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
 		bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
 	}
-	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
-		     (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
-		     (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
-		     (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
+	if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
 		printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
-				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+				     "0x%08X, 0x%08X, 0x%08X, "
+				     "0x%08X, 0x%08X, 0x%08X\n",
 		        dma_reason[0], dma_reason[1],
-			dma_reason[2], dma_reason[3]);
+			dma_reason[2], dma_reason[3],
+			dma_reason[4], dma_reason[5]);
 		bcm43xx_controller_restart(bcm, "DMA error");
 		bcm43xx_unlock_mmio(bcm, flags);
 		return;
 	}
-	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
-		     (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
-		     (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
-		     (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
+	if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
 		printkl(KERN_ERR PFX "DMA error: "
-				     "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+				     "0x%08X, 0x%08X, 0x%08X, "
+				     "0x%08X, 0x%08X, 0x%08X\n",
 		        dma_reason[0], dma_reason[1],
-			dma_reason[2], dma_reason[3]);
+			dma_reason[2], dma_reason[3],
+			dma_reason[4], dma_reason[5]);
 	}
 
 	if (reason & BCM43xx_IRQ_PS) {
@@ -1777,8 +1778,6 @@
 	}
 
 	/* Check the DMA reason registers for received data. */
-	assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
-	assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
 	if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
@@ -1786,13 +1785,17 @@
 			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
 		/* We intentionally don't set "activity" to 1, here. */
 	}
+	assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+	assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
 	if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
 		else
-			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
+			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
 		activity = 1;
 	}
+	assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
+	assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
 	bcmirq_handled(BCM43xx_IRQ_RX);
 
 	if (reason & BCM43xx_IRQ_XMIT_STATUS) {
@@ -1848,14 +1851,18 @@
 
 	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
 
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
 			bcm->dma_reason[0]);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
 			bcm->dma_reason[1]);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
 			bcm->dma_reason[2]);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
 			bcm->dma_reason[3]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+			bcm->dma_reason[4]);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
+			bcm->dma_reason[5]);
 }
 
 /* Interrupt handler top-half */
@@ -1880,14 +1887,18 @@
 	if (!reason)
 		goto out;
 
-	bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
-			     & 0x0001dc00;
-	bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
-			     & 0x0000dc00;
-	bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
-			     & 0x0000dc00;
-	bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
-			     & 0x0001dc00;
+	bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
+			     & 0x0001DC00;
+	bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+			     & 0x0000DC00;
+	bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+			     & 0x0000DC00;
+	bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+			     & 0x0001DC00;
+	bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+			     & 0x0000DC00;
+	bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
+			     & 0x0000DC00;
 
 	bcm43xx_interrupt_ack(bcm, reason);
 
@@ -2462,10 +2473,12 @@
 		bcm43xx_write32(bcm, 0x018C, 0x02000000);
 	}
 	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
 	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
 
 	value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
 	value32 |= 0x00100000;


-- 
Greetings Michael.

^ permalink raw reply

* Re: updated [Patch 1/1] AF_UNIX Datagram getpeersec
From: James Morris @ 2006-06-17 15:55 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Catherine Zhang, netdev, davem, jmorris, chrisw, herbert, sds,
	tjaeger, akpm, latten, sergeh, gcwilson, czhang.us
In-Reply-To: <20060616211603.14547a1d@localhost.localdomain>

On Fri, 16 Jun 2006, Stephen Hemminger wrote:

> This is so short, it would make sense to put it in scm.h
> and why not have it return the value instead of call by reference?
> Same goes for selinux_get_inode_sid

Actually, all of the SELinux API functions are like this, and I'm not sure 
why for void return methods (it's a good idea when they return errnos).

Once this area has settled down (post 2.6.18), I'm planning to do some 
cleanups for this API anyway, and can fix these all at the same time.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply

* Re: updated [Patch 1/1] AF_UNIX Datagram getpeersec
From: James Morris @ 2006-06-17 15:46 UTC (permalink / raw)
  To: Xiaolan Zhang
  Cc: Stephen Hemminger, akpm, chrisw, Catherine Zhang, czhang.us,
	davem, George Wilson, herbert, jmorris, latten, netdev, sds,
	Serge E Hallyn, tjaeger
In-Reply-To: <OF42C27083.DD6A539B-ON85257190.00252DFB-85257190.0025456C@us.ibm.com>

On Sat, 17 Jun 2006, Xiaolan Zhang wrote:

> Hi, Stephen,
> 
> It appears that selinux_enabled is defined inside selinux module and not 
> visible to the rest of the kernel...

Yes, these are SELinux API functions, they belong in 
security/selinux/exports.c

But what about Stephens question on the return value?


> 
> thanks,
> Catherine
> 
> Stephen Hemminger <shemminger@osdl.org> wrote on 06/17/2006 12:16:03 AM:
> 
> > O
> > > 
> > > +void selinux_get_sock_sid(const struct socket *sock, u32 *sid)
> > > +{
> > > +   if (selinux_enabled) {
> > > +      const struct inode *inode = SOCK_INODE(sock);
> > > +      selinux_get_inode_sid(inode, sid);
> > > +      return;
> > > +   }
> > > +   *sid = 0;
> > > +}
> > > +
> > 
> > This is so short, it would make sense to put it in scm.h
> > and why not have it return the value instead of call by reference?
> > Same goes for selinux_get_inode_sid
> > 
> > static inline void selinux_get_sock_sid(const struct socket *sock, u32 
> *sid)
> > {
> >    if (selinux_enabled)
> >       selinux_get_inode_sid(SOCK_INODE(sock), sid);
> >    else
> >       *sid = 0;
> > }
> > 
> > or
> > static inline u32 selinux_get_sock_sid(const struct socket *sock)
> > {
> >    return selinux_enabled ? selinux_get_inode_sid(SOCK_INODE(sid)) : 0;
> > }
> 
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
James Morris
<jmorris@namei.org>

^ 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