📄 ax88180.c
字号:
spin_lock_irqsave(&pax88180_local->lock, flags); //Update the statistics counter here..... READ_MACREG(RXIPCRCCNT, tmp_regval); pax88180_local->stats.rx_errors += tmp_regval; WRITE_MACREG(RXIPCRCCNT, 0); READ_MACREG(RXCRCCNT, tmp_regval); pax88180_local->stats.rx_errors += tmp_regval; WRITE_MACREG(RXCRCCNT, 0); READ_MACREG(TXFAILCNT, tmp_regval); pax88180_local->stats.tx_errors += tmp_regval; WRITE_MACREG(TXFAILCNT, 0); spin_unlock_irqrestore(&pax88180_local->lock, flags); PRINTK(OTHERS_MSG, "ax88180: ax88180_get_stats end ..........\n"); return &pax88180_local->stats;}/* ***************************************************************************** * ax88180_set_multicast_list() ***************************************************************************** */static void ax88180_set_multicast_list(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; struct dev_mc_list *mc_list; unsigned long mc_hash_table[2]; int crc_val,i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(OTHERS_MSG, "ax88180: ax88180_set_multicast_list beginning ..........\n"); pax88180_local->RxFilterMode = DEFAULT_RXFILTER; if (global_dev->flags & IFF_PROMISC) { pax88180_local->RxFilterMode |= RX_RXANY; } else if (global_dev->flags & IFF_ALLMULTI) { pax88180_local->RxFilterMode |= RX_MULTICAST; } else if (global_dev->flags & IFF_MULTICAST) { pax88180_local->RxFilterMode |= RX_MULTI_HASH; /* Handle Rx multicast hash table here */ mc_hash_table[0] = mc_hash_table[1] = 0; for (i = 0, mc_list = global_dev->mc_list; (mc_list != NULL) && (i < global_dev->mc_count); i++, mc_list = mc_list->next) { crc_val = ether_crc(ETH_ALEN, mc_list->dmi_addr); set_bit(crc_val >> 26, mc_hash_table); } WRITE_MACREG(HASHTAB0, (unsigned int)mc_hash_table[0]); WRITE_MACREG(HASHTAB1, (unsigned int)(mc_hash_table[0] >> 16)); WRITE_MACREG(HASHTAB2, (unsigned int)mc_hash_table[1]); WRITE_MACREG(HASHTAB3, (unsigned int)(mc_hash_table[1] >> 16)); } WRITE_MACREG(RXFILTER, pax88180_local->RxFilterMode); PRINTK(OTHERS_MSG, "ax88180: ax88180_set_multicast_list end ..........\n"); return;}/* ***************************************************************************** * ax88180_interrupt() * * Handle the network interface interrupts. * ***************************************************************************** */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)static void ax88180_interrupt(int irq, void *global_dev_id, struct pt_regs * regs)#elsestatic irqreturn_t ax88180_interrupt(int irq, void *global_dev_id, struct pt_regs * regs)#endif{ struct net_device *global_dev = global_dev_id; struct _AX88180_PRIVATE *pax88180_local; unsigned long ISR_Status; unsigned long rxcurt_ptr, rxbound_ptr; unsigned long bmsr_val; unsigned long tmp_regval; int i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; /* Read and check interrupt status here...... */ READ_MACREG(ISR, ISR_Status); if ( (ISR_Status == 0) || (ISR_Status & ~DEFAULT_IMR) ) {// PRINTK(WARNING_MSG, "ax88180: Not our interrupt!!\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) return;#else return 0;#endif } PRINTK(INT_MSG, "ax88180: ax88180_interrupt beginning ..........\n"); //allan9 add for debugging// DISPLAY_ALLMACREG; // DISPLAY_ALLPHYREG; /* Disable AX88180 interrupt */ DISABLE_INTERRUPT; /* Clear the interrupt status */ WRITE_MACREG(ISR, ISR_Status); PRINTK(INT_MSG, "ax88180: The interrupt status = 0x%08lx\n", ISR_Status); /* Handle AX88180 interrupt events */ if (ISR_Status & ISR_WATCHDOG) { PRINTK(DRIVER_MSG, "ax88180: Watchdog Timer interrupt (ISR = 0x%08lx)\n", ISR_Status); } if (ISR_Status & ISR_RX) { ax88180_rx_handler(global_dev); } if (ISR_Status & ISR_TX) { ax88180_tx_handler(global_dev); } if (ISR_Status & ISR_RXBUFFOVR) { pax88180_local->rxbuf_overflow_count++; pax88180_local->stats.rx_fifo_errors++; READ_MACREG(RXCURT, rxcurt_ptr); READ_MACREG(RXBOUND, rxbound_ptr); PRINTK(ERROR_MSG, "ax88180: RX Buffer overflow!! (count=%d, RXBOUND=0x%08lx, RXCURT=0x%08lx)\n", (int)pax88180_local->rxbuf_overflow_count, rxbound_ptr, rxcurt_ptr); PRINTK(ERROR_MSG, "ax88180: The interrupt status = 0x%08lx\n", ISR_Status); if (pax88180_local->rxbuf_overflow_count > 10) { RESET_MAC; INIT_TXRX_VARIABLES; } } if (ISR_Status & ISR_PHY) { /* Read ISR register once to clear Marvell PHY interrupt bit */ READ_PHYREG(pax88180_local->PhyAddr, M88_ISR, tmp_regval); /* Waiting 200 msecs for PHY link stable */ for (i = 0; i < 200; i++) { READ_PHYREG(pax88180_local->PhyAddr, BMSR, bmsr_val); if (bmsr_val & LINKOK) { break; } mdelay(1); } if (bmsr_val & LINKOK) { PRINTK(WARNING_MSG, "ax88180: The cable is connected.\n"); netif_carrier_on(global_dev); if (pax88180_local->ForceMedia == AUTO_MEDIA) ax88180_meida_config(global_dev); DISPLAY_ALLPHYREG; } else { PRINTK(WARNING_MSG, "ax88180: The cable is disconnected.\n"); netif_carrier_off(global_dev); DISPLAY_ALLPHYREG; } } /* Enable AX88180 interrupt */ ENABLE_INTERRUPT; PRINTK(INT_MSG, "ax88180: ax88180_interrupt end ..........\n\n");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) return;#else return IRQ_RETVAL(0);#endif}/* * =========================================================================== * <<<<<< Declare INIT/OTHERS SUB-ROUTINES >>>>>> * =========================================================================== *//* ***************************************************************************** * ax88180_initialization() ***************************************************************************** */static int ax88180_initialization(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local;// unsigned long flags; unsigned long macid0_val, macid1_val, macid2_val; unsigned long tmp_regval; int i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(INIT_MSG, "ax88180: ax88180_initialization beginning ..........\n");// spin_lock_irqsave(&pax88180_local->lock, flags); RESET_MAC; /* Reload MAC address from EEPROM */ WRITE_MACREG(PROMCTRL, RELOAD_EEPROM); for (i = 0; i < 500; i++) { READ_MACREG(PROMCTRL, tmp_regval); if ((tmp_regval & RELOAD_EEPROM) == 0) break; mdelay(1); } /* Disable AX88180 interrupt */ DISABLE_INTERRUPT; /* Disable AX88180 TX/RX functions */ WRITE_MACREG(CMD, WAKEMOD); /* Get MAC addresses */ READ_MACREG(MACID0, macid0_val); READ_MACREG(MACID1, macid1_val); READ_MACREG(MACID2, macid2_val); if ((macid0_val | macid1_val | macid2_val) != 0) { global_dev->dev_addr[0] = (unsigned char)macid0_val; global_dev->dev_addr[1] = (unsigned char)(macid0_val >> 8); global_dev->dev_addr[2] = (unsigned char)macid1_val; global_dev->dev_addr[3] = (unsigned char)(macid1_val >> 8); global_dev->dev_addr[4] = (unsigned char)macid2_val; global_dev->dev_addr[5] = (unsigned char)(macid2_val >> 8); } else { /* No EEPROM found!! Set a default MAC address. */ /* The driver designer should assign a legal MAC address here. */ global_dev->dev_addr[0] = 0x00; global_dev->dev_addr[1] = 0x12; global_dev->dev_addr[2] = 0x34; global_dev->dev_addr[3] = 0x56; global_dev->dev_addr[4] = 0x78; global_dev->dev_addr[5] = 0x9a; macid0_val = (global_dev->dev_addr[1] << 8) + global_dev->dev_addr[0]; macid1_val = (global_dev->dev_addr[3] << 8) + global_dev->dev_addr[2]; macid2_val = (global_dev->dev_addr[5] << 8) + global_dev->dev_addr[4]; WRITE_MACREG(MACID0, macid0_val); WRITE_MACREG(MACID1, macid1_val); WRITE_MACREG(MACID2, macid2_val); } /* Print the MAC address */ PRINTK(DRIVER_MSG, "ax88180: The MAC address is"); for (i = 0; i < ETH_ALEN; i++) PRINTK(DRIVER_MSG, "%c%02x", i ? ':' : ' ', global_dev->dev_addr[i]); PRINTK(DRIVER_MSG, "\n"); /* Initial PHY registers */ ax88180_PHY_initial(global_dev); /* Configure MAC media mode registers */ ax88180_meida_config(global_dev);#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) /* Initial MII interface information for ethtool ioctl */ pax88180_local->mii_if.dev = global_dev; pax88180_local->mii_if.phy_id = pax88180_local->PhyAddr; pax88180_local->mii_if.phy_id_mask = 0x1F; pax88180_local->mii_if.reg_num_mask = 0x1F; pax88180_local->mii_if.mdio_read = mdio_read; pax88180_local->mii_if.mdio_write = mdio_write; pax88180_local->mii_if.force_media = pax88180_local->ForceMedia; pax88180_local->mii_if.full_duplex = pax88180_local->LineSpeed; pax88180_local->mii_if.force_media = pax88180_local->DuplexMode; #endif WRITE_MACREG(RXFILTER, DEFAULT_RXFILTER);// spin_unlock_irqrestore(&pax88180_local->lock, flags); PRINTK(INIT_MSG, "ax88180: ax88180_initialization end ..........\n"); return 0;}/* ***************************************************************************** * ax88180_PHY_initial() * * Initialize PHY registers. * ***************************************************************************** */static void ax88180_PHY_initial(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long bmcr_val, anar_val, bmsr_val; unsigned long aux_1000_ctrl; unsigned long tmp_regval; unsigned int i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(INIT_MSG, "ax88180: ax88180_PHY_initial beginning ..........\n"); /* Check avaliable PHY chipset */ pax88180_local->PhyAddr = MARVELL_88E1111_PHYADDR; READ_PHYREG(pax88180_local->PhyAddr, PHYIDR0, pax88180_local->PhyID0); if (pax88180_local->PhyID0 == MARVELL_88E1111_PHYIDR0) { PRINTK(DRIVER_MSG, "ax88180: Found Marvell 88E1111 PHY chipset. (PHY Addr=0x%x)\n", (unsigned int)pax88180_local->PhyAddr); READ_PHYREG(pax88180_local->PhyAddr, M88_EXT_SSR, tmp_regval); if ((tmp_regval & HWCFG_MODE_MASK) == RGMII_COPPER_MODE) { WRITE_PHYREG(pax88180_local->PhyAddr, M88_EXT_SCR, DEFAULT_EXT_SCR); RESET_PHY; WRITE_PHYREG(pax88180_local->PhyAddr, M88_IER, LINK_CHANGE_INT); } } else { pax88180_local->PhyAddr = CICADA_CIS8201_PHYADDR; READ_PHYREG(pax88180_local->PhyAddr, PHYIDR0, pax88180_local->PhyID0); if (pax88180_local->PhyID0 == CICADA_CIS8201_PHYIDR0) { PRINTK(DRIVER_MSG, "ax88180: Found CICADA CIS8201 PHY chipset. (PHY Addr=0x%x)\n", (unsigned int)pax88180_local->PhyAddr); WRITE_PHYREG(pax88180_local->PhyAddr, CIS_IMR, (CIS_INT_ENABLE | LINK_CHANGE_INT)); /* Set CIS_SMI_PRIORITY bit before force the media mode */ READ_PHYREG(pax88180_local->PhyAddr, CIS_AUX_CTRL_STATUS, tmp_regval); tmp_regval &= ~CIS_SMI_PRIORITY; if (pax88180_local->MediaMode != MEDIA_AUTO) tmp_regval |= CIS_SMI_PRIORITY; WRITE_PHYREG(pax88180_local->PhyAddr, CIS_AUX_CTRL_STATUS, tmp_regval); } else { PRINTK(ERROR_MSG, "ax88180: Unknown PHY chipset!!\n"); //allan9 add for debugging DISPLAY_ALLPHYREG; } } PRINTK(INIT_MSG, "ax88180: PHY_Addr=0x%lx, PHY_ID=0x%04x, media=%d\n", pax88180_local->PhyAddr, (unsigned int)pax88180_local->PhyID0, media); switch (pax88180_local->MediaMode) { default: case MEDIA_AUTO: PRINTK(INIT_MSG, "ax88180: The meida mode is autosense.\n"); pax88180_local->ForceMedia = AUTO_MEDIA; aux_1000_ctrl = DEFAULT_AUX_1000_CTRL; anar_val = (ANAR_PAUSE | ANAR_100FULL | ANAR_100HALF | ANAR_10FULL | ANAR_10HALF | ANAR_8023BIT); break; case MEDIA_100FULL: PRINTK(INIT_MSG, "ax88180: The meida mode is forced to 100full.\n"); pax88180_local->ForceMedia = FORCE_MEDIA; aux_1000_ctrl = 0; anar_val = (ANAR_PAUSE | ANAR_100FULL | ANAR_8023BIT); break; case MEDIA_100HALF: PRINTK(INIT_MSG, "ax88180: The meida mode is forced to 100half.\n"); pax88180_local->ForceMedia = FORCE_MEDIA; aux_1000_ctrl = 0; anar_val = (ANAR_100HALF | ANAR_8023BIT); break; case MEDIA_10FULL: PRINTK(INIT_MSG, "ax88180: The meida mode is forced to 10full.\n"); pax88180_local->ForceMedia = FORCE_MEDIA; aux_1000_ctrl = 0; anar_val = (ANAR_PAUSE | ANAR_10FULL | ANAR_8023BIT); break; case MEDIA_10HALF: PRINTK(INIT_MSG, "ax88180: The meida mode is forced to 10half.\n"); pax88180_local->ForceMedia = FORCE_MEDIA; aux_1000_ctrl = 0; anar_val = (ANAR_10HALF | ANAR_8023BIT); break; } WRITE_PHYREG(pax88180_local->PhyAddr, AUX_1000_CTRL, aux_1000_ctrl); WRITE_PHYREG(pax88180_local->PhyAddr, ANAR, anar_val); /* Enable and restart auto-negotiation operation */ bmcr_val = (AUTONEG_EN | RESTART_AUTONEG); WRITE_PHYREG(pax88180_local->PhyAddr, BMCR, bmcr_val); /* Waiting 5 secs for PHY link stable */ PRINTK(DRIVER_MSG, "ax88180: Waiting for auto-negotiation completion......\n"); for (i = 0; i < 5000; i++) { READ_PHYREG(pax88180_local->PhyAddr, BMSR, bmsr_val); if (bmsr_val & LINKOK) { break; } mdelay(1); } //allan9 add for debugging DISPLAY_ALLPHYREG; PRINTK(INIT_MSG, "ax88180: ax88180_PHY_initial end ..........\n"); return;}/* ***************************************************************************** * ax88180_meida_config() * * Configure MAC registers (RXCFG, MACCFG0, MACCFG1) to match the real PHY media mode. * ***************************************************************************** */static void ax88180_meida_config(struct net_device *global_dev){ struct _AX88180_PRIVATE *pax88180_local; unsigned long bmcr_val, bmsr_val; unsigned long rxcfg_val, maccfg0_val, maccfg1_val; int i; pax88180_local = (struct _AX88180_PRIVATE *) global_dev->priv; PRINTK(INIT_MSG, "ax88180: ax88180_meida_config beginning ..........\n"); /* Waiting 200 msecs for PHY link stable */ for (i = 0; i < 200; i++) { READ_PHYREG(pax88180_local->PhyAddr, BMSR, bmsr_val); if (bmsr_val & LINKOK) { break; } mdelay(1); } //allan9 add for debugging// DISPLAY_ALLPHYREG; READ_PHYREG(pax88180_local->PhyAddr, BMSR, bmsr_val); if (bmsr_val & LINKOK) { READ_PHYREG(pax88180_local->PhyAddr, BMCR, bmcr_val); if (bmcr_val & AUTONEG_EN) { /* Waiting for Auto-negotiation completion */ PRINTK(INIT_MSG, "ax88180: Auto-negotiation is enabled. Waiting for NWay completion.....\n"); for (i = 0; i < 5000; i++) { if (bmsr_val & AUTONEG_COMPLETE) { break; } mdelay(1); READ_PHYREG(pax88180_local->PhyAddr, BMSR, bmsr_val); } if (i >= 5000) PRINTK(INIT_MSG, "ax88180: Auto-negotiation is NOT completed!!\n"); } else PRINTK(INIT_MSG, "ax88180: Auto-negotiation is disabled.\n"); PRINTK(DEBUG_MSG, "ax88180: BMCR=0x%04x, BMSR=0x%04x\n", (unsigned int)bmcr_val, (unsigned int)bmsr_val); /* Get real media mode here */ if (pax88180_local->PhyID0 == MARVELL_88E1111_PHYIDR0) { get_MarvellPHY_meida_mode(global_dev); } else if (pax88180_local->PhyID0 == CICADA_CIS8201_PHYIDR0) { get_CicadaPHY_meida_mode(global_dev); } else { pax88180_local->RealMediaMode = MEDIA_1000FULL; } switch (pax88180_local->RealMediaMode) { default: case MEDIA_1000FULL: PRINTK(DRIVER_MSG, "ax88180: Set to 1000Mbps Full-duplex mode.\n"); pax88180_local->LineSpeed = SPEED_1000; pax88180_local->DuplexMode = DUPLEX_FULL; rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG; maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0; maccfg1_val = GIGA_MODE_EN | RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -