aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/svc4proc.c12
-rw-r--r--fs/lockd/svcproc.c16
-rw-r--r--fs/lockd/svcsubs.c6
-rw-r--r--fs/nfsd/lockd.c14
-rw-r--r--include/linux/lockd/bind.h5
-rw-r--r--include/linux/lockd/xdr.h4
-rw-r--r--include/linux/sunrpc/msg_prot.h4
-rw-r--r--include/linux/sunrpc/xdr.h1
-rw-r--r--net/sunrpc/svc.c5
9 files changed, 41 insertions, 26 deletions
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index fa370f6eb07b..399ad11b97be 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -96,7 +96,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
96 96
97 /* Obtain client and file */ 97 /* Obtain client and file */
98 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 98 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
99 return rpc_success; 99 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
100 100
101 /* Now check for conflicting locks */ 101 /* Now check for conflicting locks */
102 resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); 102 resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
@@ -126,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
126 126
127 /* Obtain client and file */ 127 /* Obtain client and file */
128 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 128 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
129 return rpc_success; 129 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
130 130
131#if 0 131#if 0
132 /* If supplied state doesn't match current state, we assume it's 132 /* If supplied state doesn't match current state, we assume it's
@@ -169,7 +169,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
169 169
170 /* Obtain client and file */ 170 /* Obtain client and file */
171 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 171 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
172 return rpc_success; 172 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
173 173
174 /* Try to cancel request. */ 174 /* Try to cancel request. */
175 resp->status = nlmsvc_cancel_blocked(file, &argp->lock); 175 resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
@@ -202,7 +202,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
202 202
203 /* Obtain client and file */ 203 /* Obtain client and file */
204 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 204 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
205 return rpc_success; 205 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
206 206
207 /* Now try to remove the lock */ 207 /* Now try to remove the lock */
208 resp->status = nlmsvc_unlock(file, &argp->lock); 208 resp->status = nlmsvc_unlock(file, &argp->lock);
@@ -339,7 +339,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
339 339
340 /* Obtain client and file */ 340 /* Obtain client and file */
341 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 341 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
342 return rpc_success; 342 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
343 343
344 /* Now try to create the share */ 344 /* Now try to create the share */
345 resp->status = nlmsvc_share_file(host, file, argp); 345 resp->status = nlmsvc_share_file(host, file, argp);
@@ -372,7 +372,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
372 372
373 /* Obtain client and file */ 373 /* Obtain client and file */
374 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 374 if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
375 return rpc_success; 375 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
376 376
377 /* Now try to lock the file */ 377 /* Now try to lock the file */
378 resp->status = nlmsvc_unshare_file(host, file, argp); 378 resp->status = nlmsvc_unshare_file(host, file, argp);
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 75b2c81bcb93..6a931f4ab75c 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -59,7 +59,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
59 struct nlm_host *host = NULL; 59 struct nlm_host *host = NULL;
60 struct nlm_file *file = NULL; 60 struct nlm_file *file = NULL;
61 struct nlm_lock *lock = &argp->lock; 61 struct nlm_lock *lock = &argp->lock;
62 u32 error; 62 u32 error = 0;
63 63
64 /* nfsd callbacks must have been installed for this procedure */ 64 /* nfsd callbacks must have been installed for this procedure */
65 if (!nlmsvc_ops) 65 if (!nlmsvc_ops)
@@ -88,6 +88,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
88no_locks: 88no_locks:
89 if (host) 89 if (host)
90 nlm_release_host(host); 90 nlm_release_host(host);
91 if (error)
92 return error;
91 return nlm_lck_denied_nolocks; 93 return nlm_lck_denied_nolocks;
92} 94}
93 95
@@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
122 124
123 /* Obtain client and file */ 125 /* Obtain client and file */
124 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 126 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
125 return rpc_success; 127 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
126 128
127 /* Now check for conflicting locks */ 129 /* Now check for conflicting locks */
128 resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); 130 resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
@@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
153 155
154 /* Obtain client and file */ 156 /* Obtain client and file */
155 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 157 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
156 return rpc_success; 158 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
157 159
158#if 0 160#if 0
159 /* If supplied state doesn't match current state, we assume it's 161 /* If supplied state doesn't match current state, we assume it's
@@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
196 198
197 /* Obtain client and file */ 199 /* Obtain client and file */
198 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 200 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
199 return rpc_success; 201 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
200 202
201 /* Try to cancel request. */ 203 /* Try to cancel request. */
202 resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); 204 resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
@@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
229 231
230 /* Obtain client and file */ 232 /* Obtain client and file */
231 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 233 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
232 return rpc_success; 234 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
233 235
234 /* Now try to remove the lock */ 236 /* Now try to remove the lock */
235 resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); 237 resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
@@ -368,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
368 370
369 /* Obtain client and file */ 371 /* Obtain client and file */
370 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 372 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
371 return rpc_success; 373 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
372 374
373 /* Now try to create the share */ 375 /* Now try to create the share */
374 resp->status = cast_status(nlmsvc_share_file(host, file, argp)); 376 resp->status = cast_status(nlmsvc_share_file(host, file, argp));
@@ -401,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
401 403
402 /* Obtain client and file */ 404 /* Obtain client and file */
403 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 405 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
404 return rpc_success; 406 return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
405 407
406 /* Now try to unshare the file */ 408 /* Now try to unshare the file */
407 resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); 409 resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c5f9113cdc70..7dac96e6c82c 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -135,12 +135,6 @@ out_unlock:
135 135
136out_free: 136out_free:
137 kfree(file); 137 kfree(file);
138#ifdef CONFIG_LOCKD_V4
139 if (nfserr == 1)
140 nfserr = nlm4_stale_fh;
141 else
142#endif
143 nfserr = nlm_lck_denied;
144 goto out_unlock; 138 goto out_unlock;
145} 139}
146 140
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 7b889ff15ae6..9b9e7e127c03 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
39 fh_put(&fh); 39 fh_put(&fh);
40 rqstp->rq_client = NULL; 40 rqstp->rq_client = NULL;
41 exp_readunlock(); 41 exp_readunlock();
42 /* nlm and nfsd don't share error codes. 42 /* We return nlm error codes as nlm doesn't know
43 * we invent: 0 = no error 43 * about nfsd, but nfsd does know about nlm..
44 * 1 = stale file handle
45 * 2 = other error
46 */ 44 */
47 switch (nfserr) { 45 switch (nfserr) {
48 case nfs_ok: 46 case nfs_ok:
49 return 0; 47 return 0;
48 case nfserr_dropit:
49 return nlm_drop_reply;
50#ifdef CONFIG_LOCKD_V4
50 case nfserr_stale: 51 case nfserr_stale:
51 return 1; 52 return nlm4_stale_fh;
53#endif
52 default: 54 default:
53 return 2; 55 return nlm_lck_denied;
54 } 56 }
55} 57}
56 58
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 81e3a185f951..aa50d89eacd7 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -10,6 +10,11 @@
10#define LINUX_LOCKD_BIND_H 10#define LINUX_LOCKD_BIND_H
11 11
12#include <linux/lockd/nlm.h> 12#include <linux/lockd/nlm.h>
13/* need xdr-encoded error codes too, so... */
14#include <linux/lockd/xdr.h>
15#ifdef CONFIG_LOCKD_V4
16#include <linux/lockd/xdr4.h>
17#endif
13 18
14/* Dummy declarations */ 19/* Dummy declarations */
15struct svc_rqst; 20struct svc_rqst;
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index bb0a0f1caa91..66fdae3b490c 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -13,6 +13,8 @@
13#include <linux/nfs.h> 13#include <linux/nfs.h>
14#include <linux/sunrpc/xdr.h> 14#include <linux/sunrpc/xdr.h>
15 15
16struct svc_rqst;
17
16#define NLM_MAXCOOKIELEN 32 18#define NLM_MAXCOOKIELEN 32
17#define NLM_MAXSTRLEN 1024 19#define NLM_MAXSTRLEN 1024
18 20
@@ -22,6 +24,8 @@
22#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED) 24#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
23#define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD) 25#define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
24 26
27#define nlm_drop_reply __constant_htonl(30000)
28
25/* Lock info passed via NLM */ 29/* Lock info passed via NLM */
26struct nlm_lock { 30struct nlm_lock {
27 char * caller; 31 char * caller;
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 1e65f2dd80e5..606cb2165232 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -56,7 +56,9 @@ enum rpc_accept_stat {
56 RPC_PROG_MISMATCH = 2, 56 RPC_PROG_MISMATCH = 2,
57 RPC_PROC_UNAVAIL = 3, 57 RPC_PROC_UNAVAIL = 3,
58 RPC_GARBAGE_ARGS = 4, 58 RPC_GARBAGE_ARGS = 4,
59 RPC_SYSTEM_ERR = 5 59 RPC_SYSTEM_ERR = 5,
60 /* internal use only */
61 RPC_DROP_REPLY = 60000,
60}; 62};
61 63
62enum rpc_reject_stat { 64enum rpc_reject_stat {
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 953723b09bc6..ac69e5511606 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -74,6 +74,7 @@ struct xdr_buf {
74#define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL) 74#define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL)
75#define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS) 75#define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS)
76#define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR) 76#define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR)
77#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY)
77 78
78#define rpc_auth_ok __constant_htonl(RPC_AUTH_OK) 79#define rpc_auth_ok __constant_htonl(RPC_AUTH_OK)
79#define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED) 80#define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 2807fa0eab40..eb44ec929ca1 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -828,6 +828,11 @@ svc_process(struct svc_rqst *rqstp)
828 *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 828 *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
829 829
830 /* Encode reply */ 830 /* Encode reply */
831 if (*statp == rpc_drop_reply) {
832 if (procp->pc_release)
833 procp->pc_release(rqstp, NULL, rqstp->rq_resp);
834 goto dropit;
835 }
831 if (*statp == rpc_success && (xdr = procp->pc_encode) 836 if (*statp == rpc_success && (xdr = procp->pc_encode)
832 && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { 837 && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
833 dprintk("svc: failed to encode reply\n"); 838 dprintk("svc: failed to encode reply\n");
om">/* transmit buffer unavilable */ TI = 0x00000008, /* transmit interrupt */ RI = 0x00000004, /* receive interrupt */ RxErr = 0x00000002, /* receive error */ }; /* Bits in the NetworkConfig register, W for writing, R for reading */ /* FIXME: some names are invented by me. Marked with (name?) */ /* If you have docs and know bit names, please fix 'em */ enum rx_mode_bits { CR_W_ENH = 0x02000000, /* enhanced mode (name?) */ CR_W_FD = 0x00100000, /* full duplex */ CR_W_PS10 = 0x00080000, /* 10 mbit */ CR_W_TXEN = 0x00040000, /* tx enable (name?) */ CR_W_PS1000 = 0x00010000, /* 1000 mbit */ /* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */ CR_W_RXMODEMASK = 0x000000e0, CR_W_PROM = 0x00000080, /* promiscuous mode */ CR_W_AB = 0x00000040, /* accept broadcast */ CR_W_AM = 0x00000020, /* accept mutlicast */ CR_W_ARP = 0x00000008, /* receive runt pkt */ CR_W_ALP = 0x00000004, /* receive long pkt */ CR_W_SEP = 0x00000002, /* receive error pkt */ CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */ CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */ CR_R_FD = 0x00100000, /* full duplex detected */ CR_R_PS10 = 0x00080000, /* 10 mbit detected */ CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */ }; /* The Tulip Rx and Tx buffer descriptors. */ struct fealnx_desc { s32 status; s32 control; u32 buffer; u32 next_desc; struct fealnx_desc *next_desc_logical; struct sk_buff *skbuff; u32 reserved1; u32 reserved2; }; /* Bits in network_desc.status */ enum rx_desc_status_bits { RXOWN = 0x80000000, /* own bit */ FLNGMASK = 0x0fff0000, /* frame length */ FLNGShift = 16, MARSTATUS = 0x00004000, /* multicast address received */ BARSTATUS = 0x00002000, /* broadcast address received */ PHYSTATUS = 0x00001000, /* physical address received */ RXFSD = 0x00000800, /* first descriptor */ RXLSD = 0x00000400, /* last descriptor */ ErrorSummary = 0x80, /* error summary */ RUNT = 0x40, /* runt packet received */ LONG = 0x20, /* long packet received */ FAE = 0x10, /* frame align error */ CRC = 0x08, /* crc error */ RXER = 0x04, /* receive error */ }; enum rx_desc_control_bits { RXIC = 0x00800000, /* interrupt control */ RBSShift = 0, }; enum tx_desc_status_bits { TXOWN = 0x80000000, /* own bit */ JABTO = 0x00004000, /* jabber timeout */ CSL = 0x00002000, /* carrier sense lost */ LC = 0x00001000, /* late collision */ EC = 0x00000800, /* excessive collision */ UDF = 0x00000400, /* fifo underflow */ DFR = 0x00000200, /* deferred */ HF = 0x00000100, /* heartbeat fail */ NCRMask = 0x000000ff, /* collision retry count */ NCRShift = 0, }; enum tx_desc_control_bits { TXIC = 0x80000000, /* interrupt control */ ETIControl = 0x40000000, /* early transmit interrupt */ TXLD = 0x20000000, /* last descriptor */ TXFD = 0x10000000, /* first descriptor */ CRCEnable = 0x08000000, /* crc control */ PADEnable = 0x04000000, /* padding control */ RetryTxLC = 0x02000000, /* retry late collision */ PKTSMask = 0x3ff800, /* packet size bit21-11 */ PKTSShift = 11, TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ TBSShift = 0, }; /* BootROM/EEPROM/MII Management Register */ #define MASK_MIIR_MII_READ 0x00000000 #define MASK_MIIR_MII_WRITE 0x00000008 #define MASK_MIIR_MII_MDO 0x00000004 #define MASK_MIIR_MII_MDI 0x00000002 #define MASK_MIIR_MII_MDC 0x00000001 /* ST+OP+PHYAD+REGAD+TA */ #define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ #define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ /* ------------------------------------------------------------------------- */ /* Constants for Myson PHY */ /* ------------------------------------------------------------------------- */ #define MysonPHYID 0xd0000302 /* 89-7-27 add, (begin) */ #define MysonPHYID0 0x0302 #define StatusRegister 18 #define SPEED100 0x0400 // bit10 #define FULLMODE 0x0800 // bit11 /* 89-7-27 add, (end) */ /* ------------------------------------------------------------------------- */ /* Constants for Seeq 80225 PHY */ /* ------------------------------------------------------------------------- */ #define SeeqPHYID0 0x0016 #define MIIRegister18 18 #define SPD_DET_100 0x80 #define DPLX_DET_FULL 0x40 /* ------------------------------------------------------------------------- */ /* Constants for Ahdoc 101 PHY */ /* ------------------------------------------------------------------------- */ #define AhdocPHYID0 0x0022 #define DiagnosticReg 18 #define DPLX_FULL 0x0800 #define Speed_100 0x0400 /* 89/6/13 add, */ /* -------------------------------------------------------------------------- */ /* Constants */ /* -------------------------------------------------------------------------- */ #define MarvellPHYID0 0x0141 #define LevelOnePHYID0 0x0013 #define MII1000BaseTControlReg 9 #define MII1000BaseTStatusReg 10 #define SpecificReg 17 /* for 1000BaseT Control Register */ #define PHYAbletoPerform1000FullDuplex 0x0200 #define PHYAbletoPerform1000HalfDuplex 0x0100 #define PHY1000AbilityMask 0x300 // for phy specific status register, marvell phy. #define SpeedMask 0x0c000 #define Speed_1000M 0x08000 #define Speed_100M 0x4000 #define Speed_10M 0 #define Full_Duplex 0x2000 // 89/12/29 add, for phy specific status register, levelone phy, (begin) #define LXT1000_100M 0x08000 #define LXT1000_1000M 0x0c000 #define LXT1000_Full 0x200 // 89/12/29 add, for phy specific status register, levelone phy, (end) /* for 3-in-1 case, BMCRSR register */ #define LinkIsUp2 0x00040000 /* for PHY */ #define LinkIsUp 0x0004 struct netdev_private { /* Descriptor rings first for alignment. */ struct fealnx_desc *rx_ring; struct fealnx_desc *tx_ring; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; spinlock_t lock; struct net_device_stats stats; /* Media monitoring timer. */ struct timer_list timer; /* Reset timer */ struct timer_list reset_timer; int reset_timer_armed; unsigned long crvalue_sv; unsigned long imrvalue_sv; /* Frequently used values: keep some adjacent for cache effect. */ int flags; struct pci_dev *pci_dev; unsigned long crvalue; unsigned long bcrvalue; unsigned long imrvalue; struct fealnx_desc *cur_rx; struct fealnx_desc *lack_rxbuf; int really_rx_count; struct fealnx_desc *cur_tx; struct fealnx_desc *cur_tx_copy; int really_tx_count; int free_tx_count; unsigned int rx_buf_sz; /* Based on MTU+slack. */ /* These values are keep track of the transceiver/media in use. */ unsigned int linkok; unsigned int line_speed; unsigned int duplexmode; unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int PHYType; /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ unsigned char phys[2]; /* MII device addresses. */ struct mii_if_info mii; void __iomem *mem; }; static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static void getlinktype(struct net_device *dev); static void getlinkstatus(struct net_device *dev); static void netdev_timer(unsigned long data); static void reset_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static int netdev_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void __set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; static int netdev_close(struct net_device *dev); static void reset_rx_descriptors(struct net_device *dev); static void reset_tx_descriptors(struct net_device *dev); static void stop_nic_rx(void __iomem *ioaddr, long crvalue) { int delay = 0x1000; iowrite32(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR); while (--delay) { if ( (ioread32(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP) break; } } static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue) { int delay = 0x1000; iowrite32(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR); while (--delay) { if ( (ioread32(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP)) == (CR_R_RXSTOP+CR_R_TXSTOP) ) break; } } static int __devinit fealnx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct netdev_private *np; int i, option, err, irq; static int card_idx = -1; char boardname[12]; void __iomem *ioaddr; unsigned long len; unsigned int chip_id = ent->driver_data; struct net_device *dev; void *ring_space; dma_addr_t ring_dma; #ifdef USE_IO_OPS int bar = 0; #else int bar = 1; #endif /* when built into the kernel, we only print version if device is found */ #ifndef MODULE static int printed_version; if (!printed_version++) printk(version); #endif card_idx++; sprintf(boardname, "fealnx%d", card_idx); option = card_idx < MAX_UNITS ? options[card_idx] : 0; i = pci_enable_device(pdev); if (i) return i; pci_set_master(pdev); len = pci_resource_len(pdev, bar); if (len < MIN_REGION_SIZE) { dev_err(&pdev->dev, "region size %ld too small, aborting\n", len); return -ENODEV; } i = pci_request_regions(pdev, boardname); if (i) return i; irq = pdev->irq; ioaddr = pci_iomap(pdev, bar, len); if (!ioaddr) { err = -ENOMEM; goto err_out_res; } dev = alloc_etherdev(sizeof(struct netdev_private)); if (!dev) { err = -ENOMEM; goto err_out_unmap; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* read ethernet id */ for (i = 0; i < 6; ++i) dev->dev_addr[i] = ioread8(ioaddr + PAR0 + i); /* Reset the chip to erase previous misconfiguration. */ iowrite32(0x00000001, ioaddr + BCR); dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; /* Make certain the descriptor lists are aligned. */ np = netdev_priv(dev); np->mem = ioaddr; spin_lock_init(&np->lock); np->pci_dev = pdev; np->flags = skel_netdrv_tbl[chip_id].flags; pci_set_drvdata(pdev, dev); np->mii.dev = dev; np->mii.mdio_read = mdio_read; np->mii.mdio_write = mdio_write; np->mii.phy_id_mask = 0x1f; np->mii.reg_num_mask = 0x1f; ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); if (!ring_space) { err = -ENOMEM; goto err_out_free_dev; } np->rx_ring = (struct fealnx_desc *)ring_space; np->rx_ring_dma = ring_dma; ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) { err = -ENOMEM; goto err_out_free_rx; } np->tx_ring = (struct fealnx_desc *)ring_space; np->tx_ring_dma = ring_dma; /* find the connected MII xcvrs */ if (np->flags == HAS_MII_XCVR) { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; dev_info(&pdev->dev, "MII PHY found at address %d, status " "0x%4.4x.\n", phy, mii_status); /* get phy type */ { unsigned int data; data = mdio_read(dev, np->phys[0], 2); if (data == SeeqPHYID0) np->PHYType = SeeqPHY; else if (data == AhdocPHYID0) np->PHYType = AhdocPHY; else if (data == MarvellPHYID0) np->PHYType = MarvellPHY; else if (data == MysonPHYID0) np->PHYType = Myson981; else if (data == LevelOnePHYID0) np->PHYType = LevelOnePHY; else np->PHYType = OtherPHY; } } } np->mii_cnt = phy_idx; if (phy_idx == 0) dev_warn(&pdev->dev, "MII PHY not found -- this device may " "not operate correctly.\n"); } else { np->phys[0] = 32; /* 89/6/23 add, (begin) */ /* get phy type */ if (ioread32(ioaddr + PHYIDENTIFIER) == MysonPHYID) np->PHYType = MysonPHY; else np->PHYType = OtherPHY; } np->mii.phy_id = np->phys[0]; if (dev->mem_start) option = dev->mem_start; /* The lower four bits are the media type. */ if (option > 0) { if (option & 0x200) np->mii.full_duplex = 1; np->default_port = option & 15; } if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) np->mii.full_duplex = full_duplex[card_idx]; if (np->mii.full_duplex) { dev_info(&pdev->dev, "Media type forced to Full Duplex.\n"); /* 89/6/13 add, (begin) */ // if (np->PHYType==MarvellPHY) if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) { unsigned int data; data = mdio_read(dev, np->phys[0], 9); data = (data & 0xfcff) | 0x0200; mdio_write(dev, np->phys[0], 9, data); } /* 89/6/13 add, (end) */ if (np->flags == HAS_MII_XCVR) mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); else iowrite32(ADVERTISE_FULL, ioaddr + ANARANLPAR); np->mii.force_media = 1; } /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; err = register_netdev(dev); if (err) goto err_out_free_tx; printk(KERN_INFO "%s: %s at %p, ", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); return 0; err_out_free_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); err_out_free_rx: pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); err_out_free_dev: free_netdev(dev); err_out_unmap: pci_iounmap(pdev, ioaddr); err_out_res: pci_release_regions(pdev); return err; } static void __devexit fealnx_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); if (dev) { struct netdev_private *np = netdev_priv(dev); pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); unregister_netdev(dev); pci_iounmap(pdev, np->mem); free_netdev(dev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } else printk(KERN_ERR "fealnx: remove for unknown device\n"); } static ulong m80x_send_cmd_to_phy(void __iomem *miiport, int opcode, int phyad, int regad) { ulong miir; int i; unsigned int mask, data; /* enable MII output */ miir = (ulong) ioread32(miiport); miir &= 0xfffffff0; miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; /* send 32 1's preamble */ for (i = 0; i < 32; i++) { /* low MDC; MDO is already high (miir) */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); } /* calculate ST+OP+PHYAD+REGAD+TA */ data = opcode | (phyad << 7) | (regad << 2); /* sent out */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); if (mask & data) miir |= MASK_MIIR_MII_MDO; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); udelay(30); /* next */ mask >>= 1; if (mask == 0x2 && opcode == OP_READ) miir &= ~MASK_MIIR_MII_WRITE; } return miir; } static int mdio_read(struct net_device *dev, int phyad, int regad) { struct netdev_private *np = netdev_priv(dev); void __iomem *miiport = np->mem + MANAGEMENT; ulong miir; unsigned int mask, data; miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); /* read data */ mask = 0x8000; data = 0; while (mask) { /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport); /* read MDI */ miir = ioread32(miiport); if (miir & MASK_MIIR_MII_MDI) data |= mask; /* high MDC, and wait */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); udelay(30); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport); return data & 0xffff; } static void mdio_write(struct net_device *dev, int phyad, int regad, int data) { struct netdev_private *np = netdev_priv(dev); void __iomem *miiport = np->mem + MANAGEMENT; ulong miir; unsigned int mask; miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); /* write data */ mask = 0x8000; while (mask) { /* low MDC, prepare MDO */ miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); if (mask & data) miir |= MASK_MIIR_MII_MDO; iowrite32(miir, miiport); /* high MDC */ miir |= MASK_MIIR_MII_MDC; iowrite32(miir, miiport); /* next */ mask >>= 1; } /* low MDC */ miir &= ~MASK_MIIR_MII_MDC; iowrite32(miir, miiport); } static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->mem; int i; iowrite32(0x00000001, ioaddr + BCR); /* Reset */ if (request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev)) return -EAGAIN; for (i = 0; i < 3; i++) iowrite16(((unsigned short*)dev->dev_addr)[i], ioaddr + PAR0 + i*2); init_ring(dev); iowrite32(np->rx_ring_dma, ioaddr + RXLBA); iowrite32(np->tx_ring_dma, ioaddr + TXLBA); /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. 486: Set 8 longword burst. 586: no burst limit. Burst length 5:3 0 0 0 1 0 0 1 4 0 1 0 8 0 1 1 16 1 0 0 32 1 0 1 64 1 1 0 128 1 1 1 256 Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. FIXME (Ueimor): optimistic for alpha + posted writes ? */ #if defined(__powerpc__) || defined(__sparc__) // 89/9/1 modify,