📄 dmfe.c
字号:
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(virt_to_bus(db->first_tx_desc), ioaddr + DCR4); /* Init CR4 */ /* rx descriptor start pointer */ db->first_rx_desc = (struct rx_desc *) ((u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT); db->rx_insert_ptr = db->first_rx_desc; db->rx_ready_ptr = db->first_rx_desc; outl(virt_to_bus(db->first_rx_desc), ioaddr + DCR3); /* Init CR3 */ /* Init Transmit chain */ tmp_buf = db->buf_pool_start; 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 = 0; tmp_tx->tdes1 = 0x81000000; /* IC, chain */ tmp_tx->tdes2 = (u32) virt_to_bus(tmp_buf); tmp_tx->tdes3 = (u32) virt_to_bus(tmp_tx) + sizeof(struct tx_desc); tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc)); tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC); } (--tmp_tx)->tdes3 = (u32) virt_to_bus(db->first_tx_desc); tmp_tx->next_tx_desc = (u32) db->first_tx_desc; /* Init Receive descriptor chain */ for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) { tmp_rx->rdes0 = 0; tmp_rx->rdes1 = 0x01000600; tmp_rx->rdes3 = (u32) virt_to_bus(tmp_rx) + sizeof(struct rx_desc); tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc)); } (--tmp_rx)->rdes3 = (u32) virt_to_bus(db->first_rx_desc); 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); cr6_tmp = inl(ioaddr + DCR6); /* printk("CR6 update %x ", cr6_tmp); */}/* Send a setup frame for DM9132 This setup frame initilize DM910X addres filter mode */static void dm9132_id_table(struct net_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 net_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 = 0x890000c0; /* Resource Check and Send the setup packet */ if (!db->tx_packet_cnt) { /* Resource Empty */ db->tx_packet_cnt++; txptr->tdes0 = 0x80000000; update_cr6(db->cr6_data | 0x2000, dev->base_addr); outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ update_cr6(db->cr6_data, dev->base_addr); } else { /* Put into TX queue */ db->tx_queue_cnt++; }}/* * Allocate rx buffer, * Allocate as many Rx buffers as possible. */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 = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL) break; rxptr->rx_skb_ptr = (u32) skb; rxptr->rdes2 = virt_to_bus(skb->tail); rxptr->rdes0 = 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 void dmfe_sense_speed(struct dmfe_board_info *db){ int i; u16 phy_mode; for (i = 1000; i; i--) { DELAY_5US; phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); if ((phy_mode & 0x24) == 0x24) break; } if (i) { 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("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; DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode); break; } } else { db->op_mode = DMFE_10MHF; DMFE_DBUG(0, "Link Failed :", phy_mode); }}/* 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 */ db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ if (db->op_mode & 0x4) db->cr6_data |= CR6_FDM; if (!(db->media_mode & DMFE_AUTO)) { /* Force Mode Check */ /* User force the media type */ phy_reg = phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id); /* printk("Nway phy_reg5 %x ",phy_reg); */ if (phy_reg & 0x1) { /* parter own the N-Way capability */ phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x1e0; switch (db->op_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; } phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); } else { /* parter without the N-Way capability */ 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); } }}/* 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; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send write command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); /* written trasnition */ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); /* Write a word data to PHY controller */ for (i = 0x8000; i > 0; i >>= 1) phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0); }}/* Read a word data from phy register */static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id){ int i; u16 phy_data; u32 ioaddr; if (chip_id == PCI_DM9132_ID) { /* DM9132 Chip */ ioaddr = iobase + 0x80 + offset * 4; phy_data = inw(ioaddr); } else { /* DM9102/DM9102A Chip */ ioaddr = iobase + DCR9; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); /* Send read command(10) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); /* Send Phy addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register addres */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); /* Skip transition state */ phy_read_1bit(ioaddr); /* read 16bit data */ for (phy_data = 0, i = 0; i < 16; i++) { phy_data <<= 1; phy_data |= phy_read_1bit(ioaddr); } } return phy_data;}/* Write one bit data to Phy Controller */static void phy_write_1bit(u32 ioaddr, u32 phy_data){ outl(phy_data, ioaddr); /* MII Clock Low */ DELAY_1US; outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ DELAY_1US; outl(phy_data, ioaddr); /* MII Clock Low */ DELAY_1US;}/* Read one bit phy data from PHY controller */static u16 phy_read_1bit(u32 ioaddr){ u16 phy_data; outl(0x50000, ioaddr); DELAY_1US; phy_data = (inl(ioaddr) >> 19) & 0x1; outl(0x40000, ioaddr); DELAY_1US; return phy_data;}/* 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) */unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag){ unsigned long Crc = 0xffffffff; while (Len--) { Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8); } if (flag) return ~Crc; else return Crc;}static struct pci_device_id dmfe_pci_tbl[] __initdata = { { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID }, { 0, }};MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);static struct pci_driver dmfe_driver = { name: "dmfe", id_table: dmfe_pci_tbl, probe: dmfe_init_one, remove: dmfe_remove_one,};MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");MODULE_PARM(debug, "i");MODULE_PARM(mode, "i");MODULE_PARM(cr6set, "i");MODULE_PARM(chkmode, "i");/* Description: * when user used insmod to add module, system invoked init_module() * to initilize and register. */ static int __init dmfe_init_module(void){ int rc; DMFE_DBUG(0, "init_module() ", debug); if (debug) dmfe_debug = debug; /* set debug flag */ if (cr6set) dmfe_cr6_user_set = cr6set; switch (mode) { case 0: case 1: case 4: case 5: dmfe_media_mode = mode; break; default: dmfe_media_mode = 8; break; } rc = pci_register_driver(&dmfe_driver); if (rc < 0) return rc; if (rc > 0) { printk (KERN_INFO "Davicom DM91xx net driver loaded, version " DMFE_VERSION "\n"); return 0; } return -ENODEV;}/* * Description: * when user used rmmod to delete module, system invoked clean_module() * to un-register all registered services. */ static void __exit dmfe_cleanup_module(void){ pci_unregister_driver(&dmfe_driver);}module_init(dmfe_init_module);module_exit(dmfe_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -