Import 2.3.18pre1
[davej-history.git] / drivers / atm / suni.c
blob43904624fd839e9e97e4dc663e8bbad16256dc51
1 /* drivers/atm/suni.c - PMC SUNI (PHY) driver */
3 /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/module.h>
7 #include <linux/sched.h>
8 #include <linux/kernel.h>
9 #include <linux/mm.h>
10 #include <linux/errno.h>
11 #include <linux/atmdev.h>
12 #include <linux/sonet.h>
13 #include <linux/delay.h>
14 #include <linux/timer.h>
15 #include <linux/init.h>
16 #include <linux/capability.h>
17 #include <linux/atm_suni.h>
18 #include <asm/system.h>
19 #include <asm/param.h>
20 #include <asm/uaccess.h>
22 #include"suni.h"
25 #if 0
26 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
27 #else
28 #define DPRINTK(format,args...)
29 #endif
32 struct suni_priv {
33 struct sonet_stats sonet_stats;/* link diagnostics */
34 unsigned char loop_mode;/* loopback mode */
35 struct atm_dev *dev;/* device back-pointer */
36 struct suni_priv *next;/* next SUNI */
40 #define PRIV(dev) ((struct suni_priv *) dev->phy_data)
42 #define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg)
43 #define GET(reg) dev->ops->phy_get(dev,SUNI_##reg)
44 #define REG_CHANGE(mask,shift,value,reg) \
45 PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg)
48 static struct timer_list poll_timer;
49 static int start_timer =1;
50 static struct suni_priv *sunis = NULL;
53 static voidsuni_hz(unsigned long dummy)
55 struct suni_priv *walk;
56 struct atm_dev *dev;
57 struct sonet_stats *stats;
59 for(walk = sunis; walk; walk = walk->next) {
60 dev = walk->dev;
61 stats = &walk->sonet_stats;
62 PUT(0,MRI);/* latch counters */
63 udelay(1);
64 stats->section_bip += (GET(RSOP_SBL) &0xff) |
65 ((GET(RSOP_SBM) &0xff) <<8);
66 if(stats->section_bip <0) stats->section_bip = LONG_MAX;
67 stats->line_bip += (GET(RLOP_LBL) &0xff) |
68 ((GET(RLOP_LB) &0xff) <<8) |
69 ((GET(RLOP_LBM) &0xf) <<16);
70 if(stats->line_bip <0) stats->line_bip = LONG_MAX;
71 stats->path_bip += (GET(RPOP_PBL) &0xff) |
72 ((GET(RPOP_PBM) &0xff) <<8);
73 if(stats->path_bip <0) stats->path_bip = LONG_MAX;
74 stats->line_febe += (GET(RLOP_LFL) &0xff) |
75 ((GET(RLOP_LF) &0xff) <<8) |
76 ((GET(RLOP_LFM) &0xf) <<16);
77 if(stats->line_febe <0) stats->line_febe = LONG_MAX;
78 stats->path_febe += (GET(RPOP_PFL) &0xff) |
79 ((GET(RPOP_PFM) &0xff) <<8);
80 if(stats->path_febe <0) stats->path_febe = LONG_MAX;
81 stats->corr_hcs +=GET(RACP_CHEC) &0xff;
82 if(stats->corr_hcs <0) stats->corr_hcs = LONG_MAX;
83 stats->uncorr_hcs +=GET(RACP_UHEC) &0xff;
84 if(stats->uncorr_hcs <0) stats->uncorr_hcs = LONG_MAX;
85 stats->rx_cells += (GET(RACP_RCCL) &0xff) |
86 ((GET(RACP_RCC) &0xff) <<8) |
87 ((GET(RACP_RCCM) &7) <<16);
88 if(stats->rx_cells <0) stats->rx_cells = LONG_MAX;
89 stats->tx_cells += (GET(TACP_TCCL) &0xff) |
90 ((GET(TACP_TCC) &0xff) <<8) |
91 ((GET(TACP_TCCM) &7) <<16);
92 if(stats->tx_cells <0) stats->tx_cells = LONG_MAX;
94 if(!start_timer)mod_timer(&poll_timer,jiffies+HZ);
98 static intfetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
100 unsigned long flags;
101 int error;
103 error =0;
104 save_flags(flags);
105 cli();
106 if(arg)
107 error =copy_to_user(arg,&PRIV(dev)->sonet_stats,
108 sizeof(struct sonet_stats));
109 if(zero && !error)
110 memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
111 restore_flags(flags);
112 return error ? -EFAULT :0;
116 #define HANDLE_FLAG(flag,reg,bit) \
117 if (todo & flag) { \
118 if (set) PUT(GET(reg) | bit,reg); \
119 else PUT(GET(reg) & ~bit,reg); \
120 todo &= ~flag; \
124 static intchange_diag(struct atm_dev *dev,void*arg,int set)
126 int todo;
128 if(get_user(todo,(int*) arg))return-EFAULT;
129 HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8);
130 HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP);
131 HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3);
132 HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF);
133 HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS);
134 HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS);
135 HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS);
136 HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS);
137 returnput_user(todo,(int*) arg) ? -EFAULT :0;
141 #undef HANDLE_FLAG
144 static intget_diag(struct atm_dev *dev,void*arg)
146 int set;
148 set =0;
149 if(GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP;
150 if(GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP;
151 if(GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP;
152 /* SONET_INS_FRAME is one-shot only */
153 if(GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS;
154 if(GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS;
155 if(GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS;
156 if(GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS;
157 returnput_user(set,(int*) arg) ? -EFAULT :0;
161 static intsuni_ioctl(struct atm_dev *dev,unsigned int cmd,void*arg)
163 switch(cmd) {
164 case SONET_GETSTATZ:
165 case SONET_GETSTAT:
166 returnfetch_stats(dev,(struct sonet_stats *) arg,
167 cmd == SONET_GETSTATZ);
168 case SONET_SETDIAG:
169 returnchange_diag(dev,arg,1);
170 case SONET_CLRDIAG:
171 returnchange_diag(dev,arg,0);
172 case SONET_GETDIAG:
173 returnget_diag(dev,arg);
174 case SONET_SETFRAMING:
175 if(!capable(CAP_NET_ADMIN))return-EPERM;
176 if(arg != SONET_FRAME_SONET)return-EINVAL;
177 return0;
178 case SONET_GETFRAMING:
179 returnput_user(SONET_FRAME_SONET,(int*) arg) ?
180 -EFAULT :0;
181 case SONET_GETFRSENSE:
182 return-EINVAL;
183 case SUNI_SETLOOP:
184 if(!capable(CAP_NET_ADMIN))return-EPERM;
185 if((int) arg <0|| (int) arg > SUNI_LM_LOOP)
186 return-EINVAL;
187 PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) |
188 ((int) arg == SUNI_LM_DIAG ? SUNI_MCT_DLE :0) |
189 ((int) arg == SUNI_LM_LOOP ? SUNI_MCT_LLE :0),MCT);
190 PRIV(dev)->loop_mode = (int) arg;
191 return0;
192 case SUNI_GETLOOP:
193 returnput_user(PRIV(dev)->loop_mode,(int*) arg) ?
194 -EFAULT :0;
195 default:
196 return-EINVAL;
201 static voidpoll_los(struct atm_dev *dev)
203 dev->signal =GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? ATM_PHY_SIG_LOST :
204 ATM_PHY_SIG_FOUND;
208 static voidsuni_int(struct atm_dev *dev)
210 poll_los(dev);
211 printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number,
212 dev->signal == ATM_PHY_SIG_LOST ?"lost":"detected again");
216 static intsuni_start(struct atm_dev *dev)
218 unsigned long flags;
220 if(!(PRIV(dev) =kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
221 return-ENOMEM;
222 PRIV(dev)->dev = dev;
223 save_flags(flags);
224 cli();
225 PRIV(dev)->next = sunis;
226 sunis =PRIV(dev);
227 restore_flags(flags);
228 memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
229 PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
230 /* interrupt on loss of signal */
231 poll_los(dev);/* ... and clear SUNI interrupts */
232 if(dev->signal == ATM_PHY_SIG_LOST)
233 printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
234 dev->number);
235 PRIV(dev)->loop_mode = SUNI_LM_NONE;
236 suni_hz(0);/* clear SUNI counters */
237 (void)fetch_stats(dev,NULL,1);/* clear kernel counters */
238 cli();
239 if(!start_timer)restore_flags(flags);
240 else{
241 start_timer =0;
242 restore_flags(flags);
243 init_timer(&poll_timer);
244 poll_timer.expires = jiffies+HZ;
245 poll_timer.function = suni_hz;
246 #if 0
247 printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
248 (unsigned long) poll_timer.next);
249 #endif
250 add_timer(&poll_timer);
252 return0;
256 static const struct atmphy_ops suni_ops = {
257 suni_start,
258 suni_ioctl,
259 suni_int
263 int __init suni_init(struct atm_dev *dev)
265 unsigned char mri;
267 mri =GET(MRI);/* reset SUNI */
268 PUT(mri | SUNI_MRI_RESET,MRI);
269 PUT(mri,MRI);
270 PUT(0,MT);/* disable all tests */
271 REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET,
272 TPOP_APM);/* use SONET */
273 REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP,
274 TACP_IUCHP);/* idle cells */
275 PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP);
276 dev->phy = &suni_ops;
277 return0;
281 EXPORT_SYMBOL(suni_init);
284 #ifdef MODULE
287 intinit_module(void)
289 MOD_INC_USE_COUNT;
290 return0;
294 voidcleanup_module(void)
296 /* Nay */
299 #endif
close