eni.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,303 行 · 第 1/5 页
C
2,303 行
eni_dev->free_len = 0; eni_put_free(eni_dev,buf,buffer_mem); memset_io(eni_dev->vci,0,16*NR_VCI); /* clear VCI table */ /* * byte_addr free (k) * 0x00000000 512 VCI table * 0x00004000 496 RX DMA * 0x00005000 492 TX DMA * 0x00006000 488 service list * 0x00007000 484 buffers * 0x00080000 0 end (512kB) */ eni_out(0xffffffff,MID_IE); error = start_tx(dev); if (error) return error; error = start_rx(dev); if (error) return error; error = dev->phy->start(dev); if (error) return error; eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, MID_MC_S); /* Tonga uses SBus INTReq1 */ (void) eni_in(MID_ISA); /* clear Midway interrupts */ return 0;}static void eni_close(struct atm_vcc *vcc){ DPRINTK(">eni_close\n"); if (!ENI_VCC(vcc)) return; clear_bit(ATM_VF_READY,&vcc->flags); close_rx(vcc); close_tx(vcc); DPRINTK("eni_close: done waiting\n"); /* deallocate memory */ kfree(ENI_VCC(vcc)); vcc->dev_data = NULL; clear_bit(ATM_VF_ADDR,&vcc->flags); /*foo();*/}static int eni_open(struct atm_vcc *vcc){ struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; int error; short vpi = vcc->vpi; int vci = vcc->vci; DPRINTK(">eni_open\n"); EVENT("eni_open\n",0,0); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL; eni_dev = ENI_DEV(vcc->dev); 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; vcc->dev_data = 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); skb_queue_walk(&eni_dev->tx_queue, skb) { void __iomem *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 __user *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, 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, 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 __user *optval,int optlen){ return -EINVAL;}static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, void __user *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 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){ struct hlist_node *node; struct sock *s; 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%ld-0x%ld " "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, (unsigned long) (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)); } read_lock(&vcc_sklist_lock); for(i = 0; i < VCC_HTABLE_SIZE; ++i) { struct hlist_head *head = &vcc_hash[i]; sk_for_each(s, node, head) { struct eni_vcc *eni_vcc; int length; vcc = atm_sk(s); if (vcc->dev != dev) continue; eni_vcc = ENI_VCC(vcc); if (--left) continue; length = sprintf(page,"vcc %4d: ",vcc->vci); if (eni_vcc->rx) { length += sprintf(page+length,"0x%ld-0x%ld " "(%6ld bytes)", (unsigned long) (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'; read_unlock(&vcc_sklist_lock); return length+1; } } read_unlock(&vcc_sklist_lock); 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 = (unsigned long) eni_dev->ram+eni_dev->base_diff; return sprintf(page,"free %p-%p (%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, .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"); 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; dev->dev_data = 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: return error;}static struct pci_device_id eni_pci_tbl[] = { { 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 (%Zd < %Zd)\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;}module_init(eni_init);/* @@@ since exit routine not defined, this module can not be unloaded */MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?