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

📄 uli526x.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	ret = request_irq(dev->irq, &uli526x_interrupt, SA_SHIRQ, dev->name, dev);	if (ret)		return ret;	/* system variable init */	db->cr6_data = CR6_DEFAULT | uli526x_cr6_user_set;	db->tx_packet_cnt = 0;	db->rx_avail_cnt = 0;	db->link_failed = 1;	netif_carrier_off(dev);	db->wait_reset = 0;	db->NIC_capability = 0xf;	/* All capability*/	db->PHY_reg4 = 0x1e0;	/* CR6 operation mode decision */	db->cr6_data |= ULI526X_TXTH_256;	db->cr0_data = CR0_DEFAULT;		/* Initialize ULI526X board */	uli526x_init(dev);	/* Active System Interface */	netif_wake_queue(dev);	/* set and active a timer process */	init_timer(&db->timer);	db->timer.expires = ULI526X_TIMER_WUT + HZ * 2;	db->timer.data = (unsigned long)dev;	db->timer.function = &uli526x_timer;	add_timer(&db->timer);	return 0;}/*	Initialize ULI526X board *	Reset ULI526X board *	Initialize TX/Rx descriptor chain structure *	Send the set-up frame *	Enable Tx/Rx machine */static void uli526x_init(struct net_device *dev){	struct uli526x_board_info *db = netdev_priv(dev);	unsigned long ioaddr = db->ioaddr;	u8	phy_tmp;	u16	phy_value;	u16 phy_reg_reset;	ULI526X_DBUG(0, "uli526x_init()", 0);	/* Reset M526x MAC controller */	outl(ULI526X_RESET, ioaddr + DCR0);	/* RESET MAC */	udelay(100);	outl(db->cr0_data, ioaddr + DCR0);	udelay(5);	/* Phy addr : In some boards,M5261/M5263 phy address != 1 */	db->phy_addr = 1;	for(phy_tmp=0;phy_tmp<32;phy_tmp++)	{		phy_value=phy_read(db->ioaddr,phy_tmp,3,db->chip_id);//peer add		if(phy_value != 0xffff&&phy_value!=0)		{			db->phy_addr = phy_tmp;			break;		}	}	if(phy_tmp == 32)		printk(KERN_WARNING "Can not find the phy address!!!");	/* Parser SROM and media mode */	db->media_mode = uli526x_media_mode;	/* Phyxcer capability setting */	phy_reg_reset = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);	phy_reg_reset = (phy_reg_reset | 0x8000);	phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id);	udelay(500);	/* Process Phyxcer Media Mode */	uli526x_set_phyxcer(db);	/* Media Mode Process */	if ( !(db->media_mode & ULI526X_AUTO) )		db->op_mode = db->media_mode; 	/* Force Mode */	/* Initialize Transmit/Receive decriptor and CR3/4 */	uli526x_descriptor_init(db, ioaddr);	/* Init CR6 to program M526X operation */	update_cr6(db->cr6_data, ioaddr);	/* Send setup frame */	send_filter_frame(dev, dev->mc_count);	/* M5261/M5263 */	/* 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 ULI526X Tx/Rx function */	db->cr6_data |= CR6_RXSC | CR6_TXSC;	update_cr6(db->cr6_data, ioaddr);}/* *	Hardware start transmission. *	Send a packet to media from the upper layer. */static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct uli526x_board_info *db = netdev_priv(dev);	struct tx_desc *txptr;	unsigned long flags;	ULI526X_DBUG(0, "uli526x_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_packet_cnt >= TX_FREE_DESC_CNT) {		spin_unlock_irqrestore(&db->lock, flags);		printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_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_packet_cnt < TX_DESC_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 */	}	/* Tx resource check */	if ( db->tx_packet_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 uli526x_stop(struct net_device *dev){	struct uli526x_board_info *db = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	ULI526X_DBUG(0, "uli526x_stop", 0);	/* disable system */	netif_stop_queue(dev);	/* deleted timer */	del_timer_sync(&db->timer);	/* Reset & stop ULI526X board */	outl(ULI526X_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 */	uli526x_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;}/* *	M5261/M5263 insterrupt handler *	receive the packet to upper layer, free the transmitted packet */static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct uli526x_board_info *db = netdev_priv(dev);	unsigned long ioaddr = dev->base_addr;	unsigned long flags;	if (!dev) {		ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);		return IRQ_NONE;	}	spin_lock_irqsave(&db->lock, flags);	outl(0, ioaddr + DCR7);	/* Got ULI526X status */	db->cr5_data = inl(ioaddr + DCR5);	outl(db->cr5_data, ioaddr + DCR5);	if ( !(db->cr5_data & 0x180c1) ) {		spin_unlock_irqrestore(&db->lock, flags);		outl(db->cr7_data, ioaddr + DCR7);		return IRQ_HANDLED;	}	/* Check system status */	if (db->cr5_data & 0x2000) {		/* system bus error happen */		ULI526X_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 )		uli526x_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)		uli526x_free_tx_pkt(dev, db);	/* Restore CR7 to enable interrupt mask */	outl(db->cr7_data, ioaddr + DCR7);	spin_unlock_irqrestore(&db->lock, flags);	return IRQ_HANDLED;}/* *	Free TX resource after TX complete */static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_info * db){	struct tx_desc *txptr;	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;	/* Resource available check */	if ( db->tx_packet_cnt < TX_WAKE_DESC_CNT )		netif_wake_queue(dev);	/* Active upper layer, send again */}/* *	Receive the come packet and pass to upper layer */static void uli526x_rx_packet(struct net_device *dev, struct uli526x_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 */			ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0);			uli526x_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;						/* 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->tail, rxlen);					uli526x_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 */				ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0);				uli526x_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 * uli526x_get_stats(struct net_device *dev){	struct uli526x_board_info *db = netdev_priv(dev);	ULI526X_DBUG(0, "uli526x_get_stats", 0);	return &db->stats;}/* * Set ULI526X multicast address */static void uli526x_set_filter_mode(struct net_device * dev)

⌨️ 快捷键说明

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