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

📄 dscc4.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		    !dscc4_tx_done(dpriv))				dscc4_do_tx(dpriv, dev);		return;	}	loop++;	dpriv->iqtx[cur] = 0;	dpriv->iqtx_current++;	if (state_check(state, dpriv, dev, "Tx") < 0)		return;	if (state & SccEvt) {		if (state & Alls) {			struct net_device_stats *stats = hdlc_stats(dev);			struct sk_buff *skb;			struct TxFD *tx_fd;			if (debug > 2)				dscc4_tx_print(dev, dpriv, "Alls");			/*			 * DataComplete can't be trusted for Tx completion.			 * Cf errata DS5 p.8			 */			cur = dpriv->tx_dirty%TX_RING_SIZE;			tx_fd = dpriv->tx_fd + cur;			skb = dpriv->tx_skbuff[cur];			if (skb) {				pci_unmap_single(ppriv->pdev, tx_fd->data,						 skb->len, PCI_DMA_TODEVICE);				if (tx_fd->state & FrameEnd) {					stats->tx_packets++;					stats->tx_bytes += skb->len;				}				dev_kfree_skb_irq(skb);				dpriv->tx_skbuff[cur] = NULL;				++dpriv->tx_dirty;			} else {				if (debug > 1)					printk(KERN_ERR "%s Tx: NULL skb %d\n",						dev->name, cur);			}			/*			 * If the driver ends sending crap on the wire, it			 * will be way easier to diagnose than the (not so)			 * random freeze induced by null sized tx frames.			 */			tx_fd->data = tx_fd->next;			tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE);			tx_fd->complete = 0x00000000;			tx_fd->jiffies = 0;			if (!(state &= ~Alls))				goto try;		}		/*		 * Transmit Data Underrun		 */		if (state & Xdu) {			printk(KERN_ERR "%s: XDU. Ask maintainer\n", DRV_NAME);			dpriv->flags = NeedIDT;			/* Tx reset */			writel(MTFi | Rdt,			       dpriv->base_addr + 0x0c*dpriv->dev_id + CH0CFG);			writel(Action, dpriv->base_addr + GCMDR);			return;		}		if (state & Cts) {			printk(KERN_INFO "%s: CTS transition\n", dev->name);			if (!(state &= ~Cts)) /* DEBUG */				goto try;		}		if (state & Xmr) {			/* Frame needs to be sent again - FIXME */			printk(KERN_ERR "%s: Xmr. Ask maintainer\n", DRV_NAME);			if (!(state &= ~Xmr)) /* DEBUG */				goto try;		}		if (state & Xpr) {			void __iomem *scc_addr;			unsigned long ring;			int i;			/*			 * - the busy condition happens (sometimes);			 * - it doesn't seem to make the handler unreliable.			 */			for (i = 1; i; i <<= 1) {				if (!(scc_readl_star(dpriv, dev) & SccBusy))					break;			}			if (!i)				printk(KERN_INFO "%s busy in irq\n", dev->name);			scc_addr = dpriv->base_addr + 0x0c*dpriv->dev_id;			/* Keep this order: IDT before IDR */			if (dpriv->flags & NeedIDT) {				if (debug > 2)					dscc4_tx_print(dev, dpriv, "Xpr");				ring = dpriv->tx_fd_dma +				       (dpriv->tx_dirty%TX_RING_SIZE)*				       sizeof(struct TxFD);				writel(ring, scc_addr + CH0BTDA);				dscc4_do_tx(dpriv, dev);				writel(MTFi | Idt, scc_addr + CH0CFG);				if (dscc4_do_action(dev, "IDT") < 0)					goto err_xpr;				dpriv->flags &= ~NeedIDT;			}			if (dpriv->flags & NeedIDR) {				ring = dpriv->rx_fd_dma +				       (dpriv->rx_current%RX_RING_SIZE)*				       sizeof(struct RxFD);				writel(ring, scc_addr + CH0BRDA);				dscc4_rx_update(dpriv, dev);				writel(MTFi | Idr, scc_addr + CH0CFG);				if (dscc4_do_action(dev, "IDR") < 0)					goto err_xpr;				dpriv->flags &= ~NeedIDR;				smp_wmb();				/* Activate receiver and misc */				scc_writel(0x08050008, dpriv, dev, CCR2);			}		err_xpr:			if (!(state &= ~Xpr))				goto try;		}		if (state & Cd) {			if (debug > 0)				printk(KERN_INFO "%s: CD transition\n", dev->name);			if (!(state &= ~Cd)) /* DEBUG */				goto try;		}	} else { /* ! SccEvt */		if (state & Hi) {#ifdef DSCC4_POLLING			while (!dscc4_tx_poll(dpriv, dev));#endif			printk(KERN_INFO "%s: Tx Hi\n", dev->name);			state &= ~Hi;		}		if (state & Err) {			printk(KERN_INFO "%s: Tx ERR\n", dev->name);			hdlc_stats(dev)->tx_errors++;			state &= ~Err;		}	}	goto try;}static void dscc4_rx_irq(struct dscc4_pci_priv *priv,				    struct dscc4_dev_priv *dpriv){	struct net_device *dev = dscc4_to_dev(dpriv);	u32 state;	int cur;try:	cur = dpriv->iqrx_current%IRQ_RING_SIZE;	state = dpriv->iqrx[cur];	if (!state)		return;	dpriv->iqrx[cur] = 0;	dpriv->iqrx_current++;	if (state_check(state, dpriv, dev, "Rx") < 0)		return;	if (!(state & SccEvt)){		struct RxFD *rx_fd;		if (debug > 4)			printk(KERN_DEBUG "%s: Rx ISR = 0x%08x\n", dev->name,			       state);		state &= 0x00ffffff;		if (state & Err) { /* Hold or reset */			printk(KERN_DEBUG "%s: Rx ERR\n", dev->name);			cur = dpriv->rx_current%RX_RING_SIZE;			rx_fd = dpriv->rx_fd + cur;			/*			 * Presume we're not facing a DMAC receiver reset.			 * As We use the rx size-filtering feature of the			 * DSCC4, the beginning of a new frame is waiting in			 * the rx fifo. I bet a Receive Data Overflow will			 * happen most of time but let's try and avoid it.			 * Btw (as for RDO) if one experiences ERR whereas			 * the system looks rather idle, there may be a			 * problem with latency. In this case, increasing			 * RX_RING_SIZE may help.			 */			//while (dpriv->rx_needs_refill) {				while (!(rx_fd->state1 & Hold)) {					rx_fd++;					cur++;					if (!(cur = cur%RX_RING_SIZE))						rx_fd = dpriv->rx_fd;				}				//dpriv->rx_needs_refill--;				try_get_rx_skb(dpriv, dev);				if (!rx_fd->data)					goto try;				rx_fd->state1 &= ~Hold;				rx_fd->state2 = 0x00000000;				rx_fd->end = 0xbabeface;			//}			goto try;		}		if (state & Fi) {			dscc4_rx_skb(dpriv, dev);			goto try;		}		if (state & Hi ) { /* HI bit */			printk(KERN_INFO "%s: Rx Hi\n", dev->name);			state &= ~Hi;			goto try;		}	} else { /* SccEvt */		if (debug > 1) {			//FIXME: verifier la presence de tous les evenements		static struct {			u32 mask;			const char *irq_name;		} evts[] = {			{ 0x00008000, "TIN"},			{ 0x00000020, "RSC"},			{ 0x00000010, "PCE"},			{ 0x00000008, "PLLA"},			{ 0, NULL}		}, *evt;		for (evt = evts; evt->irq_name; evt++) {			if (state & evt->mask) {					printk(KERN_DEBUG "%s: %s\n",						dev->name, evt->irq_name);				if (!(state &= ~evt->mask))					goto try;			}		}		} else {			if (!(state &= ~0x0000c03c))				goto try;		}		if (state & Cts) {			printk(KERN_INFO "%s: CTS transition\n", dev->name);			if (!(state &= ~Cts)) /* DEBUG */				goto try;		}		/*		 * Receive Data Overflow (FIXME: fscked)		 */		if (state & Rdo) {			struct RxFD *rx_fd;			void __iomem *scc_addr;			int cur;			//if (debug)			//	dscc4_rx_dump(dpriv);			scc_addr = dpriv->base_addr + 0x0c*dpriv->dev_id;			scc_patchl(RxActivate, 0, dpriv, dev, CCR2);			/*			 * This has no effect. Why ?			 * ORed with TxSccRes, one sees the CFG ack (for			 * the TX part only).			 */			scc_writel(RxSccRes, dpriv, dev, CMDR);			dpriv->flags |= RdoSet;			/*			 * Let's try and save something in the received data.			 * rx_current must be incremented at least once to			 * avoid HOLD in the BRDA-to-be-pointed desc.			 */			do {				cur = dpriv->rx_current++%RX_RING_SIZE;				rx_fd = dpriv->rx_fd + cur;				if (!(rx_fd->state2 & DataComplete))					break;				if (rx_fd->state2 & FrameAborted) {					hdlc_stats(dev)->rx_over_errors++;					rx_fd->state1 |= Hold;					rx_fd->state2 = 0x00000000;					rx_fd->end = 0xbabeface;				} else					dscc4_rx_skb(dpriv, dev);			} while (1);			if (debug > 0) {				if (dpriv->flags & RdoSet)					printk(KERN_DEBUG					       "%s: no RDO in Rx data\n", DRV_NAME);			}#ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY			/*			 * FIXME: must the reset be this violent ?			 */#warning "FIXME: CH0BRDA"			writel(dpriv->rx_fd_dma +			       (dpriv->rx_current%RX_RING_SIZE)*			       sizeof(struct RxFD), scc_addr + CH0BRDA);			writel(MTFi|Rdr|Idr, scc_addr + CH0CFG);			if (dscc4_do_action(dev, "RDR") < 0) {				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",				       dev->name, "RDR");				goto rdo_end;			}			writel(MTFi|Idr, scc_addr + CH0CFG);			if (dscc4_do_action(dev, "IDR") < 0) {				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",				       dev->name, "IDR");				goto rdo_end;			}		rdo_end:#endif			scc_patchl(0, RxActivate, dpriv, dev, CCR2);			goto try;		}		if (state & Cd) {			printk(KERN_INFO "%s: CD transition\n", dev->name);			if (!(state &= ~Cd)) /* DEBUG */				goto try;		}		if (state & Flex) {			printk(KERN_DEBUG "%s: Flex. Ttttt...\n", DRV_NAME);			if (!(state &= ~Flex))				goto try;		}	}}/* * I had expected the following to work for the first descriptor * (tx_fd->state = 0xc0000000) * - Hold=1 (don't try and branch to the next descripto); * - No=0 (I want an empty data section, i.e. size=0); * - Fe=1 (required by No=0 or we got an Err irq and must reset). * It failed and locked solid. Thus the introduction of a dummy skb. * Problem is acknowledged in errata sheet DS5. Joy :o/ */static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv){	struct sk_buff *skb;	skb = dev_alloc_skb(DUMMY_SKB_SIZE);	if (skb) {		int last = dpriv->tx_dirty%TX_RING_SIZE;		struct TxFD *tx_fd = dpriv->tx_fd + last;		skb->len = DUMMY_SKB_SIZE;		memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE);		tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE);		tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,					     DUMMY_SKB_SIZE, PCI_DMA_TODEVICE);		dpriv->tx_skbuff[last] = skb;	}	return skb;}static int dscc4_init_ring(struct net_device *dev){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	struct pci_dev *pdev = dpriv->pci_priv->pdev;	struct TxFD *tx_fd;	struct RxFD *rx_fd;	void *ring;	int i;	ring = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &dpriv->rx_fd_dma);	if (!ring)		goto err_out;	dpriv->rx_fd = rx_fd = (struct RxFD *) ring;	ring = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &dpriv->tx_fd_dma);	if (!ring)		goto err_free_dma_rx;	dpriv->tx_fd = tx_fd = (struct TxFD *) ring;	memset(dpriv->tx_skbuff, 0, sizeof(struct sk_buff *)*TX_RING_SIZE);	dpriv->tx_dirty = 0xffffffff;	i = dpriv->tx_current = 0;	do {		tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE);		tx_fd->complete = 0x00000000;	        /* FIXME: NULL should be ok - to be tried */	        tx_fd->data = dpriv->tx_fd_dma;		(tx_fd++)->next = (u32)(dpriv->tx_fd_dma +					(++i%TX_RING_SIZE)*sizeof(*tx_fd));	} while (i < TX_RING_SIZE);	if (dscc4_init_dummy_skb(dpriv) < 0)		goto err_free_dma_tx;	memset(dpriv->rx_skbuff, 0, sizeof(struct sk_buff *)*RX_RING_SIZE);	i = dpriv->rx_dirty = dpriv->rx_current = 0;	do {		/* size set by the host. Multiple of 4 bytes please */	        rx_fd->state1 = HiDesc;	        rx_fd->state2 = 0x00000000;	        rx_fd->end = 0xbabeface;	        rx_fd->state1 |= TO_STATE_RX(HDLC_MAX_MRU);		// FIXME: return value verifiee mais traitement suspect		if (try_get_rx_skb(dpriv, dev) >= 0)			dpriv->rx_dirty++;		(rx_fd++)->next = (u32)(dpriv->rx_fd_dma +					(++i%RX_RING_SIZE)*sizeof(*rx_fd));	} while (i < RX_RING_SIZE);	return 0;err_free_dma_tx:	pci_free_consistent(pdev, TX_TOTAL_SIZE, ring, dpriv->tx_fd_dma);err_free_dma_rx:	pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);err_out:	return -ENOMEM;}static void __devexit dscc4_remove_one(struct pci_dev *pdev){	struct dscc4_pci_priv *ppriv;	struct dscc4_dev_priv *root;	void __iomem *ioaddr;	int i;	ppriv = pci_get_drvdata(pdev);	root = ppriv->root;	ioaddr = root->base_addr;	dscc4_pci_reset(pdev, ioaddr);	free_irq(pdev->irq, root);	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg,			    ppriv->iqcfg_dma);	for (i = 0; i < dev_per_card; i++) {		struct dscc4_dev_priv *dpriv = root + i;		dscc4_release_ring(dpriv);		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),				    dpriv->iqrx, dpriv->iqrx_dma);		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),				    dpriv->iqtx, dpriv->iqtx_dma);	}	dscc4_free1(pdev);	iounmap(ioaddr);	pci_release_region(pdev, 1);	pci_release_region(pdev, 0);	pci_disable_device(pdev);}static int dscc4_hdlc_attach(struct net_device *dev, unsigned short encoding,	unsigned short parity){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	if (encoding != ENCODING_NRZ &&	    encoding != ENCODING_NRZI &&	    encoding != ENCODING_FM_MARK &&	    encoding != ENCODING_FM_SPACE &&	    encoding != ENCODING_MANCHESTER)		return -EINVAL;	if (parity != PARITY_NONE &&	    parity != PARITY_CRC16_PR0_CCITT &&	    parity != PARITY_CRC16_PR1_CCITT &&	    parity != PARITY_CRC32_PR0_CCITT &&	    parity != PARITY_CRC32_PR1_CCITT)		return -EINVAL;        dpriv->encoding = encoding;        dpriv->parity = parity;	return 0;}#ifndef MODULEstatic int __init dscc4_setup(char *str){	int *args[] = { &debug, &quartz, NULL }, **p = args;	while (*p && (get_option(&str, *p) == 2))		p++;	return 1;}__setup("dscc4.setup=", dscc4_setup);#endifstatic struct pci_device_id dscc4_pci_tbl[] = {	{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,	        PCI_ANY_ID, PCI_ANY_ID, },	{ 0,}};MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl);static struct pci_driver dscc4_driver = {	.name		= DRV_NAME,	.id_table	= dscc4_pci_tbl,	.probe		= dscc4_init_one,	.remove		= __devexit_p(dscc4_remove_one),};static int __init dscc4_init_module(void){	return pci_module_init(&dscc4_driver);}static void __exit dscc4_cleanup_module(void){	pci_unregister_driver(&dscc4_driver);}module_init(dscc4_init_module);module_exit(dscc4_cleanup_module);

⌨️ 快捷键说明

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