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> 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> 26 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) 28 #define DPRINTK(format,args...) 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
; 57 struct sonet_stats
*stats
; 59 for(walk
= sunis
; walk
; walk
= walk
->next
) { 61 stats
= &walk
->sonet_stats
; 62 PUT(0,MRI
);/* latch counters */ 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
) 107 error
=copy_to_user(arg
,&PRIV(dev
)->sonet_stats
, 108 sizeof(struct sonet_stats
)); 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) \ 118 if (set) PUT(GET(reg) | bit,reg); \ 119 else PUT(GET(reg) & ~bit,reg); \ 124 static intchange_diag(struct atm_dev
*dev
,void*arg
,int set
) 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; 144 static intget_diag(struct atm_dev
*dev
,void*arg
) 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
) 166 returnfetch_stats(dev
,(struct sonet_stats
*) arg
, 167 cmd
== SONET_GETSTATZ
); 169 returnchange_diag(dev
,arg
,1); 171 returnchange_diag(dev
,arg
,0); 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
; 178 case SONET_GETFRAMING
: 179 returnput_user(SONET_FRAME_SONET
,(int*) arg
) ? 181 case SONET_GETFRSENSE
: 184 if(!capable(CAP_NET_ADMIN
))return-EPERM
; 185 if((int) arg
<0|| (int) arg
> SUNI_LM_LOOP
) 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
; 193 returnput_user(PRIV(dev
)->loop_mode
,(int*) arg
) ? 201 static voidpoll_los(struct atm_dev
*dev
) 203 dev
->signal
=GET(RSOP_SIS
) & SUNI_RSOP_SIS_LOSV
? ATM_PHY_SIG_LOST
: 208 static voidsuni_int(struct atm_dev
*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
) 220 if(!(PRIV(dev
) =kmalloc(sizeof(struct suni_priv
),GFP_KERNEL
))) 222 PRIV(dev
)->dev
= dev
; 225 PRIV(dev
)->next
= sunis
; 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
, 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 */ 239 if(!start_timer
)restore_flags(flags
); 242 restore_flags(flags
); 243 init_timer(&poll_timer
); 244 poll_timer
.expires
= jiffies
+HZ
; 245 poll_timer
.function
= suni_hz
; 247 printk(KERN_DEBUG
"[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer
.prev
, 248 (unsigned long) poll_timer
.next
); 250 add_timer(&poll_timer
); 256 static const struct atmphy_ops suni_ops
= { 263 int __init
suni_init(struct atm_dev
*dev
) 267 mri
=GET(MRI
);/* reset SUNI */ 268 PUT(mri
| SUNI_MRI_RESET
,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
; 281 EXPORT_SYMBOL(suni_init
); 294 voidcleanup_module(void)