diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-20 17:43:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-20 17:43:29 -0700 |
commit | db6d8c7a4027b48d797b369a53f8470aaeed7063 (patch) | |
tree | e140c104a89abc2154e1f41a7db8ebecbb6fa0b4 /drivers/atm/suni.c | |
parent | 3a533374283aea50eab3976d8a6d30532175f009 (diff) | |
parent | fb65a7c091529bfffb1262515252c0d0f6241c5c (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (1232 commits)
iucv: Fix bad merging.
net_sched: Add size table for qdiscs
net_sched: Add accessor function for packet length for qdiscs
net_sched: Add qdisc_enqueue wrapper
highmem: Export totalhigh_pages.
ipv6 mcast: Omit redundant address family checks in ip6_mc_source().
net: Use standard structures for generic socket address structures.
ipv6 netns: Make several "global" sysctl variables namespace aware.
netns: Use net_eq() to compare net-namespaces for optimization.
ipv6: remove unused macros from net/ipv6.h
ipv6: remove unused parameter from ip6_ra_control
tcp: fix kernel panic with listening_get_next
tcp: Remove redundant checks when setting eff_sacks
tcp: options clean up
tcp: Fix MD5 signatures for non-linear skbs
sctp: Update sctp global memory limit allocations.
sctp: remove unnecessary byteshifting, calculate directly in big-endian
sctp: Allow only 1 listening socket with SO_REUSEADDR
sctp: Do not leak memory on multiple listen() calls
sctp: Support ipv6only AF_INET6 sockets.
...
Diffstat (limited to 'drivers/atm/suni.c')
-rw-r--r-- | drivers/atm/suni.c | 130 |
1 files changed, 105 insertions, 25 deletions
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index b1d063cc4fb..6dd3f591996 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -1,8 +1,14 @@ -/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */ +/* + * drivers/atm/suni.c - S/UNI PHY driver + * + * Supports the following: + * PMC PM5346 S/UNI LITE + * PMC PM5350 S/UNI 155 ULTRA + * PMC PM5355 S/UNI 622 + */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - #include <linux/module.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -29,15 +35,6 @@ #define DPRINTK(format,args...) #endif - -struct suni_priv { - struct k_sonet_stats sonet_stats; /* link diagnostics */ - int loop_mode; /* loopback mode */ - struct atm_dev *dev; /* device back-pointer */ - struct suni_priv *next; /* next SUNI */ -}; - - #define PRIV(dev) ((struct suni_priv *) dev->phy_data) #define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg) @@ -155,25 +152,105 @@ static int get_diag(struct atm_dev *dev,void __user *arg) static int set_loopback(struct atm_dev *dev,int mode) { unsigned char control; + int reg, dle, lle; + + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + reg = SUNI_MCM; + dle = SUNI_MCM_DLE; + lle = SUNI_MCM_LLE; + } else { + reg = SUNI_MCT; + dle = SUNI_MCT_DLE; + lle = SUNI_MCT_LLE; + } - control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE); + control = dev->ops->phy_get(dev, reg) & ~(dle | lle); switch (mode) { case ATM_LM_NONE: break; case ATM_LM_LOC_PHY: - control |= SUNI_MCT_DLE; + control |= dle; break; case ATM_LM_RMT_PHY: - control |= SUNI_MCT_LLE; + control |= lle; break; default: return -EINVAL; } - PUT(control,MCT); + dev->ops->phy_put(dev, control, reg); PRIV(dev)->loop_mode = mode; return 0; } +/* + * SONET vs. SDH Configuration + * + * Z0INS (register 0x06): 0 for SONET, 1 for SDH + * ENSS (register 0x3D): 0 for SONET, 1 for SDH + * LEN16 (register 0x28): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) + * LEN16 (register 0x50): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) + * S[1:0] (register 0x46): 00 for SONET, 10 for SDH + */ + +static int set_sonet(struct atm_dev *dev) +{ + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + PUT(GET(RPOP_RC) & ~SUNI_RPOP_RC_ENSS, RPOP_RC); + PUT(GET(SSTB_CTRL) & ~SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); + PUT(GET(SPTB_CTRL) & ~SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); + } + + REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, + SUNI_TPOP_S_SONET, TPOP_APM); + + return 0; +} + +static int set_sdh(struct atm_dev *dev) +{ + if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { + PUT(GET(RPOP_RC) | SUNI_RPOP_RC_ENSS, RPOP_RC); + PUT(GET(SSTB_CTRL) | SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); + PUT(GET(SPTB_CTRL) | SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); + } + + REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, + SUNI_TPOP_S_SDH, TPOP_APM); + + return 0; +} + + +static int get_framing(struct atm_dev *dev, void __user *arg) +{ + int framing; + unsigned char s; + + + s = (GET(TPOP_APM) & SUNI_TPOP_APM_S) >> SUNI_TPOP_APM_S_SHIFT; + if (s == SUNI_TPOP_S_SONET) + framing = SONET_FRAME_SONET; + else + framing = SONET_FRAME_SDH; + + return put_user(framing, (int __user *) arg) ? -EFAULT : 0; +} + +static int set_framing(struct atm_dev *dev, void __user *arg) +{ + int mode; + + if (get_user(mode, (int __user *) arg)) + return -EFAULT; + + if (mode == SONET_FRAME_SONET) + return set_sonet(dev); + else if (mode == SONET_FRAME_SDH) + return set_sdh(dev); + + return -EINVAL; +} + static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) { @@ -188,14 +265,16 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) case SONET_GETDIAG: return get_diag(dev,arg); case SONET_SETFRAMING: - if ((int)(unsigned long)arg != SONET_FRAME_SONET) return -EINVAL; - return 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return set_framing(dev, arg); case SONET_GETFRAMING: - return put_user(SONET_FRAME_SONET,(int __user *)arg) ? - -EFAULT : 0; + return get_framing(dev, arg); case SONET_GETFRSENSE: return -EINVAL; case ATM_SETLOOP: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; return set_loopback(dev,(int)(unsigned long)arg); case ATM_GETLOOP: return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? @@ -229,10 +308,6 @@ static int suni_start(struct atm_dev *dev) unsigned long flags; int first; - if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) - return -ENOMEM; - - PRIV(dev)->dev = dev; spin_lock_irqsave(&sunis_lock,flags); first = !sunis; PRIV(dev)->next = sunis; @@ -293,16 +368,21 @@ int suni_init(struct atm_dev *dev) { unsigned char mri; + if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL))) + return -ENOMEM; + PRIV(dev)->dev = dev; + mri = GET(MRI); /* reset SUNI */ + PRIV(dev)->type = (mri & SUNI_MRI_TYPE) >> SUNI_MRI_TYPE_SHIFT; PUT(mri | SUNI_MRI_RESET,MRI); PUT(mri,MRI); PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */ - REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET, - TPOP_APM); /* use SONET */ + set_sonet(dev); REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP, TACP_IUCHP); /* idle cells */ PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP); dev->phy = &suni_ops; + return 0; } |