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

📄 dmfe.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Reset DM910x board : need 32 PCI clock to complete */	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */	DELAY_5US;	outl(db->cr0_data, ioaddr + DCR0);	outl(0x180, ioaddr + DCR12);	/* Let bit 7 output port */	outl(0x80, ioaddr + DCR12);	/* RESET DM9102 phyxcer */	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */	db->phy_addr = 1;	/* Media Mode Check */	db->media_mode = dmfe_media_mode;	if (db->media_mode & DMFE_AUTO)		dmfe_sense_speed(db);	else		db->op_mode = db->media_mode;	dmfe_process_mode(db);	/* 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 CR5/CR7, interrupt active bit */	outl(0xffffffff, ioaddr + DCR5);	/* clear all CR5 status */	db->cr7_data = CR7_DEFAULT;	outl(db->cr7_data, ioaddr + DCR7);	/* Init CR15, Tx jabber and Rx watchdog timer */	db->cr15_data = CR15_DEFAULT;	outl(db->cr15_data, ioaddr + DCR15);	/* Enable DM910X 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 dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct dmfe_board_info *db = dev->priv;	struct tx_desc *txptr;	DMFE_DBUG(0, "dmfe_start_xmit", 0); 	netif_stop_queue(dev);		/* Too large packet check */	if (skb->len > MAX_PACKET_SIZE) {		printk(KERN_ERR "%s: oversized frame (%d bytes) for transmit.\n", dev->name, (u16) skb->len);		dev_kfree_skb(skb);		return 0;	}	/* No Tx resource check, it never happen nromally */	if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {		return 1;	}	/* transmit this packet */	txptr = db->tx_insert_ptr;	memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);	txptr->tdes1 = 0xe1000000 | skb->len;	/* Point to next transmit free descriptor */	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;	/* Transmit Packet Process */	if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {		txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */		db->tx_packet_cnt++;	/* Ready to send count */		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling comand */	} else {		db->tx_queue_cnt++;	/* queue the tx packet */		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling comand */	}	/* Tx resource check */	if (db->tx_packet_cnt < TX_FREE_DESC_CNT)		netif_wake_queue(dev);	/* 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 net_device *dev){	struct dmfe_board_info *db = dev->priv;	u32 ioaddr = dev->base_addr;	DMFE_DBUG(0, "dmfe_stop", 0);	netif_stop_queue(dev);	/* Reset & stop DM910X board */	outl(DM910X_RESET, ioaddr + DCR0);	DELAY_5US;	/* deleted timer */	del_timer_sync(&db->timer);	/* free interrupt */	free_irq(dev->irq, dev);	/* free allocated rx buffer */	dmfe_free_rxbuffer(db);	/* free all descriptor memory and buffer memory */	kfree(db->desc_pool_ptr);	kfree(db->buf_pool_ptr);	return 0;}/*   DM9102 insterrupt handler   receive the packet to upper layer, free the transmitted packet */static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct tx_desc *txptr;	struct dmfe_board_info *db;	u32 ioaddr;	if (!dev) {		DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);		return;	}	/* A real interrupt coming */	db = (struct dmfe_board_info *) dev->priv;	ioaddr = dev->base_addr;	DMFE_DBUG(0, "dmfe_interrupt()", 0);	/* Disable all interrupt in CR7 to solve the interrupt edge problem */	outl(0, ioaddr + DCR7);	/* Got DM910X status */	db->cr5_data = inl(ioaddr + DCR5);	outl(db->cr5_data, ioaddr + DCR5);	/* printk("CR5=%x\n", db->cr5_data); */	/* Check system status */	if (db->cr5_data & 0x2000) {		/* A system bus error occurred */		DMFE_DBUG(1, "A system bus error occurred. CR5=", db->cr5_data);		netif_stop_queue(dev);		db->wait_reset = 1;		/* Need to RESET */		outl(0, ioaddr + DCR7);		/* disable all interrupt */		return;	}	/* Free the transmitted descriptor */	txptr = db->tx_remove_ptr;	while (db->tx_packet_cnt) {		/* printk("tdes0=%x\n", txptr->tdes0); */		if (txptr->tdes0 & 0x80000000)			break;		db->stats.tx_packets++;				if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) {			/* printk("tdes0=%x\n", txptr->tdes0); */			db->stats.tx_errors++;		}		/* Transmit statistic counter */		if (txptr->tdes0 != 0x7fffffff) { 			/* printk("tdes0=%x\n", txptr->tdes0); */ 			db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;			db->stats.tx_bytes += txptr->tdes1 & 0x7ff;			if (txptr->tdes0 & TDES0_ERR_MASK)				db->stats.tx_errors++;		}		txptr = (struct tx_desc *) txptr->next_tx_desc;		db->tx_packet_cnt--;	}	/* Update TX remove pointer to next */	db->tx_remove_ptr = (struct tx_desc *) txptr;	/* Send the Tx packet in queue */	if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) {		txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */		db->tx_packet_cnt++;	/* Ready to send count */		outl(0x1, ioaddr + DCR1);	/* Issue Tx polling command */		dev->trans_start = jiffies;	/* saved the time stamp */		db->tx_queue_cnt--; 	}	/* Resource available check */	if (db->tx_packet_cnt < TX_FREE_DESC_CNT)		netif_wake_queue(dev);	/* Received the coming packet */	if (db->rx_avail_cnt)		dmfe_rx_packet(dev, db);	/* reallocated rx descriptor buffer */	if (db->rx_avail_cnt < RX_DESC_CNT)		allocated_rx_buffer(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 */	if (db->interval_rx_cnt > RX_MAX_TRAFFIC)		db->cr7_data = 0x1a28d;	else		db->cr7_data = 0x1a2cd;	outl(db->cr7_data, ioaddr + DCR7);}/*   Receive the come packet and pass to upper layer */static void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db){	struct rx_desc *rxptr;	struct sk_buff *skb;	int rxlen;	rxptr = db->rx_ready_ptr;	while (db->rx_avail_cnt) {		if (rxptr->rdes0 & 0x80000000)	/* packet owner check */			break;		db->rx_avail_cnt--;		db->interval_rx_cnt++;		if ((rxptr->rdes0 & 0x300) != 0x300) {			/* A packet without First/Last flag */			/* reused this SKB */			DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);			dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);			/* db->rx_error_cnt++; */		} else {			/* A packet with First/Last flag */			rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4;	/* skip CRC */			if (rxptr->rdes0 & 0x8000) {	/* error summary bit check */				/* This is a error packet */				/* printk("rdes0 error : %x \n", rxptr->rdes0); */				db->stats.rx_errors++;				if (rxptr->rdes0 & 1)					db->stats.rx_fifo_errors++;				if (rxptr->rdes0 & 2)					db->stats.rx_crc_errors++;				if (rxptr->rdes0 & 0x80)					db->stats.rx_length_errors++;			}			if (!(rxptr->rdes0 & 0x8000) ||			    ((db->cr6_data & CR6_PM) && (rxlen > 6))) {				skb = (struct sk_buff *) rxptr->rx_skb_ptr;				/* Received Packet CRC check need or not */				if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != (*(unsigned long *) (skb->tail + rxlen)))) {					/* Found a error received packet */					dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);					db->dm910x_chk_mode = 3;				} else {					/* A good packet coming, send to upper layer */					skb->dev = dev;					skb_put(skb, rxlen);					skb->protocol = eth_type_trans(skb, dev);					netif_rx(skb);	/* Send to upper layer */					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, "Reused SK buffer, rdes0", rxptr->rdes0);				dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);			}		}		rxptr = (struct rx_desc *) rxptr->next_rx_desc;	}	db->rx_ready_ptr = rxptr;}/*   Get statistics from driver. */static struct net_device_stats *dmfe_get_stats(struct net_device *dev){	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;	DMFE_DBUG(0, "dmfe_get_stats", 0);	return &db->stats;}/*   Set DM910X multicast address */static void dmfe_set_filter_mode(struct net_device *dev){	struct dmfe_board_info *db = dev->priv;	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);	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);		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;		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		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */}/*   Process the upper socket ioctl command */static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);	return 0;}/*   A periodic timer routine   Dynamic media sense, allocated Rx buffer... */static void dmfe_timer(unsigned long data){	u32 tmp_cr8;	unsigned char tmp_cr12;	struct net_device *dev = (struct net_device *) data;	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;	DMFE_DBUG(0, "dmfe_timer()", 0);	/* Do reset now */	if (db->in_reset_state)		return;	/* Operating Mode Check */	if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET)) {		db->dm910x_chk_mode = 0x4;	}	/* Dynamic reset DM910X : system error or transmit time-out */	tmp_cr8 = inl(db->ioaddr + DCR8);	if ((db->interval_rx_cnt == 0) && (tmp_cr8)) {		db->wait_reset = 1;		/* printk("CR8 %x, Interval Rx %x\n", tmp_cr8, db->interval_rx_cnt); */	}	/* Receiving Traffic check */	if (db->interval_rx_cnt > RX_MAX_TRAFFIC)		db->cr7_data = 0x1a28d;	else		db->cr7_data = 0x1a2cd;	outl(db->cr7_data, db->ioaddr + DCR7);	db->interval_rx_cnt = 0;	if (db->wait_reset | (db->tx_packet_cnt &&			      ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) {		/*		   printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);		 */		DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);		dmfe_dynamic_reset(dev);		db->timer.expires = DMFE_TIMER_WUT;		add_timer(&db->timer);		return;	}	db->rx_error_cnt = 0;	/* Clear previos counter */	/* Link status check, Dynamic media type change */	if (db->chip_id == PCI_DM9132_ID)		tmp_cr12 = inb(db->ioaddr + DCR9 + 3);	/* DM9132 */	else		tmp_cr12 = inb(db->ioaddr + DCR12);	/* DM9102/DM9102A */	if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||	    ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) {		/* DM9102A Chip */		if (tmp_cr12 & 2)			tmp_cr12 = 0x0;		/* Link failed */		else			tmp_cr12 = 0x3;		/* Link OK */	}	if (!(tmp_cr12 & 0x3) && !db->link_failed) {		/* Link Failed */		DMFE_DBUG(0, "Link Failed", tmp_cr12);		db->link_failed = 1;		phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);	/* reset Phy */		/* 10/100M link failed, used 1M Home-Net */		db->cr6_data |= 0x00040000;	/* CR6 bit18 = 1, select Home-Net */		db->cr6_data &= ~0x00000200;	/* CR6 bit9 =0, half duplex mode */		update_cr6(db->cr6_data, db->ioaddr);		/* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */		db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);		if (db->phy_id2 == 0xb900)			phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id);	} else if ((tmp_cr12 & 0x3) && db->link_failed) {		DMFE_DBUG(0, "Link link OK", tmp_cr12);		db->link_failed = 0;		/* CR6 bit18=0, select 10/100M */		db->cr6_data &= ~0x00040000;		update_cr6(db->cr6_data, db->ioaddr);		/* Auto Sense Speed */		if (db->media_mode & DMFE_AUTO)			dmfe_sense_speed(db);		dmfe_process_mode(db);		update_cr6(db->cr6_data, db->ioaddr);		/* SHOW_MEDIA_TYPE(db->op_mode); */	}	/* reallocated rx descriptor buffer */	if (db->rx_avail_cnt < RX_DESC_CNT)		allocated_rx_buffer(db);	/* Timer active again */	db->timer.expires = DMFE_TIMER_WUT;	add_timer(&db->timer);}/*   Dynamic reset the DM910X board   Stop DM910X board   Free Tx/Rx allocated memory   Reset DM910X board   Re-initilize DM910X board */static void dmfe_dynamic_reset(struct net_device *dev){	struct dmfe_board_info *db = dev->priv;	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);	/* Enter dynamic reset route */	db->in_reset_state = 1;	/* Disable upper layer interface */	netif_stop_queue(dev);		db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);		/* Disable Tx/Rx */	update_cr6(db->cr6_data, dev->base_addr);	/* Free Rx Allocate buffer */	dmfe_free_rxbuffer(db);	/* system variable init */	db->tx_packet_cnt = 0;	db->tx_queue_cnt = 0;	db->rx_avail_cnt = 0;	db->link_failed = 0;	db->wait_reset = 0;	db->rx_error_cnt = 0;	/* Re-initilize DM910X board */	dmfe_init_dm910x(dev);	/* Leave dynamic reser route */	db->in_reset_state = 0;	/* Restart upper layer interface */	netif_wake_queue(dev);}/*   free all allocated rx buffer  */static void dmfe_free_rxbuffer(struct dmfe_board_info *db){	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);	/* free allocated rx buffer */	while (db->rx_avail_cnt) {		dev_kfree_skb((void *) (db->rx_ready_ptr->rx_skb_ptr));		db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc;		db->rx_avail_cnt--;	}}/*   Reused the SK buffer */static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb){	struct rx_desc *rxptr = db->rx_insert_ptr;	if (!(rxptr->rdes0 & 0x80000000)) {		rxptr->rx_skb_ptr = (u32) skb;		rxptr->rdes2 = virt_to_bus(skb->tail);		rxptr->rdes0 = 0x80000000;		db->rx_avail_cnt++;		db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc;	} else		DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt);}/*   Initialize transmit/Receive descriptor    Using Chain structure, and allocated Tx/Rx buffer */static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr){	struct tx_desc *tmp_tx;	struct rx_desc *tmp_rx;	unsigned char *tmp_buf;	int i;

⌨️ 快捷键说明

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