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

📄 dm9xs.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct rx_desc *rxptr = db->rx_insert_ptr;



	if (!(rxptr->rdes0 & 0x80000000)) {

		rxptr->rx_skb_ptr = (u32) skb;

		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );

		rxptr->rdes0 = cpu_to_le32(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;

	dma_addr_t tmp_tx_dma, tmp_rx_dma;

	dma_addr_t tmp_buf_dma;

	int i;



	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);



	/* tx descriptor start pointer */

	db->tx_insert_ptr = db->first_tx_desc;

	db->tx_remove_ptr = db->first_tx_desc;

	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */



	/* rx descriptor start pointer */

	db->first_rx_desc = (struct rx_desc *) ( (u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT );

	db->first_rx_desc_dma = ( db->first_tx_desc_dma + sizeof(struct rx_desc) * TX_DESC_CNT);

	db->rx_insert_ptr = db->first_rx_desc;

	db->rx_ready_ptr = db->first_rx_desc;

	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */



	/* Init Transmit chain */

	tmp_buf = db->buf_pool_start;

	tmp_buf_dma = db->buf_pool_dma_start;

	tmp_tx_dma = db->first_tx_desc_dma;

	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {

		tmp_tx->tx_buf_ptr = (u32) tmp_buf;

		tmp_tx->tdes0 = cpu_to_le32(0);

		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */

		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);

		tmp_tx_dma += sizeof(struct tx_desc);

		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);

		tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc));

		tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC);

		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;

	}

	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);

	tmp_tx->next_tx_desc = (u32) db->first_tx_desc;



	 /* Init Receive descriptor chain */

	tmp_rx_dma=db->first_rx_desc_dma;

	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {

		tmp_rx->rdes0 = cpu_to_le32(0);

		tmp_rx->rdes1 = cpu_to_le32(0x01000600);

		tmp_rx_dma += sizeof(struct rx_desc);

		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);

		tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc));

	}

	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);

	tmp_rx->next_rx_desc = (u32) db->first_rx_desc;



	/* pre-allocated Rx buffer */

	allocated_rx_buffer(db);

}





/*

 *	Update CR6 vaule

 *	Firstly stop DM910X , then written value and start

 */



static void update_cr6(u32 cr6_data, u32 ioaddr)

{

	u32 cr6_tmp;

  

	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */

	outl(cr6_tmp, ioaddr + DCR6);

	DELAY_5US;

	outl(cr6_data, ioaddr + DCR6);

	DELAY_5US;

}





/* 

 *	Send a setup frame for DM9132

 *	This setup frame initilize DM910X addres filter mode

*/



static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)

{

	struct dev_mc_list *mcptr;

	u16 * addrptr;

	u32 ioaddr = dev->base_addr+0xc0;		/* ID Table */ 

	u32 hash_val;

	u16 i, hash_table[4];



	DMFE_DBUG(0, "dm9132_id_table()", 0);



	/* Node address */

	addrptr = (u16 *) dev->dev_addr;

	outw(addrptr[0], ioaddr);

	ioaddr += 4;

	outw(addrptr[1], ioaddr);

	ioaddr += 4;

	outw(addrptr[2], ioaddr);

	ioaddr += 4;

  

	/* Clear Hash Table */

	for (i = 0; i < 4; i++)

		hash_table[i] = 0x0;



	/* broadcast address */

	hash_table[3] = 0x8000;



	/* the multicast address in Hash Table : 64 bits */

	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {

		hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f; 

		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);

	}



	/* Write the hash table to MAC MD table */

	for (i = 0; i < 4; i++, ioaddr += 4)

		outw(hash_table[i], ioaddr);

}





/* 

 *	Send a setup frame for DM9102/DM9102A

 *	This setup frame initilize DM910X addres filter mode

 */



static void send_filter_frame(struct DEVICE *dev, int mc_cnt)

{

	struct dmfe_board_info *db = dev->priv;

	struct dev_mc_list *mcptr;

	struct tx_desc *txptr;

	u16 * addrptr;

	u32 * suptr;

	int i;



	DMFE_DBUG(0, "send_filetr_frame()", 0);



	txptr = db->tx_insert_ptr;

	suptr = (u32 *) txptr->tx_buf_ptr;



	/* Node address */

	addrptr = (u16 *) dev->dev_addr;

	*suptr++ = addrptr[0];

	*suptr++ = addrptr[1];

	*suptr++ = addrptr[2];



	/* broadcast address */

	*suptr++ = 0xffff;

	*suptr++ = 0xffff;

	*suptr++ = 0xffff;



	/* fit the multicast address */

	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {

		addrptr = (u16 *) mcptr->dmi_addr;

		*suptr++ = addrptr[0];

		*suptr++ = addrptr[1];

		*suptr++ = addrptr[2];

	}



	for (; i<14; i++) {

		*suptr++ = 0xffff;

		*suptr++ = 0xffff;

		*suptr++ = 0xffff;

	}



	/* prepare the setup frame */

	db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;

	txptr->tdes1 = cpu_to_le32(0x890000c0);



	/* Resource Check and Send the setup packet */

	if (!db->tx_packet_cnt) {

		/* Resource Empty */

		db->tx_packet_cnt++;

		txptr->tdes0 = cpu_to_le32(0x80000000);

		update_cr6(db->cr6_data | 0x2000, dev->base_addr);

		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */

		update_cr6(db->cr6_data, dev->base_addr);

		dev->trans_start = jiffies;

	} else 

		db->tx_queue_cnt++;	/* Put in TX queue */



}





/*

 *	Allocate rx buffer,

 *	As possible as allocated maxiumn Rx buffer

 */



static void allocated_rx_buffer(struct dmfe_board_info *db)

{

	struct rx_desc *rxptr;

	struct sk_buff *skb;



	rxptr = db->rx_insert_ptr;



	while(db->rx_avail_cnt < RX_DESC_CNT) {

		if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )

			break;

		rxptr->rx_skb_ptr = (u32) skb;

		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );

		rxptr->rdes0 = cpu_to_le32(0x80000000);

		rxptr = (struct rx_desc *) rxptr->next_rx_desc;

		db->rx_avail_cnt++;

	}



	db->rx_insert_ptr = rxptr;

}





/*

 *	Read one word data from the serial ROM

 */



static u16 read_srom_word(long ioaddr, int offset)

{

	int i;

	u16 srom_data = 0;

	long cr9_ioaddr = ioaddr + DCR9;

        

	outl(CR9_SROM_READ, cr9_ioaddr);

	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);

        

	/* Send the Read Command 110b */

	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);

	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);

	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);



	/* Send the offset */

	for (i = 5; i >= 0; i--) {

		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;

		SROM_CLK_WRITE(srom_data, cr9_ioaddr);

	}



	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);

        

	for (i = 16; i > 0; i--) {

		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);

		DELAY_5US;

		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);

		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);

		DELAY_5US;

	}



	outl(CR9_SROM_READ, cr9_ioaddr);

	return srom_data;

}





/*

 *	Auto sense the media mode

 */



static u8 dmfe_sense_speed(struct dmfe_board_info * db)

{

	u8 ErrFlag = 0;

	u16 phy_mode;



	/* CR6 bit18=0, select 10/100M */

	update_cr6( (db->cr6_data & ~0x40000), db->ioaddr);

	 

	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);

	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);



	if ( (phy_mode & 0x24) == 0x24 ) {

		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */

			phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;

		else 				/* DM9102/DM9102A */

			phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;

		/* printk("<DM9XS>: Phy_mode %x ",phy_mode); */

		switch (phy_mode) {

		case 0x1000: db->op_mode = DMFE_10MHF; break;

		case 0x2000: db->op_mode = DMFE_10MFD; break;

		case 0x4000: db->op_mode = DMFE_100MHF; break;

		case 0x8000: db->op_mode = DMFE_100MFD; break;

		default: db->op_mode = DMFE_10MHF;

			ErrFlag = 1;

			break;

		}

	} else {

		db->op_mode = DMFE_10MHF; 

		DMFE_DBUG(0, "Link Failed :", phy_mode);

		ErrFlag = 1;

	}



	return ErrFlag;

}





/*

 *	Set 10/100 phyxcer capability

 *	AUTO mode : phyxcer register4 is NIC capability

 *	Force mode: phyxcer register4 is the force media

 */



static void dmfe_set_phyxcer(struct dmfe_board_info *db)

{

	u16 phy_reg;



	/* Select 10/100M phyxcer */

	db->cr6_data &= ~0x40000;

	update_cr6(db->cr6_data, db->ioaddr);



	/* DM9009 Chip: Phyxcer reg18 bit12=0 */

	if (db->chip_id == PCI_DM9009_ID) {

		phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;

		phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);

	}



	/* Phyxcer capability setting */

	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;



	if (db->media_mode & DMFE_AUTO) {

		/* AUTO Mode */

		phy_reg |= db->PHY_reg4; 

	} else {

		/* Force Mode */

		switch(db->media_mode) {

		case DMFE_10MHF: phy_reg |= 0x20; break;

		case DMFE_10MFD: phy_reg |= 0x40; break;

		case DMFE_100MHF: phy_reg |= 0x80; break;

		case DMFE_100MFD: phy_reg |= 0x100; break;

		}

		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;

	}



  	/* Write new capability to Phyxcer Reg4 */

	if ( !(phy_reg & 0x01e0)) {

		phy_reg|=db->PHY_reg4; 

		db->media_mode|=DMFE_AUTO;

	}

	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); 



 	/* Restart Auto-Negotiation */

	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )

		phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);

	if ( !db->chip_type )

		phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);

}





/*

 *	Process op-mode

 *	AUTO mode : PHY controller in Auto-negotiation Mode

 *	Force mode: PHY controller in force mode with HUB

 *			N-way force capability with SWITCH

 */



static void dmfe_process_mode(struct dmfe_board_info *db)

{

	u16 phy_reg;



	/* Full Duplex Mode Check */

	if (db->op_mode & 0x4)

		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */

	else

		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */



	/* Transciver Selection */

	if (db->op_mode & 0x10)		/* 1M HomePNA */

		db->cr6_data |= 0x40000;/* External MII select */

	else

		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */

 

	update_cr6(db->cr6_data, db->ioaddr);



	/* 10/100M phyxcer force mode need */

	if ( !(db->media_mode & 0x18)) {

		/* Forece Mode */

		phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);

		if ( !(phy_reg & 0x1) ) {

			/* parter without N-Way capability */

			phy_reg = 0x0;

			switch(db->op_mode) {

			case DMFE_10MHF: phy_reg = 0x0; break;

			case DMFE_10MFD: phy_reg = 0x100; break;

			case DMFE_100MHF: phy_reg = 0x2000; break;

			case DMFE_100MFD: phy_reg = 0x2100; break;

			}

			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);

       			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )

				mdelay(20);

			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);

		}

	}

}





/*

 *	Write a word to Phy register

 */



static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)

{

	u16 i;

	u32 ioaddr; 



	if (chip_id == PCI_DM9132_ID) {

		ioaddr = iobase + 0x80 + offset * 4;

		outw(phy_data, ioaddr);

	} else {

		/* DM9102/DM9102A Chip */

		ioaddr = iobase + DCR9;



⌨️ 快捷键说明

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