⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 firestream.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			submit_command (dev, &dev->hp_txq, 					QE_CMD_REG_WR | QE_CMD_IMM_INQ,					0x80 + vcc->channo,					(vpi << 16) | vci, 0 ); /* XXX -- Use defines. */		}		submit_command (dev, &dev->hp_txq, 				QE_CMD_RX_EN | QE_CMD_IMM_INQ | vcc->channo,				0, 0, 0);	}    	/* Indicate we're done! */	set_bit(ATM_VF_READY, &atm_vcc->flags);	func_exit ();	return 0;}static void fs_close(struct atm_vcc *atm_vcc){	struct fs_dev *dev = FS_DEV (atm_vcc->dev);	struct fs_vcc *vcc = FS_VCC (atm_vcc);	struct atm_trafprm * txtp;	struct atm_trafprm * rxtp;	func_enter ();	clear_bit(ATM_VF_READY, &atm_vcc->flags);	fs_dprintk (FS_DEBUG_QSIZE, "--==**[%d]**==--", dev->ntxpckts);	if (vcc->last_skb) {		fs_dprintk (FS_DEBUG_QUEUE, "Waiting for skb %p to be sent.\n", 			    vcc->last_skb);		/* We're going to wait for the last packet to get sent on this VC. It would		   be impolite not to send them don't you think? 		   XXX		   We don't know which packets didn't get sent. So if we get interrupted in 		   this sleep_on, we'll lose any reference to these packets. Memory leak!		   On the other hand, it's awfully convenient that we can abort a "close" that		   is taking too long. Maybe just use non-interruptible sleep on? -- REW */		interruptible_sleep_on (& vcc->close_wait);	}	txtp = &atm_vcc->qos.txtp;	rxtp = &atm_vcc->qos.rxtp;  	/* See App note XXX (Unpublished as of now) for the reason for the 	   removal of the "CMD_IMM_INQ" part of the TX_PURGE_INH... -- REW */	if (DO_DIRECTION (txtp)) {		submit_command (dev,  &dev->hp_txq,				QE_CMD_TX_PURGE_INH | /*QE_CMD_IMM_INQ|*/ vcc->channo, 0,0,0);		clear_bit (vcc->channo, dev->tx_inuse);	}	if (DO_DIRECTION (rxtp)) {		submit_command (dev,  &dev->hp_txq,				QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0);		dev->atm_vccs [vcc->channo] = NULL;  		/* This means that this is configured as a receive channel */		if (IS_FS50 (dev)) {			/* Disable the receive filter. Is 0/0 indeed an invalid receive			   channel? -- REW.  Yes it is. -- Hang. Ok. I'll use -1			   (0xfff...) -- REW */			submit_command (dev, &dev->hp_txq, 					QE_CMD_REG_WR | QE_CMD_IMM_INQ,					0x80 + vcc->channo, -1, 0 ); 		}	}	fs_dprintk (FS_DEBUG_ALLOC, "Free vcc: %p\n", vcc);	kfree (vcc);	func_exit ();}static int fs_send (struct atm_vcc *atm_vcc, struct sk_buff *skb){	struct fs_dev *dev = FS_DEV (atm_vcc->dev);	struct fs_vcc *vcc = FS_VCC (atm_vcc);	struct FS_BPENTRY *td;	func_enter ();	fs_dprintk (FS_DEBUG_TXMEM, "I");	fs_dprintk (FS_DEBUG_SEND, "Send: atm_vcc %p skb %p vcc %p dev %p\n", 		    atm_vcc, skb, vcc, dev);	fs_dprintk (FS_DEBUG_ALLOC, "Alloc t-skb: %p (atm_send)\n", skb);	ATM_SKB(skb)->vcc = atm_vcc;	vcc->last_skb = skb;	td = kmalloc (sizeof (struct FS_BPENTRY), GFP_ATOMIC);	fs_dprintk (FS_DEBUG_ALLOC, "Alloc transd: %p(%d)\n", td, sizeof (struct FS_BPENTRY));	if (!td) {		/* Oops out of mem */		return -ENOMEM;	}	fs_dprintk (FS_DEBUG_SEND, "first word in buffer: %x\n", 		    *(int *) skb->data);	td->flags =  TD_EPI | TD_DATA | skb->len;	td->next = 0;	td->bsa  = virt_to_bus (skb->data);	td->skb = skb;	td->dev = dev;	dev->ntxpckts++;#ifdef DEBUG_EXTRA	da[qd] = td;	dq[qd].flags = td->flags;	dq[qd].next  = td->next;	dq[qd].bsa   = td->bsa;	dq[qd].skb   = td->skb;	dq[qd].dev   = td->dev;	qd++;	if (qd >= 60) qd = 0;#endif	submit_queue (dev, &dev->hp_txq, 		      QE_TRANSMIT_DE | vcc->channo,		      virt_to_bus (td), 0, 		      virt_to_bus (td));	fs_dprintk (FS_DEBUG_QUEUE, "in send: txq %d txrq %d\n", 		    read_fs (dev, Q_EA (dev->hp_txq.offset)) -		    read_fs (dev, Q_SA (dev->hp_txq.offset)),		    read_fs (dev, Q_EA (dev->tx_relq.offset)) -		    read_fs (dev, Q_SA (dev->tx_relq.offset)));	func_exit ();	return 0;}/* Some function placeholders for functions we don't yet support. */#if 0static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg){	func_enter ();	func_exit ();	return 0;}static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname,			 void *optval,int optlen){	func_enter ();	func_exit ();	return 0;}static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname,			 void *optval,int optlen){	func_enter ();	func_exit ();	return 0;}static void fs_phy_put(struct atm_dev *dev,unsigned char value,		       unsigned long addr){	func_enter ();	func_exit ();}static unsigned char fs_phy_get(struct atm_dev *dev,unsigned long addr){	func_enter ();	func_exit ();	return 0;}static void fs_feedback(struct atm_vcc *vcc,struct sk_buff *skb,			unsigned long start,unsigned long dest,int len){	func_enter ();	func_exit ();}static int fs_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags){	func_enter ();	func_exit ();	return 0;};#endifstatic const struct atmdev_ops ops = {	open:           fs_open,	close:          fs_close,	send:           fs_send,#if 0	owner:          THIS_MODULE,#endif	/*                 fs_sg_send */	/* ioctl:          fs_ioctl, */	/* getsockopt:     fs_getsockopt, */	/* setsockopt:     fs_setsockopt, */	/* feedback:       fs_feedback, */	/* change_qos:     fs_change_qos, */	/* For now implement these internally here... */  	/* phy_put:        fs_phy_put, */	/* phy_get:        fs_phy_get, */};static void __init undocumented_pci_fix (struct pci_dev *pdev){	int tint;	/* The Windows driver says: */	/* Switch off FireStream Retry Limit Threshold 	 */	/* The register at 0x28 is documented as "reserved", no further	   comments. */	pci_read_config_dword (pdev, 0x28, &tint);	if (tint != 0x80) {		tint = 0x80;		pci_write_config_dword (pdev, 0x28, tint);	}}/************************************************************************** *                              PHY routines                              * **************************************************************************/static void __init write_phy (struct fs_dev *dev, int regnum, int val){	submit_command (dev,  &dev->hp_txq, QE_CMD_PRP_WR | QE_CMD_IMM_INQ,			regnum, val, 0);}static int __init init_phy (struct fs_dev *dev, struct reginit_item *reginit){	int i;	func_enter ();	while (reginit->reg != PHY_EOF) {		if (reginit->reg == PHY_CLEARALL) {			/* "PHY_CLEARALL means clear all registers. Numregisters is in "val". */			for (i=0;i<reginit->val;i++) {				write_phy (dev, i, 0);			}		} else {			write_phy (dev, reginit->reg, reginit->val);		}		reginit++;	}	func_exit ();	return 0;}static void reset_chip (struct fs_dev *dev){	int i;	write_fs (dev, SARMODE0, SARMODE0_SRTS0);	/* Undocumented delay */	udelay (128);	/* The "internal registers are documented to all reset to zero, but 	   comments & code in the Windows driver indicates that the pools are	   NOT reset. */	for (i=0;i < FS_NR_FREE_POOLS;i++) {		write_fs (dev, FP_CNF (RXB_FP(i)), 0);		write_fs (dev, FP_SA  (RXB_FP(i)), 0);		write_fs (dev, FP_EA  (RXB_FP(i)), 0);		write_fs (dev, FP_CNT (RXB_FP(i)), 0);		write_fs (dev, FP_CTU (RXB_FP(i)), 0);	}	/* The same goes for the match channel registers, although those are	   NOT documented that way in the Windows driver. -- REW */	/* The Windows driver DOES write 0 to these registers somewhere in	   the init sequence. However, a small hardware-feature, will	   prevent reception of data on VPI/VCI = 0/0 (Unless the channel	   allocated happens to have no disabled channels that have a lower	   number. -- REW */	/* Clear the match channel registers. */	if (IS_FS50 (dev)) {		for (i=0;i<FS50_NR_CHANNELS;i++) {			write_fs (dev, 0x200 + i * 4, -1);		}	}}static void __init *aligned_kmalloc (int size, int flags, int alignment){	void  *t;	if (alignment <= 0x10) {		t = kmalloc (size, flags);		if ((unsigned int)t & (alignment-1)) {			printk ("Kmalloc doesn't align things correctly! %p\n", t);			kfree (t);			return aligned_kmalloc (size, flags, alignment * 4);		}		return t;	}	printk (KERN_ERR "Request for > 0x10 alignment not yet implemented (hard!)\n");	return NULL;}static int __init init_q (struct fs_dev *dev, 			  struct queue *txq, int queue, int nentries, int is_rq){	int sz = nentries * sizeof (struct FS_QENTRY);	struct FS_QENTRY *p;	func_enter ();	fs_dprintk (FS_DEBUG_INIT, "Inititing queue at %x: %d entries:\n", 		    queue, nentries);	p = aligned_kmalloc (sz, GFP_KERNEL, 0x10);	fs_dprintk (FS_DEBUG_ALLOC, "Alloc queue: %p(%d)\n", p, sz);	if (!p) return 0;	write_fs (dev, Q_SA(queue), virt_to_bus(p));	write_fs (dev, Q_EA(queue), virt_to_bus(p+nentries-1));	write_fs (dev, Q_WP(queue), virt_to_bus(p));	write_fs (dev, Q_RP(queue), virt_to_bus(p));	if (is_rq) {		/* Configuration for the receive queue: 0: interrupt immediately,		   no pre-warning to empty queues: We do our best to keep the		   queue filled anyway. */		write_fs (dev, Q_CNF(queue), 0 ); 	}	txq->sa = p;	txq->ea = p;	txq->offset = queue; 	func_exit ();	return 1;}static int __init init_fp (struct fs_dev *dev, 			   struct freepool *fp, int queue, int bufsize, int nr_buffers){	func_enter ();	fs_dprintk (FS_DEBUG_INIT, "Inititing free pool at %x:\n", queue);	write_fs (dev, FP_CNF(queue), (bufsize * RBFP_RBS) | RBFP_RBSVAL | RBFP_CME);	write_fs (dev, FP_SA(queue),  0);	write_fs (dev, FP_EA(queue),  0);	write_fs (dev, FP_CTU(queue), 0);	write_fs (dev, FP_CNT(queue), 0);	fp->offset = queue; 	fp->bufsize = bufsize;	fp->nr_buffers = nr_buffers;	func_exit ();	return 1;}static inline int nr_buffers_in_freepool (struct fs_dev *dev, struct freepool *fp){#if 0	/* This seems to be unreliable.... */	return read_fs (dev, FP_CNT (fp->offset));#else	return fp->n;#endif}/* Check if this gets going again if a pool ever runs out.  -- Yes, it   does. I've seen "recieve abort: no buffers" and things started   working again after that...  -- REW */static void top_off_fp (struct fs_dev *dev, struct freepool *fp, int gfp_flags){	struct FS_BPENTRY *qe, *ne;	struct sk_buff *skb;	int n = 0;	fs_dprintk (FS_DEBUG_QUEUE, "Topping off queue at %x (%d-%d/%d)\n", 		    fp->offset, read_fs (dev, FP_CNT (fp->offset)), fp->n, 		    fp->nr_buffers);	while (nr_buffers_in_freepool(dev, fp) < fp->nr_buffers) {		skb = alloc_skb (fp->bufsize, gfp_flags);		fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-skb: %p(%d)\n", skb, fp->bufsize);		if (!skb) break;		ne = kmalloc (sizeof (struct FS_BPENTRY), gfp_flags);		fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-d: %p(%d)\n", ne, sizeof (struct FS_BPENTRY));		if (!ne) {			fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", skb);			dev_kfree_skb_any (skb);			break;		}		fs_dprintk (FS_DEBUG_QUEUE, "Adding skb %p desc %p -> %p(%p) ", 			    skb, ne, skb->data, skb->head);		n++;		ne->flags = FP_FLAGS_EPI | fp->bufsize;		ne->next  = virt_to_bus (NULL);		ne->bsa   = virt_to_bus (skb->data);		ne->aal_bufsize = fp->bufsize;		ne->skb = skb;		ne->fp = fp;		qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset)));		fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe);		if (qe) {			qe = bus_to_virt ((long) qe);			qe->next = virt_to_bus(ne);			qe->flags &= ~FP_FLAGS_EPI;		} else			write_fs (dev, FP_SA(fp->offset), virt_to_bus(ne));		write_fs (dev, FP_EA(fp->offset), virt_to_bus (ne));		fp->n++;   /* XXX Atomic_inc? */		write_fs (dev, FP_CTU(fp->offset), 1);	}	fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n);}static void __exit free_queue (struct fs_dev *dev, struct queue *txq){	func_enter ();	write_fs (dev, Q_SA(txq->offset), 0);	write_fs (dev, Q_EA(txq->offset), 0);	write_fs (dev, Q_RP(txq->offset), 0);	write_fs (dev, Q_WP(txq->offset), 0);	/* Configuration ? */	fs_dprintk (FS_DEBUG_ALLOC, "Free queue: %p\n", txq->sa);	kfree (txq->sa);	func_exit ();}static void __exit free_freepool (struct fs_dev *dev, struct freepool *fp){	func_enter ();	write_fs (dev, FP_CNF(fp->offset), 0);	write_fs (dev, FP_SA (fp->offset), 0);	write_fs (dev, FP_EA (fp->offset), 0);	write_fs (dev, FP_CNT(fp->offset), 0);	write_fs (dev, FP_CTU(fp->offset), 0);	func_exit ();}static void fs_irq (int irq, void *dev_id,  struct pt_regs * pt_regs) {	int i;	u32 status;	struct fs_dev *dev = dev_id;	status = read_fs (dev, ISR);	if (!status) return;	func_enter ();#ifdef IRQ_RATE_LIMIT	/* Aaargh! I'm ashamed. This costs more lines-of-code than the actual 	   interrupt routine!. (Well, used to when I wrote that comment) -- REW */	{		static int lastjif;		static int nintr=0;    		if (lastjif == jiffies) {			if (++nintr > IRQ_RATE_LIMIT) {				free_irq (dev->irq, dev_id);				printk (KERN_ERR "fs: Too many interrupts. Turning off interrupt %d.\n", 					dev->irq);			}		} else {			lastjif = jiffies;			nintr = 0;		}	}#endif	fs_dprintk (FS_DEBUG_QUEUE, "in intr: txq %d txrq %d\n", 		    read_fs (dev, Q_EA (dev->hp_txq.offset)) -		    read_fs (dev, Q_SA (dev->hp_txq.offset)),		    read_fs (dev, Q_EA (dev->tx_relq.offset)) -		    read_fs (dev, Q_SA (dev->tx_relq.offset)));	/* print the bits in the ISR register. */	if (fs_debug & FS_DEBUG_IRQ) {		/* The FS_DEBUG things are unneccesary here. But this way it is		   clear for grep that these are debug prints. */		fs_dprintk (FS_DEBUG_IRQ,  "IRQ status:");		for (i=0;i<27;i++) 			if (status & (1 << i)) 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -