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

📄 dscc4.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
			dev_kfree_skb(*skbuff);		}		skbuff++;		rx_fd++;	}}inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev){	unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;	struct RxFD *rx_fd = dpriv->rx_fd + dirty;	const int len = RX_MAX(HDLC_MAX_MRU);	struct sk_buff *skb;	int ret = 0;	skb = dev_alloc_skb(len);	dpriv->rx_skbuff[dirty] = skb;	if (skb) {	skb->dev = dev;		skb->protocol = htons(ETH_P_HDLC);	skb->mac.raw = skb->data;		rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,					     len, PCI_DMA_FROMDEVICE);	} else {		rx_fd->data = (u32) NULL;		ret = -1;	}	return ret;}/* * IRQ/thread/whatever safe */static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,			      struct net_device *dev, char *msg){	s8 i = 0;	do {		if (!(scc_readl_star(dpriv, dev) & SccBusy)) {			printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name,			       msg, i);			goto done;		}		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(10);		rmb();	} while (++i > 0);	printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);done:	return (i >= 0) ? i : -EAGAIN;}static int dscc4_do_action(struct net_device *dev, char *msg){	unsigned long ioaddr = dev->base_addr;	s16 i = 0;	writel(Action, ioaddr + GCMDR);	ioaddr += GSTAR;	do {		u32 state = readl(ioaddr);		if (state & ArAck) {			printk(KERN_DEBUG "%s: %s ack\n", dev->name, msg);			writel(ArAck, ioaddr);			goto done;		} else if (state & Arf) {			printk(KERN_ERR "%s: %s failed\n", dev->name, msg);			writel(Arf, ioaddr);			i = -1;			goto done;	}		rmb();	} while (++i > 0);	printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);done:	return i;}static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv){	int cur = dpriv->iqtx_current%IRQ_RING_SIZE;	s8 i = 0;	do {		if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||		    (dpriv->iqtx[cur] & Xpr))			break;		smp_rmb();		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(10);	} while (++i > 0);	return (i >= 0 ) ? i : -EAGAIN;}/* Requires protection against interrupt */static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev){	/* Cf errata DS5 p.6 */	writel(0x00000000, dev->base_addr + CH0LRDA + dpriv->dev_id*4);	scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0);	readl(dev->base_addr + CH0LRDA + dpriv->dev_id*4);	writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);	writel(Action, dev->base_addr + GCMDR);}static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev){	u16 i = 0;	/* Cf errata DS5 p.7 */	scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0);	scc_writel(0x00050000, dpriv, dev, CCR2);	/*	 * Must be longer than the time required to fill the fifo.	 */	while (!dscc4_tx_quiescent(dpriv, dev) && ++i) {		udelay(1);		wmb();	}	writel(MTFi|Rdt, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);	if (dscc4_do_action(dev, "Rdt") < 0)		printk(KERN_ERR "%s: Tx reset failed\n", dev->name);}/* TODO: (ab)use this function to refill a completely depleted RX ring. */static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,				struct net_device *dev){	struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE;	struct net_device_stats *stats = &dpriv->hdlc.stats;	struct pci_dev *pdev = dpriv->pci_priv->pdev;	struct sk_buff *skb;	int pkt_len;	skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE];	if (!skb) {		printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__);		goto refill;	}	pkt_len = TO_SIZE(rx_fd->state2);	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);	pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);	if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {		stats->rx_packets++;		stats->rx_bytes += pkt_len;		skb_put(skb, pkt_len);		skb->dev->last_rx = jiffies;		netif_rx(skb);	} else {		if (skb->data[pkt_len] & FrameRdo)			stats->rx_fifo_errors++;		else if (!(skb->data[pkt_len] | ~FrameCrc))			stats->rx_crc_errors++;		else if (!(skb->data[pkt_len] | ~(FrameVfr | FrameRab)))			stats->rx_length_errors++;		else			stats->rx_errors++;		dev_kfree_skb_irq(skb);	}refill:	while ((dpriv->rx_dirty - dpriv->rx_current) % RX_RING_SIZE) {		if (try_get_rx_skb(dpriv, dev) < 0)			break;		dpriv->rx_dirty++;	}	dscc4_rx_update(dpriv, dev);	rx_fd->state2 = 0x00000000;	rx_fd->end = 0xbabeface;}static void dscc4_free1(struct pci_dev *pdev){	struct dscc4_pci_priv *ppriv;	struct dscc4_dev_priv *root;	int i;	ppriv = pci_get_drvdata(pdev);	root = ppriv->root;	for (i = 0; i < dev_per_card; i++)		unregister_hdlc_device(&root[i].hdlc);	pci_set_drvdata(pdev, NULL);	kfree(root);	kfree(ppriv);}static int __init dscc4_init_one(struct pci_dev *pdev,				  const struct pci_device_id *ent){	struct dscc4_pci_priv *priv;	struct dscc4_dev_priv *dpriv;	static int cards_found = 0;	unsigned long ioaddr;	int i;	printk(KERN_DEBUG "%s", version);	if (pci_enable_device(pdev))		goto err_out;	if (!request_mem_region(pci_resource_start(pdev, 0),	                	pci_resource_len(pdev, 0), "registers")) {	        printk(KERN_ERR "%s: can't reserve MMIO region (regs)\n",			DRV_NAME);	        goto err_out;	}	if (!request_mem_region(pci_resource_start(pdev, 1),	                        pci_resource_len(pdev, 1), "LBI interface")) {	        printk(KERN_ERR "%s: can't reserve MMIO region (lbi)\n",			DRV_NAME);	        goto err_out_free_mmio_region0;	}	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),					pci_resource_len(pdev, 0));	if (!ioaddr) {		printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n",			DRV_NAME, pci_resource_len(pdev, 0),			pci_resource_start(pdev, 0));		goto err_out_free_mmio_region;	}	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",	        pci_resource_start(pdev, 0),	        pci_resource_start(pdev, 1), pdev->irq);	/* Cf errata DS5 p.2 */	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);	pci_set_master(pdev);	if (dscc4_found1(pdev, ioaddr))	        goto err_out_iounmap;	priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev);	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, DRV_NAME, priv->root)){		printk(KERN_WARNING "%s: IRQ %d busy\n", DRV_NAME, pdev->irq);		goto err_out_free1;	}	/* power up/little endian/dma core controlled via lrda/ltda */	writel(0x00000001, ioaddr + GMODE);	/* Shared interrupt queue */	{		u32 bits;		bits = (IRQ_RING_SIZE >> 5) - 1;		bits |= bits << 4;		bits |= bits << 8;		bits |= bits << 16;		writel(bits, ioaddr + IQLENR0);	}	/* Global interrupt queue */	writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1);	priv->iqcfg = (u32 *) pci_alloc_consistent(pdev,		IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma);	if (!priv->iqcfg)		goto err_out_free_irq;	writel(priv->iqcfg_dma, ioaddr + IQCFG);	/*	 * SCC 0-3 private rx/tx irq structures	 * IQRX/TXi needs to be set soon. Learned it the hard way...	 */	for (i = 0; i < dev_per_card; i++) {		dpriv = priv->root + i;		dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);		if (!dpriv->iqtx)			goto err_out_free_iqtx;		writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);	}	for (i = 0; i < dev_per_card; i++) {		dpriv = priv->root + i;		dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);		if (!dpriv->iqrx)			goto err_out_free_iqrx;		writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4);	}	/* Cf application hint. Beware of hard-lock condition on threshold. */	writel(0x42104000, ioaddr + FIFOCR1);	//writel(0x9ce69800, ioaddr + FIFOCR2);	writel(0xdef6d800, ioaddr + FIFOCR2);	//writel(0x11111111, ioaddr + FIFOCR4);	writel(0x18181818, ioaddr + FIFOCR4);	// FIXME: should depend on the chipset revision	writel(0x0000000e, ioaddr + FIFOCR3);	writel(0xff200001, ioaddr + GCMDR);	cards_found++;	return 0;err_out_free_iqrx:	while (--i >= 0) {		dpriv = priv->root + i;		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),				    dpriv->iqrx, dpriv->iqrx_dma);	}	i = dev_per_card;err_out_free_iqtx:	while (--i >= 0) {		dpriv = priv->root + i;		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),				    dpriv->iqtx, dpriv->iqtx_dma);	}	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg,			    priv->iqcfg_dma);err_out_free_irq:	free_irq(pdev->irq, priv->root);err_out_free1:	dscc4_free1(pdev);err_out_iounmap:	iounmap ((void *)ioaddr);err_out_free_mmio_region:	release_mem_region(pci_resource_start(pdev, 1),			   pci_resource_len(pdev, 1));err_out_free_mmio_region0:	release_mem_region(pci_resource_start(pdev, 0),			   pci_resource_len(pdev, 0));err_out:	return -ENODEV;};/* * Let's hope the default values are decent enough to protect my * feet from the user's gun - Ueimor */static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,				 struct net_device *dev){	scc_writel(0x80001000, dpriv, dev, CCR0);	scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR);	/*	 * No address recognition/crc-CCITT/cts enabled	 * Shared flags transmission disabled - cf errata DS5 p.11	 * Carrier detect disabled - cf errata p.14	 */	scc_writel(0x021c8000, dpriv, dev, CCR1);	/* crc not forwarded - Cf errata DS5 p.11 */	scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2);	// crc forwarded	//scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2);	/* Don't mask RDO. Ever. */#ifdef DSCC4_POLLING	scc_writel(0xfffeef7f, dpriv, dev, IMR); /* Interrupt mask */#else	//scc_writel(0xfffaef7f, dpriv, dev, IMR); /* Interrupt mask */	//scc_writel(0xfffaef7e, dpriv, dev, IMR); /* Interrupt mask */	scc_writel(0xfffa8f7a, dpriv, dev, IMR); /* Interrupt mask */#endif}static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr){	struct dscc4_pci_priv *ppriv;	struct dscc4_dev_priv *root;	int i = 0;	root = (struct dscc4_dev_priv *)		kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);	if (!root) {		printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);		goto err_out;	}	memset(root, 0, dev_per_card*sizeof(*root));	ppriv = (struct dscc4_pci_priv *) kmalloc(sizeof(*ppriv), GFP_KERNEL);	if (!ppriv) {		printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);		goto err_free_dev;	}	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));	for (i = 0; i < dev_per_card; i++) {		struct dscc4_dev_priv *dpriv = root + i;		hdlc_device *hdlc = &dpriv->hdlc;		struct net_device *d = hdlc_to_dev(hdlc);	        d->base_addr = ioaddr;		d->init = NULL;	        d->irq = pdev->irq;	        d->open = dscc4_open;	        d->stop = dscc4_close;		d->set_multicast_list = NULL;	        d->do_ioctl = dscc4_ioctl;		d->tx_timeout = dscc4_tx_timeout;		d->watchdog_timeo = TX_TIMEOUT;		dpriv->dev_id = i;		dpriv->pci_priv = ppriv;		spin_lock_init(&dpriv->lock);		hdlc->xmit = dscc4_start_xmit;		hdlc->attach = dscc4_hdlc_attach;	        if (register_hdlc_device(hdlc)) {			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);			goto err_unregister;	        }		hdlc->proto = IF_PROTO_HDLC;		SET_MODULE_OWNER(d);		dscc4_init_registers(dpriv, d);		dpriv->parity = PARITY_CRC16_PR0_CCITT;		dpriv->encoding = ENCODING_NRZ;	}	if (dscc4_set_quartz(root, quartz) < 0)		goto err_unregister;	ppriv->root = root;	spin_lock_init(&ppriv->lock);	pci_set_drvdata(pdev, ppriv);	return 0;err_unregister:	while (--i >= 0)		unregister_hdlc_device(&root[i].hdlc);	kfree(ppriv);err_free_dev:	kfree(root);err_out:	return -1;};/* FIXME: get rid of the unneeded code */static void dscc4_timer(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);//	struct dscc4_pci_priv *ppriv;	goto done;done:        dpriv->timer.expires = jiffies + TX_TIMEOUT;        add_timer(&dpriv->timer);}static void dscc4_tx_timeout(struct net_device *dev){	/* FIXME: something is missing there */}static int dscc4_loopback_check(struct dscc4_dev_priv *dpriv){	sync_serial_settings *settings = &dpriv->settings;	if (settings->loopback && (settings->clock_type != CLOCK_INT)) {		struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);		printk(KERN_INFO "%s: loopback requires clock\n", dev->name);		return -1;	}	return 0;}static int dscc4_open(struct net_device *dev){	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);	hdlc_device *hdlc = &dpriv->hdlc;	struct dscc4_pci_priv *ppriv;	int ret = -EAGAIN;	if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit)

⌨️ 快捷键说明

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