📄 uli526x.c
字号:
if (db->tx_packet_cnt < TX_DESC_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 printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n");}/* * Allocate rx buffer, * As possible as allocate maxiumn Rx buffer */static void allocate_rx_buffer(struct uli526x_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 = skb; /* FIXME (?) */ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = 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); udelay(5); srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); udelay(5); } outl(CR9_SROM_READ, cr9_ioaddr); return srom_data;}/* * Auto sense the media mode */static u8 uli526x_sense_speed(struct uli526x_board_info * db){ u8 ErrFlag = 0; u16 phy_mode; 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 ) { phy_mode = ((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)<<7); if(phy_mode&0x8000) phy_mode = 0x8000; else if(phy_mode&0x4000) phy_mode = 0x4000; else if(phy_mode&0x2000) phy_mode = 0x2000; else phy_mode = 0x1000; /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = ULI526X_10MHF; break; case 0x2000: db->op_mode = ULI526X_10MFD; break; case 0x4000: db->op_mode = ULI526X_100MHF; break; case 0x8000: db->op_mode = ULI526X_100MFD; break; default: db->op_mode = ULI526X_10MHF; ErrFlag = 1; break; } } else { db->op_mode = ULI526X_10MHF; ULI526X_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 uli526x_set_phyxcer(struct uli526x_board_info *db){ u16 phy_reg; /* Phyxcer capability setting */ phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0; if (db->media_mode & ULI526X_AUTO) { /* AUTO Mode */ phy_reg |= db->PHY_reg4; } else { /* Force Mode */ switch(db->media_mode) { case ULI526X_10MHF: phy_reg |= 0x20; break; case ULI526X_10MFD: phy_reg |= 0x40; break; case ULI526X_100MHF: phy_reg |= 0x80; break; case ULI526X_100MFD: phy_reg |= 0x100; break; } } /* Write new capability to Phyxcer Reg4 */ if ( !(phy_reg & 0x01e0)) { phy_reg|=db->PHY_reg4; db->media_mode|=ULI526X_AUTO; } phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); /* Restart Auto-Negotiation */ phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); udelay(50);}/* * 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 uli526x_process_mode(struct uli526x_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 */ update_cr6(db->cr6_data, db->ioaddr); /* 10/100M phyxcer force mode need */ if ( !(db->media_mode & 0x8)) { /* 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 ULI526X_10MHF: phy_reg = 0x0; break; case ULI526X_10MFD: phy_reg = 0x100; break; case ULI526X_100MHF: phy_reg = 0x2000; break; case ULI526X_100MFD: phy_reg = 0x2100; break; } phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); 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_ULI5263_ID) { phy_writeby_cr10(iobase, phy_addr, offset, phy_data); return; } /* M5261/M5263 Chip */ ioaddr = iobase + DCR9; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); /* Send write command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); /* written trasnition */ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); /* 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, chip_id); }/* * 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_ULI5263_ID) return phy_readby_cr10(iobase, phy_addr, offset); /* M5261/M5263 Chip */ ioaddr = iobase + DCR9; /* Send 33 synchronization clock to Phy controller */ for (i = 0; i < 35; i++) phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); /* Send start command(01) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); /* Send read command(10) to Phy */ phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); /* Skip transition state */ phy_read_1bit(ioaddr, chip_id); /* read 16bit data */ for (phy_data = 0, i = 0; i < 16; i++) { phy_data <<= 1; phy_data |= phy_read_1bit(ioaddr, chip_id); } return phy_data;}static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset){ unsigned long ioaddr,cr10_value; ioaddr = iobase + DCR10; cr10_value = phy_addr; cr10_value = (cr10_value<<5) + offset; cr10_value = (cr10_value<<16) + 0x08000000; outl(cr10_value,ioaddr); udelay(1); while(1) { cr10_value = inl(ioaddr); if(cr10_value&0x10000000) break; } return (cr10_value&0x0ffff);}static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data){ unsigned long ioaddr,cr10_value; ioaddr = iobase + DCR10; cr10_value = phy_addr; cr10_value = (cr10_value<<5) + offset; cr10_value = (cr10_value<<16) + 0x04000000 + phy_data; outl(cr10_value,ioaddr); udelay(1);}/* * Write one bit data to Phy Controller */static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id){ 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, u32 chip_id){ u16 phy_data; outl(0x50000 , ioaddr); udelay(1); phy_data = ( inl(ioaddr) >> 19 ) & 0x1; outl(0x40000 , ioaddr); udelay(1); return phy_data;}static struct pci_device_id uli526x_pci_tbl[] = { { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID }, { 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID }, { 0, }};MODULE_DEVICE_TABLE(pci, uli526x_pci_tbl);static struct pci_driver uli526x_driver = { .name = "uli526x", .id_table = uli526x_pci_tbl, .probe = uli526x_init_one, .remove = __devexit_p(uli526x_remove_one),};MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");MODULE_DESCRIPTION("ULi M5261/M5263 fast ethernet driver");MODULE_LICENSE("GPL");MODULE_PARM(debug, "i");MODULE_PARM(mode, "i");MODULE_PARM(cr6set, "i");MODULE_PARM_DESC(debug, "ULi M5261/M5263 enable debugging (0-1)");MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");/* Description: * when user used insmod to add module, system invoked init_module() * to register the services. */static int __init uli526x_init_module(void){ int rc; printk(version); printed_version = 1; ULI526X_DBUG(0, "init_module() ", debug); if (debug) uli526x_debug = debug; /* set debug flag */ if (cr6set) uli526x_cr6_user_set = cr6set; switch(mode) { case ULI526X_10MHF: case ULI526X_100MHF: case ULI526X_10MFD: case ULI526X_100MFD: uli526x_media_mode = mode; break; default:uli526x_media_mode = ULI526X_AUTO; break; } rc = pci_module_init(&uli526x_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 uli526x_cleanup_module(void){ ULI526X_DBUG(0, "uli526x_clean_module() ", debug); pci_unregister_driver(&uli526x_driver);}module_init(uli526x_init_module);module_exit(uli526x_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -