Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/atm/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 9 kB image not shown  

Quelle  suni.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * 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>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/slab.h>
#include <asm/param.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>

#include "suni.h"


#if 0
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else
#define DPRINTK(format,args...)
#endif

#define PRIV(dev) ((struct suni_priv *) dev->phy_data)

#define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg)
#define GET(reg) dev->ops->phy_get(dev,SUNI_##reg)
#define REG_CHANGE(mask,shift,value,reg) \
  PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg)


static struct timer_list poll_timer;
static struct suni_priv *sunis = NULL;
static DEFINE_SPINLOCK(sunis_lock);


#define ADD_LIMITED(s,v) \
    atomic_add((v),&stats->s); \
    if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);


static void suni_hz(struct timer_list *timer)
{
 struct suni_priv *walk;
 struct atm_dev *dev;
 struct k_sonet_stats *stats;

 for (walk = sunis; walk; walk = walk->next) {
  dev = walk->dev;
  stats = &walk->sonet_stats;
  PUT(0,MRI); /* latch counters */
  udelay(1);
  ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
      ((GET(RSOP_SBM) & 0xff) << 8));
  ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
      ((GET(RLOP_LB) & 0xff) << 8) |
      ((GET(RLOP_LBM) & 0xf) << 16));
  ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
      ((GET(RPOP_PBM) & 0xff) << 8));
  ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
      ((GET(RLOP_LF) & 0xff) << 8) |
      ((GET(RLOP_LFM) & 0xf) << 16));
  ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
      ((GET(RPOP_PFM) & 0xff) << 8));
  ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
  ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
  ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
      ((GET(RACP_RCC) & 0xff) << 8) |
      ((GET(RACP_RCCM) & 7) << 16));
  ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
      ((GET(TACP_TCC) & 0xff) << 8) |
      ((GET(TACP_TCCM) & 7) << 16));
 }
 if (timer) mod_timer(&poll_timer,jiffies+HZ);
}


#undef ADD_LIMITED


static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero)
{
 struct sonet_stats tmp;
 int error = 0;

 sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
 if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
 if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
 return error ? -EFAULT : 0;
}


#define HANDLE_FLAG(flag,reg,bit) \
  if (todo & flag) { \
    if (set) PUT(GET(reg) | bit,reg); \
    else PUT(GET(reg) & ~bit,reg); \
    todo &= ~flag; \
  }


static int change_diag(struct atm_dev *dev,void __user *arg,int set)
{
 int todo;

 if (get_user(todo,(int __user *)arg)) return -EFAULT;
 HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8);
 HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP);
 HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3);
 HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF);
 HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS);
 HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS);
 HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS);
 HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS);
 return put_user(todo,(int __user *)arg) ? -EFAULT : 0;
}


#undef HANDLE_FLAG


static int get_diag(struct atm_dev *dev,void __user *arg)
{
 int set;

 set = 0;
 if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP;
 if (GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP;
 if (GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP;
 /* SONET_INS_FRAME is one-shot only */
 if (GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS;
 if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS;
 if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS;
 if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS;
 return put_user(set,(int __user *)arg) ? -EFAULT : 0;
}


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 = dev->ops->phy_get(dev, reg) & ~(dle | lle);
 switch (mode) {
  case ATM_LM_NONE:
   break;
  case ATM_LM_LOC_PHY:
   control |= dle;
   break;
  case ATM_LM_RMT_PHY:
   control |= lle;
   break;
  default:
   return -EINVAL;
 }
 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)
{
 switch (cmd) {
  case SONET_GETSTATZ:
  case SONET_GETSTAT:
   return fetch_stats(dev, arg, cmd == SONET_GETSTATZ);
  case SONET_SETDIAG:
   return change_diag(dev,arg,1);
  case SONET_CLRDIAG:
   return change_diag(dev,arg,0);
  case SONET_GETDIAG:
   return get_diag(dev,arg);
  case SONET_SETFRAMING:
   if (!capable(CAP_NET_ADMIN))
    return -EPERM;
   return set_framing(dev, arg);
  case SONET_GETFRAMING:
   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) ?
       -EFAULT : 0;
  case ATM_QUERYLOOP:
   return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY,
       (int __user *) arg) ? -EFAULT : 0;
  default:
   return -ENOIOCTLCMD;
 }
}


static void poll_los(struct atm_dev *dev)
{
 atm_dev_signal_change(dev,
  GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ?
  ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND);
}


static void suni_int(struct atm_dev *dev)
{
 poll_los(dev);
 printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number,
     dev->signal == ATM_PHY_SIG_LOST ?  "lost" : "detected again");
}


static int suni_start(struct atm_dev *dev)
{
 unsigned long flags;
 int first;

 spin_lock_irqsave(&sunis_lock,flags);
 first = !sunis;
 PRIV(dev)->next = sunis;
 sunis = PRIV(dev);
 spin_unlock_irqrestore(&sunis_lock,flags);
 memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
 PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
  /* interrupt on loss of signal */
 poll_los(dev); /* ... and clear SUNI interrupts */
 if (dev->signal == ATM_PHY_SIG_LOST)
  printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
      dev->number);
 PRIV(dev)->loop_mode = ATM_LM_NONE;
 suni_hz(NULL); /* clear SUNI counters */
 (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
 if (first) {
  timer_setup(&poll_timer, suni_hz, 0);
  poll_timer.expires = jiffies+HZ;
#if 0
printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.list.prev,
    (unsigned long) poll_timer.list.next);
#endif
  add_timer(&poll_timer);
 }
 return 0;
}


static int suni_stop(struct atm_dev *dev)
{
 struct suni_priv **walk;
 unsigned long flags;

 /* let SAR driver worry about stopping interrupts */
 spin_lock_irqsave(&sunis_lock,flags);
 for (walk = &sunis; *walk != PRIV(dev);
     walk = &PRIV((*walk)->dev)->next);
 *walk = PRIV((*walk)->dev)->next;
 if (!sunis) timer_delete_sync(&poll_timer);
 spin_unlock_irqrestore(&sunis_lock,flags);
 kfree(PRIV(dev));

 return 0;
}


static const struct atmphy_ops suni_ops = {
 .start  = suni_start,
 .ioctl  = suni_ioctl,
 .interrupt = suni_int,
 .stop  = suni_stop,
};


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 */
        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;
}

EXPORT_SYMBOL(suni_init);

MODULE_DESCRIPTION("S/UNI PHY driver");
MODULE_LICENSE("GPL");

Messung V0.5
C=94 H=92 G=92

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.