📄 dmfe.c
字号:
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(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id){ u16 i; unsigned long 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 address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register address */ 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(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id){ int i; u16 phy_data; unsigned long 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 address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register address */ 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(unsigned long ioaddr, u32 phy_data){ outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1); outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ udelay(1); outl(phy_data, ioaddr); /* MII Clock Low */ udelay(1);}/* * Read one bit phy data from PHY controller */static u16 phy_read_1bit(unsigned long ioaddr){ u16 phy_data; outl(0x50000, ioaddr); udelay(1); phy_data = ( inl(ioaddr) >> 19 ) & 0x1; outl(0x40000, ioaddr); udelay(1); return phy_data;}/* * Parser SROM and media mode */static void dmfe_parse_srom(struct dmfe_board_info * db){ char * srom = db->srom; int dmfe_mode, tmp_reg; DMFE_DBUG(0, "dmfe_parse_srom() ", 0); /* Init CR15 */ db->cr15_data = CR15_DEFAULT; /* Check SROM Version */ if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) { /* SROM V4.01 */ /* Get NIC support media mode */ db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2); db->PHY_reg4 = 0; for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { switch( db->NIC_capability & tmp_reg ) { case 0x1: db->PHY_reg4 |= 0x0020; break; case 0x2: db->PHY_reg4 |= 0x0040; break; case 0x4: db->PHY_reg4 |= 0x0080; break; case 0x8: db->PHY_reg4 |= 0x0100; break; } } /* Media Mode Force or not check */ dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) & le32_to_cpup((__le32 *)srom + 36/4); switch(dmfe_mode) { case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ case 0x8: dmfe_media_mode = DMFE_100MFD; break; /* 100MFD */ case 0x100: case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */ } /* Special Function setting */ /* VLAN function */ if ( (SF_mode & 0x1) || (srom[43] & 0x80) ) db->cr15_data |= 0x40; /* Flow Control */ if ( (SF_mode & 0x2) || (srom[40] & 0x1) ) db->cr15_data |= 0x400; /* TX pause packet */ if ( (SF_mode & 0x4) || (srom[40] & 0xe) ) db->cr15_data |= 0x9800; } /* Parse HPNA parameter */ db->HPNA_command = 1; /* Accept remote command or not */ if (HPNA_rx_cmd == 0) db->HPNA_command |= 0x8000; /* Issue remote command & operation mode */ if (HPNA_tx_cmd == 1) switch(HPNA_mode) { /* Issue Remote Command */ case 0: db->HPNA_command |= 0x0904; break; case 1: db->HPNA_command |= 0x0a00; break; case 2: db->HPNA_command |= 0x0506; break; case 3: db->HPNA_command |= 0x0602; break; } else switch(HPNA_mode) { /* Don't Issue */ case 0: db->HPNA_command |= 0x0004; break; case 1: db->HPNA_command |= 0x0000; break; case 2: db->HPNA_command |= 0x0006; break; case 3: db->HPNA_command |= 0x0002; break; } /* Check DM9801 or DM9802 present or not */ db->HPNA_present = 0; update_cr6(db->cr6_data|0x40000, db->ioaddr); tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id); if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) { /* DM9801 or DM9802 present */ db->HPNA_timer = 8; if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) { /* DM9801 HomeRun */ db->HPNA_present = 1; dmfe_program_DM9801(db, tmp_reg); } else { /* DM9802 LongRun */ db->HPNA_present = 2; dmfe_program_DM9802(db); } }}/* * Init HomeRun DM9801 */static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev){ uint reg17, reg25; if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR; switch(HPNA_rev) { case 0xb900: /* DM9801 E3 */ db->HPNA_command |= 0x1000; reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id); reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000; reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); break; case 0xb901: /* DM9801 E4 */ reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor; reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3; break; case 0xb902: /* DM9801 E5 */ case 0xb903: /* DM9801 E6 */ default: db->HPNA_command |= 0x1000; reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5; reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id); reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor; break; } phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id); phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);}/* * Init HomeRun DM9802 */static void dmfe_program_DM9802(struct dmfe_board_info * db){ uint phy_reg; if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR; phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id); phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor; phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);}/* * Check remote HPNA power and speed status. If not correct, * issue command again.*/static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db){ uint phy_reg; /* Got remote device status */ phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60; switch(phy_reg) { case 0x00: phy_reg = 0x0a00;break; /* LP/LS */ case 0x20: phy_reg = 0x0900;break; /* LP/HS */ case 0x40: phy_reg = 0x0600;break; /* HP/LS */ case 0x60: phy_reg = 0x0500;break; /* HP/HS */ } /* Check remote device status match our setting ot not */ if ( phy_reg != (db->HPNA_command & 0x0f00) ) { phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); db->HPNA_timer=8; } else db->HPNA_timer=600; /* Match, every 10 minutes, check */}static struct pci_device_id dmfe_pci_tbl[] = { { 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 }, { 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_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 = __devexit_p(dmfe_remove_one),};MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);module_param(debug, int, 0);module_param(mode, byte, 0);module_param(cr6set, int, 0);module_param(chkmode, byte, 0);module_param(HPNA_mode, byte, 0);module_param(HPNA_rx_cmd, byte, 0);module_param(HPNA_tx_cmd, byte, 0);module_param(HPNA_NoiseFloor, byte, 0);module_param(SF_mode, byte, 0);MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");/* 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; printk(version); printed_version = 1; DMFE_DBUG(0, "init_module() ", debug); if (debug) dmfe_debug = debug; /* set debug flag */ if (cr6set) dmfe_cr6_user_set = cr6set; switch(mode) { case DMFE_10MHF: case DMFE_100MHF: case DMFE_10MFD: case DMFE_100MFD: case DMFE_1M_HPNA: dmfe_media_mode = mode; break; default:dmfe_media_mode = DMFE_AUTO; break; } if (HPNA_mode > 4) HPNA_mode = 0; /* Default: LP/HS */ if (HPNA_rx_cmd > 1) HPNA_rx_cmd = 0; /* Default: Ignored remote cmd */ if (HPNA_tx_cmd > 1) HPNA_tx_cmd = 0; /* Default: Don't issue remote cmd */ if (HPNA_NoiseFloor > 15) HPNA_NoiseFloor = 0; rc = pci_module_init(&dmfe_driver); if (rc < 0) return rc; return 0;}/* * 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){ DMFE_DBUG(0, "dmfe_clean_module() ", debug); 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 + -