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

📄 dmfe.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	db->rx_avail_cnt = 0;	db->link_failed = 1;	db->wait_reset = 0;	db->first_in_callback = 0;	db->NIC_capability = 0xf;	/* All capability*/	db->PHY_reg4 = 0x1e0;	/* CR6 operation mode decision */	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||		(db->chip_revision >= 0x02000030) ) {    		db->cr6_data |= DMFE_TXTH_256;		db->cr0_data = CR0_DEFAULT;		db->dm910x_chk_mode=4;		/* Enter the normal mode */ 	} else {		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */		db->cr0_data = 0;		db->dm910x_chk_mode = 1;	/* Enter the check mode */	}	/* Initilize DM910X board */	dmfe_init_dm910x(dev);	/* Active System Interface */	netif_wake_queue(dev);	/* set and active a timer process */	init_timer(&db->timer);	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;	db->timer.data = (unsigned long)dev;	db->timer.function = &dmfe_timer;	add_timer(&db->timer);	return 0;}/*	Initilize DM910X board *	Reset DM910X board *	Initilize TX/Rx descriptor chain structure *	Send the set-up frame *	Enable Tx/Rx machine */static void dmfe_init_dm910x(struct DEVICE *dev){	struct dmfe_board_info *db = netdev_priv(dev);	unsigned long ioaddr = db->ioaddr;	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);	/* Reset DM910x MAC controller */	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */	udelay(100);	outl(db->cr0_data, ioaddr + DCR0);	udelay(5);	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */	db->phy_addr = 1;	/* Parser SROM and media mode */	dmfe_parse_srom(db);	db->media_mode = dmfe_media_mode;	/* RESET Phyxcer Chip by GPR port bit 7 */	outl(0x180, ioaddr + DCR12);		/* Let bit 7 output port */	if (db->chip_id == PCI_DM9009_ID) {		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */		mdelay(300);			/* Delay 300 ms */	}	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */	/* Process Phyxcer Media Mode */	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */		dmfe_set_phyxcer(db);	/* Media Mode Process */	if ( !(db->media_mode & DMFE_AUTO) )		db->op_mode = db->media_mode; 	/* Force Mode */	/* Initiliaze Transmit/Receive decriptor and CR3/4 */	dmfe_descriptor_init(db, ioaddr);	/* Init CR6 to program DM910x operation */	update_cr6(db->cr6_data, ioaddr);	/* Send setup frame */	if (db->chip_id == PCI_DM9132_ID)		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */	else		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */	/* Init CR7, interrupt active bit */	db->cr7_data = CR7_DEFAULT;	outl(db->cr7_data, ioaddr + DCR7);	/* Init CR15, Tx jabber and Rx watchdog timer */	outl(db->cr15_data, ioaddr + DCR15);	/* Enable DM910X Tx/Rx function */	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;	update_cr6(db->cr6_data, ioaddr);}/* *	Hardware start transmission. *	Send a packet to media from the upper layer. */static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev){	struct dmfe_board_info *db = netdev_priv(dev);	struct tx_desc *txptr;	unsigned long flags;	DMFE_DBUG(0, "dmfe_start_xmit", 0);	/* Resource flag check */	netif_stop_queue(dev);	/* Too large packet check */	if (skb->len > MAX_PACKET_SIZE) {		printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);		dev_kfree_skb(skb);		return 0;	}	spin_lock_irqsave(&db->lock, flags);	/* No Tx resource check, it never happen nromally */	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {		spin_unlock_irqrestore(&db->lock, flags);		printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);		return 1;	}	/* Disable NIC interrupt */	outl(0, dev->base_addr + DCR7);	/* transmit this packet */	txptr = db->tx_insert_ptr;	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);	/* Point to next transmit free descriptor */	db->tx_insert_ptr = txptr->next_tx_desc;	/* Transmit Packet Process */	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */		db->tx_packet_cnt++;			/* Ready to send */		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */		dev->trans_start = jiffies;		/* saved time stamp */	} else {		db->tx_queue_cnt++;			/* queue TX packet */		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */	}	/* Tx resource check */	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )		netif_wake_queue(dev);	/* Restore CR7 to enable interrupt */	spin_unlock_irqrestore(&db->lock, flags);	outl(db->cr7_data, dev->base_addr + DCR7);	/* free this SKB */	dev_kfree_skb(skb);	return 0;}/* *	Stop the interface. *	The interface is stopped when it is brought. */static int dmfe_stop(struct DEVICE *dev){	struct dmfe_board_info *db = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	DMFE_DBUG(0, "dmfe_stop", 0);	/* disable system */	netif_stop_queue(dev);	/* deleted timer */	del_timer_sync(&db->timer);	/* Reset & stop DM910X board */	outl(DM910X_RESET, ioaddr + DCR0);	udelay(5);	phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);	/* free interrupt */	free_irq(dev->irq, dev);	/* free allocated rx buffer */	dmfe_free_rxbuffer(db);#if 0	/* show statistic counter */	printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",		db->tx_fifo_underrun, db->tx_excessive_collision,		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,		db->reset_fatal, db->reset_TXtimeout);#endif	return 0;}/* *	DM9102 insterrupt handler *	receive the packet to upper layer, free the transmitted packet */static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct DEVICE *dev = dev_id;	struct dmfe_board_info *db = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	unsigned long flags;	DMFE_DBUG(0, "dmfe_interrupt()", 0);	spin_lock_irqsave(&db->lock, flags);	/* Got DM910X status */	db->cr5_data = inl(ioaddr + DCR5);	outl(db->cr5_data, ioaddr + DCR5);	if ( !(db->cr5_data & 0xc1) ) {		spin_unlock_irqrestore(&db->lock, flags);		return IRQ_HANDLED;	}	/* Disable all interrupt in CR7 to solve the interrupt edge problem */	outl(0, ioaddr + DCR7);	/* Check system status */	if (db->cr5_data & 0x2000) {		/* system bus error happen */		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);		db->reset_fatal++;		db->wait_reset = 1;	/* Need to RESET */		spin_unlock_irqrestore(&db->lock, flags);		return IRQ_HANDLED;	}	 /* Received the coming packet */	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )		dmfe_rx_packet(dev, db);	/* reallocate rx descriptor buffer */	if (db->rx_avail_cnt<RX_DESC_CNT)		allocate_rx_buffer(db);	/* Free the transmitted descriptor */	if ( db->cr5_data & 0x01)		dmfe_free_tx_pkt(dev, db);	/* Mode Check */	if (db->dm910x_chk_mode & 0x2) {		db->dm910x_chk_mode = 0x4;		db->cr6_data |= 0x100;		update_cr6(db->cr6_data, db->ioaddr);	}	/* Restore CR7 to enable interrupt mask */	outl(db->cr7_data, ioaddr + DCR7);	spin_unlock_irqrestore(&db->lock, flags);	return IRQ_HANDLED;}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void poll_dmfe (struct net_device *dev){	/* disable_irq here is not very nice, but with the lockless	   interrupt handler we have no other choice. */	disable_irq(dev->irq);	dmfe_interrupt (dev->irq, dev, NULL);	enable_irq(dev->irq);}#endif/* *	Free TX resource after TX complete */static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db){	struct tx_desc *txptr;	unsigned long ioaddr = dev->base_addr;	u32 tdes0;	txptr = db->tx_remove_ptr;	while(db->tx_packet_cnt) {		tdes0 = le32_to_cpu(txptr->tdes0);		/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */		if (tdes0 & 0x80000000)			break;		/* A packet sent completed */		db->tx_packet_cnt--;		db->stats.tx_packets++;		/* Transmit statistic counter */		if ( tdes0 != 0x7fffffff ) {			/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */			db->stats.collisions += (tdes0 >> 3) & 0xf;			db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;			if (tdes0 & TDES0_ERR_MASK) {				db->stats.tx_errors++;				if (tdes0 & 0x0002) {	/* UnderRun */					db->tx_fifo_underrun++;					if ( !(db->cr6_data & CR6_SFT) ) {						db->cr6_data = db->cr6_data | CR6_SFT;						update_cr6(db->cr6_data, db->ioaddr);					}				}				if (tdes0 & 0x0100)					db->tx_excessive_collision++;				if (tdes0 & 0x0200)					db->tx_late_collision++;				if (tdes0 & 0x0400)					db->tx_no_carrier++;				if (tdes0 & 0x0800)					db->tx_loss_carrier++;				if (tdes0 & 0x4000)					db->tx_jabber_timeout++;			}		}    		txptr = txptr->next_tx_desc;	}/* End of while */	/* Update TX remove pointer to next */	db->tx_remove_ptr = txptr;	/* Send the Tx packet in queue */	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */		db->tx_packet_cnt++;			/* Ready to send */		db->tx_queue_cnt--;		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */		dev->trans_start = jiffies;		/* saved time stamp */	}	/* Resource available check */	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )		netif_wake_queue(dev);	/* Active upper layer, send again */}/* *	Calculate the CRC valude of the Rx packet *	flag = 	1 : return the reverse CRC (for the received packet CRC) *		0 : return the normal CRC (for Hash Table index) */static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag){	u32 crc = crc32(~0, Data, Len);	if (flag) crc = ~crc;	return crc;}/* *	Receive the come packet and pass to upper layer */static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db){	struct rx_desc *rxptr;	struct sk_buff *skb;	int rxlen;	u32 rdes0;	rxptr = db->rx_ready_ptr;	while(db->rx_avail_cnt) {		rdes0 = le32_to_cpu(rxptr->rdes0);		if (rdes0 & 0x80000000)	/* packet owner check */			break;		db->rx_avail_cnt--;		db->interval_rx_cnt++;		pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);		if ( (rdes0 & 0x300) != 0x300) {			/* A packet without First/Last flag */			/* reuse this SKB */			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);		} else {			/* A packet with First/Last flag */			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;			/* error summary bit check */			if (rdes0 & 0x8000) {				/* This is a error packet */				//printk(DRV_NAME ": rdes0: %lx\n", rdes0);				db->stats.rx_errors++;				if (rdes0 & 1)					db->stats.rx_fifo_errors++;				if (rdes0 & 2)					db->stats.rx_crc_errors++;				if (rdes0 & 0x80)					db->stats.rx_length_errors++;			}			if ( !(rdes0 & 0x8000) ||				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {				skb = rxptr->rx_skb_ptr;				/* Received Packet CRC check need or not */				if ( (db->dm910x_chk_mode & 1) &&					(cal_CRC(skb->data, rxlen, 1) !=					(*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */					/* Found a error received packet */					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);					db->dm910x_chk_mode = 3;				} else {					/* Good packet, send to upper layer */					/* Shorst packet used new SKB */					if ( (rxlen < RX_COPY_SIZE) &&						( (skb = dev_alloc_skb(rxlen + 2) )						!= NULL) ) {						/* size less than COPY_SIZE, allocate a rxlen SKB */						skb->dev = dev;						skb_reserve(skb, 2); /* 16byte align */						memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen);						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);					} else {						skb->dev = dev;						skb_put(skb, rxlen);					}					skb->protocol = eth_type_trans(skb, dev);					netif_rx(skb);					dev->last_rx = jiffies;					db->stats.rx_packets++;					db->stats.rx_bytes += rxlen;				}			} else {				/* Reuse SKB buffer when the packet is error */				DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);				dmfe_reuse_skb(db, rxptr->rx_skb_ptr);			}		}		rxptr = rxptr->next_rx_desc;	}	db->rx_ready_ptr = rxptr;}/* *	Get statistics from driver. */static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev){	struct dmfe_board_info *db = netdev_priv(dev);	DMFE_DBUG(0, "dmfe_get_stats", 0);	return &db->stats;}/* * Set DM910X multicast address */static void dmfe_set_filter_mode(struct DEVICE * dev){	struct dmfe_board_info *db = netdev_priv(dev);	unsigned long flags;	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);	spin_lock_irqsave(&db->lock, flags);	if (dev->flags & IFF_PROMISC) {		DMFE_DBUG(0, "Enable PROM Mode", 0);		db->cr6_data |= CR6_PM | CR6_PBF;		update_cr6(db->cr6_data, db->ioaddr);		spin_unlock_irqrestore(&db->lock, flags);		return;	}	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);		db->cr6_data &= ~(CR6_PM | CR6_PBF);		db->cr6_data |= CR6_PAM;		spin_unlock_irqrestore(&db->lock, flags);		return;	}	DMFE_DBUG(0, "Set multicast address", dev->mc_count);	if (db->chip_id == PCI_DM9132_ID)		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */	else

⌨️ 快捷键说明

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