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 + -
显示快捷键?