📄 eni.c
字号:
static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci){ struct atm_vcc *walk; if (*vpi == ATM_VPI_ANY) *vpi = 0; if (*vci == ATM_VCI_ANY) { for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) { if (vcc->qos.rxtp.traffic_class != ATM_NONE && ENI_DEV(vcc->dev)->rx_map[*vci]) continue; if (vcc->qos.txtp.traffic_class != ATM_NONE) { for (walk = vcc->dev->vccs; walk; walk = walk->next) if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci && walk->qos.txtp.traffic_class != ATM_NONE) break; if (walk) continue; } break; } return *vci == NR_VCI ? -EADDRINUSE : 0; } if (*vci == ATM_VCI_UNSPEC) return 0; if (vcc->qos.rxtp.traffic_class != ATM_NONE && ENI_DEV(vcc->dev)->rx_map[*vci]) return -EADDRINUSE; if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; for (walk = vcc->dev->vccs; walk; walk = walk->next) if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci && walk->qos.txtp.traffic_class != ATM_NONE) return -EADDRINUSE; return 0;}static int eni_open(struct atm_vcc *vcc,short vpi,int vci){ struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; int error; DPRINTK(">eni_open\n"); EVENT("eni_open\n",0,0); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL; eni_dev = ENI_DEV(vcc->dev); error = get_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) return -EINVAL; DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, vcc->vci); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL); if (!eni_vcc) return -ENOMEM; ENI_VCC(vcc) = eni_vcc; eni_vcc->tx = NULL; /* for eni_close after open_rx */ if ((error = open_rx_first(vcc))) { eni_close(vcc); return error; } if ((error = open_tx_first(vcc))) { eni_close(vcc); return error; } } if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; if ((error = open_rx_second(vcc))) { eni_close(vcc); return error; } if ((error = open_tx_second(vcc))) { eni_close(vcc); return error; } set_bit(ATM_VF_READY,&vcc->flags); /* should power down SUNI while !ref_count @@@ */ return 0;}static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs){ struct eni_dev *eni_dev = ENI_DEV(vcc->dev); struct eni_tx *tx = ENI_VCC(vcc)->tx; struct sk_buff *skb; int error,rate,rsv,shp; if (qos->txtp.traffic_class == ATM_NONE) return 0; if (tx == eni_dev->ubr) return -EBADFD; rate = atm_pcr_goal(&qos->txtp); if (rate < 0) rate = -rate; rsv = shp = 0; if ((flgs & ATM_MF_DEC_RSV) && rate && rate < tx->reserved) rsv = 1; if ((flgs & ATM_MF_INC_RSV) && (!rate || rate > tx->reserved)) rsv = 1; if ((flgs & ATM_MF_DEC_SHP) && rate && rate < tx->shaping) shp = 1; if ((flgs & ATM_MF_INC_SHP) && (!rate || rate > tx->shaping)) shp = 1; if (!rsv && !shp) return 0; error = reserve_or_set_tx(vcc,&qos->txtp,rsv,shp); if (error) return error; if (shp && !(flgs & ATM_MF_IMMED)) return 0; /* * Walk through the send buffer and patch the rate information in all * segmentation buffer descriptors of this VCC. */ tasklet_disable(&eni_dev->task); for (skb = eni_dev->tx_queue.next; skb != (struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) { unsigned long dsc; if (ATM_SKB(skb)->vcc != vcc) continue; dsc = tx->send+ENI_PRV_POS(skb)*4; writel((readl(dsc) & ~(MID_SEG_RATE | MID_SEG_PR)) | (tx->prescaler << MID_SEG_PR_SHIFT) | (tx->resolution << MID_SEG_RATE_SHIFT), dsc); } tasklet_enable(&eni_dev->task); return 0;}static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg){ struct eni_dev *eni_dev = ENI_DEV(dev); if (cmd == ENI_MEMDUMP) { if (!capable(CAP_NET_ADMIN)) return -EPERM; printk(KERN_WARNING "Please use /proc/atm/" DEV_LABEL ":%d " "instead of obsolete ioctl ENI_MEMDUMP\n",dev->number); dump(dev); return 0; } if (cmd == ENI_SETMULT) { struct eni_multipliers mult; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&mult,(void *) arg, sizeof(struct eni_multipliers))) return -EFAULT; if ((mult.tx && mult.tx <= 100) || (mult.rx &&mult.rx <= 100) || mult.tx > 65536 || mult.rx > 65536) return -EINVAL; if (mult.tx) eni_dev->tx_mult = mult.tx; if (mult.rx) eni_dev->rx_mult = mult.rx; return 0; } if (cmd == ATM_SETCIRANGE) { struct atm_cirange ci; if (copy_from_user(&ci,(void *) arg,sizeof(struct atm_cirange))) return -EFAULT; if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && (ci.vci_bits == NR_VCI_LD || ci.vpi_bits == ATM_CI_MAX)) return 0; return -EINVAL; } if (!dev->phy->ioctl) return -ENOIOCTLCMD; return dev->phy->ioctl(dev,cmd,arg);}static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, void *optval,int optlen){ return -EINVAL;}static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, void *optval,int optlen){ return -EINVAL;}static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb){ enum enq_res res; DPRINTK(">eni_send\n"); if (!ENI_VCC(vcc)->tx) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); return -EINVAL; } if (!skb) { printk(KERN_CRIT "!skb in eni_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); return -EINVAL; } if (vcc->qos.aal == ATM_AAL0) { if (skb->len != ATM_CELL_SIZE-1) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); return -EINVAL; } *(u32 *) skb->data = htonl(*(u32 *) skb->data); }submitted++; ATM_SKB(skb)->vcc = vcc; tasklet_disable(&ENI_DEV(vcc->dev)->task); res = do_tx(skb); tasklet_enable(&ENI_DEV(vcc->dev)->task); if (res == enq_ok) return 0; skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);backlogged++; tasklet_schedule(&ENI_DEV(vcc->dev)->task); return 0;}static int eni_sg_send(struct atm_vcc *vcc,unsigned long start, unsigned long size){ return vcc->qos.aal == ATM_AAL5 && !((start | size) & 3); /* don't tolerate misalignment */}static void eni_phy_put(struct atm_dev *dev,unsigned char value, unsigned long addr){ writel(value,ENI_DEV(dev)->phy+addr*4);}static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr){ return readl(ENI_DEV(dev)->phy+addr*4);}static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page){ static const char *signal[] = { "LOST","unknown","okay" }; struct eni_dev *eni_dev = ENI_DEV(dev); struct atm_vcc *vcc; int left,i; left = *pos; if (!left) return sprintf(page,DEV_LABEL "(itf %d) signal %s, %dkB, " "%d cps remaining\n",dev->number,signal[(int) dev->signal], eni_dev->mem >> 10,eni_dev->tx_bw); if (!--left) return sprintf(page,"%4sBursts: TX"#if !defined(CONFIG_ATM_ENI_BURST_TX_16W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_8W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_4W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_2W) " none"#endif#ifdef CONFIG_ATM_ENI_BURST_TX_16W " 16W"#endif#ifdef CONFIG_ATM_ENI_BURST_TX_8W " 8W"#endif#ifdef CONFIG_ATM_ENI_BURST_TX_4W " 4W"#endif#ifdef CONFIG_ATM_ENI_BURST_TX_2W " 2W"#endif ", RX"#if !defined(CONFIG_ATM_ENI_BURST_RX_16W) && \ !defined(CONFIG_ATM_ENI_BURST_RX_8W) && \ !defined(CONFIG_ATM_ENI_BURST_RX_4W) && \ !defined(CONFIG_ATM_ENI_BURST_RX_2W) " none"#endif#ifdef CONFIG_ATM_ENI_BURST_RX_16W " 16W"#endif#ifdef CONFIG_ATM_ENI_BURST_RX_8W " 8W"#endif#ifdef CONFIG_ATM_ENI_BURST_RX_4W " 4W"#endif#ifdef CONFIG_ATM_ENI_BURST_RX_2W " 2W"#endif#ifndef CONFIG_ATM_ENI_TUNE_BURST " (default)"#endif "\n",""); if (!--left) return sprintf(page,"%4sBuffer multipliers: tx %d%%, rx %d%%\n", "",eni_dev->tx_mult,eni_dev->rx_mult); for (i = 0; i < NR_CHAN; i++) { struct eni_tx *tx = eni_dev->tx+i; if (!tx->send) continue; if (!--left) { return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx " "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, tx->send-eni_dev->ram, tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, tx->reserved,tx->shaping, tx == eni_dev->ubr ? " (UBR)" : ""); } if (--left) continue; return sprintf(page,"%10sbacklog %u packets\n","", skb_queue_len(&tx->backlog)); } for (vcc = dev->vccs; vcc; vcc = vcc->next) { struct eni_vcc *eni_vcc = ENI_VCC(vcc); int length; if (--left) continue; length = sprintf(page,"vcc %4d: ",vcc->vci); if (eni_vcc->rx) { length += sprintf(page+length,"0x%06lx-0x%06lx " "(%6ld bytes)", eni_vcc->recv-eni_dev->ram, eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, eni_vcc->words*4); if (eni_vcc->tx) length += sprintf(page+length,", "); } if (eni_vcc->tx) length += sprintf(page+length,"tx[%d], txing %d bytes", eni_vcc->tx->index,eni_vcc->txing); page[length] = '\n'; return length+1; } for (i = 0; i < eni_dev->free_len; i++) { struct eni_free *fe = eni_dev->free_list+i; unsigned long offset; if (--left) continue; offset = eni_dev->ram+eni_dev->base_diff; return sprintf(page,"free 0x%06lx-0x%06lx (%6d bytes)\n", fe->start-offset,fe->start-offset+(1 << fe->order)-1, 1 << fe->order); } return 0;}static const struct atmdev_ops ops = { open: eni_open, close: eni_close, ioctl: eni_ioctl, getsockopt: eni_getsockopt, setsockopt: eni_setsockopt, send: eni_send, sg_send: eni_sg_send, phy_put: eni_phy_put, phy_get: eni_phy_get, change_qos: eni_change_qos, proc_read: eni_proc_read};static int __devinit eni_init_one(struct pci_dev *pci_dev, const struct pci_device_id *ent){ struct atm_dev *dev; struct eni_dev *eni_dev; int error = -ENOMEM; DPRINTK("eni_init_one\n"); MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */ if (pci_enable_device(pci_dev)) { error = -EIO; goto out0; } eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL); if (!eni_dev) goto out0; if (!cpu_zeroes) { cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE, &zeroes); if (!cpu_zeroes) goto out1; } dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) goto out2; pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; ENI_DEV(dev) = eni_dev; eni_dev->asic = ent->driver_data; error = eni_do_init(dev); if (error) goto out3; error = eni_start(dev); if (error) goto out3; eni_dev->more = eni_boards; eni_boards = dev; return 0;out3: atm_dev_deregister(dev);out2: pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,cpu_zeroes,zeroes); cpu_zeroes = NULL;out1: kfree(eni_dev);out0: MOD_DEC_USE_COUNT; /* @@@ we don't support unloading yet */ return error;}static struct pci_device_id eni_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 /* FPGA */ }, { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 /* ASIC */ }, { 0, }};MODULE_DEVICE_TABLE(pci,eni_pci_tbl);static void __devexit eni_remove_one(struct pci_dev *pci_dev){ /* grrr */}static struct pci_driver eni_driver = { name: DEV_LABEL, id_table: eni_pci_tbl, probe: eni_init_one, remove: __devexit_p(eni_remove_one),};static int __init eni_init(void){ struct sk_buff *skb; /* dummy for sizeof */ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", sizeof(skb->cb),sizeof(struct eni_skb_prv)); return -EIO; } if (pci_register_driver(&eni_driver) > 0) return 0; pci_unregister_driver (&eni_driver); return -ENODEV;}static void __exit eni_cleanup(void){ /* * Well, there's no way to get rid of the driver yet, so we don't * have to clean up, right ? :-) */}module_init(eni_init);module_exit(eni_cleanup);EXPORT_NO_SYMBOLS;MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -