1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * drivers/atm/suni.c - S/UNI PHY driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Supports the following:
6*4882a593Smuzhiyun * PMC PM5346 S/UNI LITE
7*4882a593Smuzhiyun * PMC PM5350 S/UNI 155 ULTRA
8*4882a593Smuzhiyun * PMC PM5355 S/UNI 622
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/jiffies.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/mm.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/atmdev.h>
19*4882a593Smuzhiyun #include <linux/sonet.h>
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/timer.h>
22*4882a593Smuzhiyun #include <linux/init.h>
23*4882a593Smuzhiyun #include <linux/capability.h>
24*4882a593Smuzhiyun #include <linux/atm_suni.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <asm/param.h>
27*4882a593Smuzhiyun #include <linux/uaccess.h>
28*4882a593Smuzhiyun #include <linux/atomic.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include "suni.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #if 0
34*4882a593Smuzhiyun #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
35*4882a593Smuzhiyun #else
36*4882a593Smuzhiyun #define DPRINTK(format,args...)
37*4882a593Smuzhiyun #endif
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define PRIV(dev) ((struct suni_priv *) dev->phy_data)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg)
42*4882a593Smuzhiyun #define GET(reg) dev->ops->phy_get(dev,SUNI_##reg)
43*4882a593Smuzhiyun #define REG_CHANGE(mask,shift,value,reg) \
44*4882a593Smuzhiyun PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static struct timer_list poll_timer;
48*4882a593Smuzhiyun static struct suni_priv *sunis = NULL;
49*4882a593Smuzhiyun static DEFINE_SPINLOCK(sunis_lock);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define ADD_LIMITED(s,v) \
53*4882a593Smuzhiyun atomic_add((v),&stats->s); \
54*4882a593Smuzhiyun if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun
suni_hz(struct timer_list * timer)57*4882a593Smuzhiyun static void suni_hz(struct timer_list *timer)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct suni_priv *walk;
60*4882a593Smuzhiyun struct atm_dev *dev;
61*4882a593Smuzhiyun struct k_sonet_stats *stats;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun for (walk = sunis; walk; walk = walk->next) {
64*4882a593Smuzhiyun dev = walk->dev;
65*4882a593Smuzhiyun stats = &walk->sonet_stats;
66*4882a593Smuzhiyun PUT(0,MRI); /* latch counters */
67*4882a593Smuzhiyun udelay(1);
68*4882a593Smuzhiyun ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
69*4882a593Smuzhiyun ((GET(RSOP_SBM) & 0xff) << 8));
70*4882a593Smuzhiyun ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
71*4882a593Smuzhiyun ((GET(RLOP_LB) & 0xff) << 8) |
72*4882a593Smuzhiyun ((GET(RLOP_LBM) & 0xf) << 16));
73*4882a593Smuzhiyun ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
74*4882a593Smuzhiyun ((GET(RPOP_PBM) & 0xff) << 8));
75*4882a593Smuzhiyun ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
76*4882a593Smuzhiyun ((GET(RLOP_LF) & 0xff) << 8) |
77*4882a593Smuzhiyun ((GET(RLOP_LFM) & 0xf) << 16));
78*4882a593Smuzhiyun ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
79*4882a593Smuzhiyun ((GET(RPOP_PFM) & 0xff) << 8));
80*4882a593Smuzhiyun ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
81*4882a593Smuzhiyun ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
82*4882a593Smuzhiyun ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
83*4882a593Smuzhiyun ((GET(RACP_RCC) & 0xff) << 8) |
84*4882a593Smuzhiyun ((GET(RACP_RCCM) & 7) << 16));
85*4882a593Smuzhiyun ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
86*4882a593Smuzhiyun ((GET(TACP_TCC) & 0xff) << 8) |
87*4882a593Smuzhiyun ((GET(TACP_TCCM) & 7) << 16));
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun if (timer) mod_timer(&poll_timer,jiffies+HZ);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #undef ADD_LIMITED
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun
fetch_stats(struct atm_dev * dev,struct sonet_stats __user * arg,int zero)96*4882a593Smuzhiyun static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct sonet_stats tmp;
99*4882a593Smuzhiyun int error = 0;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
102*4882a593Smuzhiyun if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
103*4882a593Smuzhiyun if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
104*4882a593Smuzhiyun return error ? -EFAULT : 0;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun #define HANDLE_FLAG(flag,reg,bit) \
109*4882a593Smuzhiyun if (todo & flag) { \
110*4882a593Smuzhiyun if (set) PUT(GET(reg) | bit,reg); \
111*4882a593Smuzhiyun else PUT(GET(reg) & ~bit,reg); \
112*4882a593Smuzhiyun todo &= ~flag; \
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun
change_diag(struct atm_dev * dev,void __user * arg,int set)116*4882a593Smuzhiyun static int change_diag(struct atm_dev *dev,void __user *arg,int set)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun int todo;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (get_user(todo,(int __user *)arg)) return -EFAULT;
121*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8);
122*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP);
123*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3);
124*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF);
125*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS);
126*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS);
127*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS);
128*4882a593Smuzhiyun HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS);
129*4882a593Smuzhiyun return put_user(todo,(int __user *)arg) ? -EFAULT : 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #undef HANDLE_FLAG
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun
get_diag(struct atm_dev * dev,void __user * arg)136*4882a593Smuzhiyun static int get_diag(struct atm_dev *dev,void __user *arg)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun int set;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun set = 0;
141*4882a593Smuzhiyun if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP;
142*4882a593Smuzhiyun if (GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP;
143*4882a593Smuzhiyun if (GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP;
144*4882a593Smuzhiyun /* SONET_INS_FRAME is one-shot only */
145*4882a593Smuzhiyun if (GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS;
146*4882a593Smuzhiyun if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS;
147*4882a593Smuzhiyun if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS;
148*4882a593Smuzhiyun if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS;
149*4882a593Smuzhiyun return put_user(set,(int __user *)arg) ? -EFAULT : 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun
set_loopback(struct atm_dev * dev,int mode)153*4882a593Smuzhiyun static int set_loopback(struct atm_dev *dev,int mode)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun unsigned char control;
156*4882a593Smuzhiyun int reg, dle, lle;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) {
159*4882a593Smuzhiyun reg = SUNI_MCM;
160*4882a593Smuzhiyun dle = SUNI_MCM_DLE;
161*4882a593Smuzhiyun lle = SUNI_MCM_LLE;
162*4882a593Smuzhiyun } else {
163*4882a593Smuzhiyun reg = SUNI_MCT;
164*4882a593Smuzhiyun dle = SUNI_MCT_DLE;
165*4882a593Smuzhiyun lle = SUNI_MCT_LLE;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun control = dev->ops->phy_get(dev, reg) & ~(dle | lle);
169*4882a593Smuzhiyun switch (mode) {
170*4882a593Smuzhiyun case ATM_LM_NONE:
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun case ATM_LM_LOC_PHY:
173*4882a593Smuzhiyun control |= dle;
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun case ATM_LM_RMT_PHY:
176*4882a593Smuzhiyun control |= lle;
177*4882a593Smuzhiyun break;
178*4882a593Smuzhiyun default:
179*4882a593Smuzhiyun return -EINVAL;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun dev->ops->phy_put(dev, control, reg);
182*4882a593Smuzhiyun PRIV(dev)->loop_mode = mode;
183*4882a593Smuzhiyun return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /*
187*4882a593Smuzhiyun * SONET vs. SDH Configuration
188*4882a593Smuzhiyun *
189*4882a593Smuzhiyun * Z0INS (register 0x06): 0 for SONET, 1 for SDH
190*4882a593Smuzhiyun * ENSS (register 0x3D): 0 for SONET, 1 for SDH
191*4882a593Smuzhiyun * LEN16 (register 0x28): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD)
192*4882a593Smuzhiyun * LEN16 (register 0x50): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD)
193*4882a593Smuzhiyun * S[1:0] (register 0x46): 00 for SONET, 10 for SDH
194*4882a593Smuzhiyun */
195*4882a593Smuzhiyun
set_sonet(struct atm_dev * dev)196*4882a593Smuzhiyun static int set_sonet(struct atm_dev *dev)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) {
199*4882a593Smuzhiyun PUT(GET(RPOP_RC) & ~SUNI_RPOP_RC_ENSS, RPOP_RC);
200*4882a593Smuzhiyun PUT(GET(SSTB_CTRL) & ~SUNI_SSTB_CTRL_LEN16, SSTB_CTRL);
201*4882a593Smuzhiyun PUT(GET(SPTB_CTRL) & ~SUNI_SPTB_CTRL_LEN16, SPTB_CTRL);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT,
205*4882a593Smuzhiyun SUNI_TPOP_S_SONET, TPOP_APM);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
set_sdh(struct atm_dev * dev)210*4882a593Smuzhiyun static int set_sdh(struct atm_dev *dev)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) {
213*4882a593Smuzhiyun PUT(GET(RPOP_RC) | SUNI_RPOP_RC_ENSS, RPOP_RC);
214*4882a593Smuzhiyun PUT(GET(SSTB_CTRL) | SUNI_SSTB_CTRL_LEN16, SSTB_CTRL);
215*4882a593Smuzhiyun PUT(GET(SPTB_CTRL) | SUNI_SPTB_CTRL_LEN16, SPTB_CTRL);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT,
219*4882a593Smuzhiyun SUNI_TPOP_S_SDH, TPOP_APM);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun
get_framing(struct atm_dev * dev,void __user * arg)225*4882a593Smuzhiyun static int get_framing(struct atm_dev *dev, void __user *arg)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun int framing;
228*4882a593Smuzhiyun unsigned char s;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun s = (GET(TPOP_APM) & SUNI_TPOP_APM_S) >> SUNI_TPOP_APM_S_SHIFT;
232*4882a593Smuzhiyun if (s == SUNI_TPOP_S_SONET)
233*4882a593Smuzhiyun framing = SONET_FRAME_SONET;
234*4882a593Smuzhiyun else
235*4882a593Smuzhiyun framing = SONET_FRAME_SDH;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return put_user(framing, (int __user *) arg) ? -EFAULT : 0;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
set_framing(struct atm_dev * dev,void __user * arg)240*4882a593Smuzhiyun static int set_framing(struct atm_dev *dev, void __user *arg)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun int mode;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (get_user(mode, (int __user *) arg))
245*4882a593Smuzhiyun return -EFAULT;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (mode == SONET_FRAME_SONET)
248*4882a593Smuzhiyun return set_sonet(dev);
249*4882a593Smuzhiyun else if (mode == SONET_FRAME_SDH)
250*4882a593Smuzhiyun return set_sdh(dev);
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun return -EINVAL;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun
suni_ioctl(struct atm_dev * dev,unsigned int cmd,void __user * arg)256*4882a593Smuzhiyun static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun switch (cmd) {
259*4882a593Smuzhiyun case SONET_GETSTATZ:
260*4882a593Smuzhiyun case SONET_GETSTAT:
261*4882a593Smuzhiyun return fetch_stats(dev, arg, cmd == SONET_GETSTATZ);
262*4882a593Smuzhiyun case SONET_SETDIAG:
263*4882a593Smuzhiyun return change_diag(dev,arg,1);
264*4882a593Smuzhiyun case SONET_CLRDIAG:
265*4882a593Smuzhiyun return change_diag(dev,arg,0);
266*4882a593Smuzhiyun case SONET_GETDIAG:
267*4882a593Smuzhiyun return get_diag(dev,arg);
268*4882a593Smuzhiyun case SONET_SETFRAMING:
269*4882a593Smuzhiyun if (!capable(CAP_NET_ADMIN))
270*4882a593Smuzhiyun return -EPERM;
271*4882a593Smuzhiyun return set_framing(dev, arg);
272*4882a593Smuzhiyun case SONET_GETFRAMING:
273*4882a593Smuzhiyun return get_framing(dev, arg);
274*4882a593Smuzhiyun case SONET_GETFRSENSE:
275*4882a593Smuzhiyun return -EINVAL;
276*4882a593Smuzhiyun case ATM_SETLOOP:
277*4882a593Smuzhiyun if (!capable(CAP_NET_ADMIN))
278*4882a593Smuzhiyun return -EPERM;
279*4882a593Smuzhiyun return set_loopback(dev,(int)(unsigned long)arg);
280*4882a593Smuzhiyun case ATM_GETLOOP:
281*4882a593Smuzhiyun return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ?
282*4882a593Smuzhiyun -EFAULT : 0;
283*4882a593Smuzhiyun case ATM_QUERYLOOP:
284*4882a593Smuzhiyun return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY,
285*4882a593Smuzhiyun (int __user *) arg) ? -EFAULT : 0;
286*4882a593Smuzhiyun default:
287*4882a593Smuzhiyun return -ENOIOCTLCMD;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun
poll_los(struct atm_dev * dev)292*4882a593Smuzhiyun static void poll_los(struct atm_dev *dev)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun atm_dev_signal_change(dev,
295*4882a593Smuzhiyun GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ?
296*4882a593Smuzhiyun ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun
suni_int(struct atm_dev * dev)300*4882a593Smuzhiyun static void suni_int(struct atm_dev *dev)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun poll_los(dev);
303*4882a593Smuzhiyun printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number,
304*4882a593Smuzhiyun dev->signal == ATM_PHY_SIG_LOST ? "lost" : "detected again");
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun
suni_start(struct atm_dev * dev)308*4882a593Smuzhiyun static int suni_start(struct atm_dev *dev)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun unsigned long flags;
311*4882a593Smuzhiyun int first;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun spin_lock_irqsave(&sunis_lock,flags);
314*4882a593Smuzhiyun first = !sunis;
315*4882a593Smuzhiyun PRIV(dev)->next = sunis;
316*4882a593Smuzhiyun sunis = PRIV(dev);
317*4882a593Smuzhiyun spin_unlock_irqrestore(&sunis_lock,flags);
318*4882a593Smuzhiyun memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
319*4882a593Smuzhiyun PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
320*4882a593Smuzhiyun /* interrupt on loss of signal */
321*4882a593Smuzhiyun poll_los(dev); /* ... and clear SUNI interrupts */
322*4882a593Smuzhiyun if (dev->signal == ATM_PHY_SIG_LOST)
323*4882a593Smuzhiyun printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
324*4882a593Smuzhiyun dev->number);
325*4882a593Smuzhiyun PRIV(dev)->loop_mode = ATM_LM_NONE;
326*4882a593Smuzhiyun suni_hz(NULL); /* clear SUNI counters */
327*4882a593Smuzhiyun (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
328*4882a593Smuzhiyun if (first) {
329*4882a593Smuzhiyun timer_setup(&poll_timer, suni_hz, 0);
330*4882a593Smuzhiyun poll_timer.expires = jiffies+HZ;
331*4882a593Smuzhiyun #if 0
332*4882a593Smuzhiyun printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.list.prev,
333*4882a593Smuzhiyun (unsigned long) poll_timer.list.next);
334*4882a593Smuzhiyun #endif
335*4882a593Smuzhiyun add_timer(&poll_timer);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun
suni_stop(struct atm_dev * dev)341*4882a593Smuzhiyun static int suni_stop(struct atm_dev *dev)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun struct suni_priv **walk;
344*4882a593Smuzhiyun unsigned long flags;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* let SAR driver worry about stopping interrupts */
347*4882a593Smuzhiyun spin_lock_irqsave(&sunis_lock,flags);
348*4882a593Smuzhiyun for (walk = &sunis; *walk != PRIV(dev);
349*4882a593Smuzhiyun walk = &PRIV((*walk)->dev)->next);
350*4882a593Smuzhiyun *walk = PRIV((*walk)->dev)->next;
351*4882a593Smuzhiyun if (!sunis) del_timer_sync(&poll_timer);
352*4882a593Smuzhiyun spin_unlock_irqrestore(&sunis_lock,flags);
353*4882a593Smuzhiyun kfree(PRIV(dev));
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun static const struct atmphy_ops suni_ops = {
360*4882a593Smuzhiyun .start = suni_start,
361*4882a593Smuzhiyun .ioctl = suni_ioctl,
362*4882a593Smuzhiyun .interrupt = suni_int,
363*4882a593Smuzhiyun .stop = suni_stop,
364*4882a593Smuzhiyun };
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun
suni_init(struct atm_dev * dev)367*4882a593Smuzhiyun int suni_init(struct atm_dev *dev)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun unsigned char mri;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
372*4882a593Smuzhiyun return -ENOMEM;
373*4882a593Smuzhiyun PRIV(dev)->dev = dev;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun mri = GET(MRI); /* reset SUNI */
376*4882a593Smuzhiyun PRIV(dev)->type = (mri & SUNI_MRI_TYPE) >> SUNI_MRI_TYPE_SHIFT;
377*4882a593Smuzhiyun PUT(mri | SUNI_MRI_RESET,MRI);
378*4882a593Smuzhiyun PUT(mri,MRI);
379*4882a593Smuzhiyun PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */
380*4882a593Smuzhiyun set_sonet(dev);
381*4882a593Smuzhiyun REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP,
382*4882a593Smuzhiyun TACP_IUCHP); /* idle cells */
383*4882a593Smuzhiyun PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP);
384*4882a593Smuzhiyun dev->phy = &suni_ops;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun EXPORT_SYMBOL(suni_init);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun MODULE_LICENSE("GPL");
392