📄 dm9xs.c
字号:
/* 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;
/* 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;
}
/*
* 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 = *(u16 *) (&srom[34]);
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 = *( (int *) &srom[34]) & *( (int *) &srom[36] );
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[] __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 },
{ 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: "dm9xs",
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");
MODULE_PARM(HPNA_mode, "i");
MODULE_PARM(HPNA_rx_cmd, "i");
MODULE_PARM(HPNA_tx_cmd, "i");
MODULE_PARM(HPNA_NoiseFloor, "i");
MODULE_PARM(SF_mode, "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 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_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.
*/
void clean_module(void)
{
DMFE_DBUG(0, "dmfe_clean_module() ", debug);
pci_unregister_driver(&dmfe_driver);
}
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 + -