📄 1022.ethernet.patch
字号:
+ /* Reset the PHY */+ phy_cntl = BMCR_RESET;+ if (private->phy_loopback)+ phy_cntl |= BMCR_LOOPBACK;+ DBG_PRINT("%s: Reset PHY\n", __func__);+ mdio_write(dev, mii_if->phy_id, MII_BMCR, phy_cntl);+ /* Wait up to 5 seconds for the reset to complete */+ for (timeout = 10; timeout != 0; timeout--) {+ phy_cntl = mdio_read(dev, mii_if->phy_id, MII_BMCR);+ if (!(phy_cntl & BMCR_RESET))+ break;+ /* Wait 500 milliseconds */+ wait_ms(500);+ }+ if (timeout == 0) {+ DBG_PRINT("PHY reset timeout\n");+ goto out;+ }+ /* Read phy & advertising capabilities */+ DBG_PRINT("%s: set up caps\n", __func__);+ phy_caps = mdio_read(dev, mii_if->phy_id, MII_BMSR);+ ad_caps = ADVERTISE_CSMA;+ if (phy_caps & BMSR_100BASE4)+ ad_caps |= ADVERTISE_100BASE4;+ if (phy_caps & BMSR_100FULL)+ ad_caps |= ADVERTISE_100FULL;+ if (phy_caps & BMSR_100HALF)+ ad_caps |= ADVERTISE_100HALF;+ if (phy_caps & BMSR_10FULL)+ ad_caps |= ADVERTISE_10FULL;+ if (phy_caps & BMSR_10HALF)+ ad_caps |= ADVERTISE_10HALF;++ /* Update auto-negociation advertisement register */+ mdio_write(dev, mii_if->phy_id, MII_ADVERTISE, ad_caps);+ /* Read the register back. Some (buggy) PHY won't negociate properly+ * if this is not done.+ */+ status = mdio_read(dev, mii_if->phy_id, MII_ADVERTISE);+ timeout = 30;+ /* Restart auto-negociation with our new advertisement capabilities */+ DBG_PRINT("%s: start autonegociation\n", __func__);+ restart_autoneg:+ phy_cntl = BMCR_ANRESTART | BMCR_ANENABLE;+ if (private->phy_loopback)+ phy_cntl |= BMCR_LOOPBACK;+ mdio_write(dev, mii_if->phy_id, MII_BMCR, phy_cntl);+ /* Wait for the auto-negociation to complete.+ * This can take up to 3 seconds.+ */+ for (; timeout != 0; timeout--) {+ status = mdio_read(dev, mii_if->phy_id, MII_BMSR);+ if (status & BMSR_ANEGCOMPLETE)+ break;+ if (status & BMSR_RFAULT) {+ /* In case of remote fault, restart negociation */+ DBG_PRINT("%s: restart autonegociation\n", __func__);+ goto restart_autoneg;+ }+ wait_ms(100);+ }+ status = mdio_read(dev, mii_if->phy_id, MII_BMSR);+ if (!(status & BMSR_ANEGCOMPLETE))+ DBG_PRINT("Auto-negociation timeout\n");+ else if (status & BMSR_RFAULT)+ DBG_PRINT("Auto-negociation remote fault\n");+ else+ DBG_PRINT("Auto-negociation done\n");++ netdev_get_settings(dev, &cmd);+ dump_ethtool_cmd(&cmd);+ out:+ private->autoneg_active = 0;+ DBG_PRINT_INOUT_FUNC("END");+}++/* PHY detection */+/* XXX: to be moved into mii.c */+int phy_detect (struct net_device *dev, struct mii_if_info *mii_if)+{+ int phy_n;+ int mii_status, phy_id1, phy_id2;+ + DBG_PRINT_INOUT_FUNC("START");+ mii_if->dev = dev;+ mii_if->mdio_read = mdio_read;+ mii_if->mdio_write = mdio_write;+ mii_if->phy_id_mask = 0x1f;+ mii_if->reg_num_mask = 0x1f;+ mii_if->phy_id = -1; /* No PHY found */+ for (phy_n = 0; phy_n < 32; phy_n++) {+ DBG_PRINT("%s: check PHY %d\n", __func__, phy_n);+ mii_status = mdio_read(dev, phy_n, MII_BMSR);+ phy_id1 = mdio_read(dev, phy_n, MII_PHYSID1);+ phy_id2 = mdio_read(dev, phy_n, MII_PHYSID2);+ /* PHY_ID1 is zero in some realtek PHYs */+ if (/*phy_id1 > 0 &&*/ phy_id1 < 0xFFFF && phy_id1 != 0x8000 &&+ phy_id2 > 0 && phy_id2 < 0xFFFF && phy_id2 != 0x8000 &&+ mii_status != 0xffff && mii_status != 0x0000) {+ mii_if->advertising = mdio_read(dev, phy_n, 4);+ mii_if->phy_id = phy_n;+ DBG_PRINT(KERN_INFO "%s: MII PHY found at address %d, status "+ "0x%4.4x advertising %4.4x Link %4.4x.\n",+ dev->name, phy_n, mii_status, mii_if->advertising,+ mdio_read(dev, phy_n, 5));+ /* set IFF_RUNNING */+ if (mii_status & BMSR_LSTATUS) {+ DBG_PRINT("%s: netif_carrier_on\n", __func__);+ netif_carrier_on(dev);+ }+ else {+ DBG_PRINT("%s: netif_carrier_off\n", __func__);+ netif_carrier_off(dev);+ }+ break;+ }+ }+ if (phy_n == 32) {+ DBG_PRINT("failed to detect PHY\n");+ return -1;+ }+ + DBG_PRINT_INOUT_FUNC("END");+ return phy_n;+}++/* Getting MAC address from local RAM */+static int get_mac_address(unsigned long *mac_lo, unsigned long *mac_hi)+{+ unsigned long cksum, lo, hi;+ const unsigned char marker = 'M';+ + DBG_PRINT_INOUT_FUNC("START");+ lo = em86xx_read_reg(REG_BASE_cpu_block + LR_ETH_MAC_LO);+ hi = em86xx_read_reg(REG_BASE_cpu_block + LR_ETH_MAC_HI);++ if (((unsigned char)((hi >> 16) & 0xff)) != marker)+ return(1); /* Not valid MAC */+ cksum = ((lo & 0xff) + ((lo >> 8) & 0xff) + ((lo >> 16) & 0xff) + ((lo >> 24) & 0xff) + + (hi & 0xff) + ((hi >> 8) & 0xff)) & 0xff;+ if (((hi >> 24) & 0xff) != cksum)+ return(1); /* Not valid MAC */+ *mac_lo = lo;+ *mac_hi = hi & 0xffff;++ DBG_PRINT_INOUT_FUNC("END");+ return(0); /* Got valid MAC */+}++/* Get the device mac address */+static int em86xx_get_macaddr(unsigned char *addr)+{+ DBG_PRINT_INOUT_FUNC("START");+#if defined(CONFIG_TANGO2) && (defined(CONFIG_TANGO2_SIG_BLOCK) || defined(CONFIG_TANGO2_XENV))+ unsigned long hi, lo;+ if (get_mac_address(&lo, &hi) == 0) {+ *addr++ = (hi & 0x0000ff00) >> 8;+ *addr++ = (hi & 0x000000ff);+ *addr++ = (lo & 0xff000000) >> 24;+ *addr++ = (lo & 0x00ff0000) >> 16;+ *addr++ = (lo & 0x0000ff00) >> 8;+ *addr = (lo & 0x000000ff);+ } else if (tango2_ethernet_getmac(addr) == 0) {+ *addr++ = (def_mac_hi & 0x0000ff00) >> 8;+ *addr++ = (def_mac_hi & 0x000000ff);+ *addr++ = (def_mac_lo & 0xff000000) >> 24;+ *addr++ = (def_mac_lo & 0x00ff0000) >> 16;+ *addr++ = (def_mac_lo & 0x0000ff00) >> 8;+ *addr = (def_mac_lo & 0x000000ff);+ }+#else+#ifdef BOOTLOADER+ if( mac_read(addr) == -1) {+ *addr++ = (def_mac_hi & 0x0000ff00) >> 8;+ *addr++ = (def_mac_hi & 0x000000ff);+ *addr++ = (def_mac_lo & 0xff000000) >> 24;+ *addr++ = (def_mac_lo & 0x00ff0000) >> 16;+ *addr++ = (def_mac_lo & 0x0000ff00) >> 8;+ *addr = (def_mac_lo & 0x000000ff);+ }+#else+#ifdef CONFIG_SD_BOOTLOADER_INTEGRATION+ {+ unsigned long lo, hi;++ if (get_mac_address(&lo, &hi) == 0) {+ def_mac_hi = hi;+ def_mac_lo = lo;+ }+ }+#endif+ *addr++ = (def_mac_hi & 0x0000ff00) >> 8;+ *addr++ = (def_mac_hi & 0x000000ff);+ *addr++ = (def_mac_lo & 0xff000000) >> 24;+ *addr++ = (def_mac_lo & 0x00ff0000) >> 16;+ *addr++ = (def_mac_lo & 0x0000ff00) >> 8;+ *addr = (def_mac_lo & 0x000000ff);+#endif /* BOOTLOADER */ +#endif /* CONFIG_TANGO2 && (CONFIG_TANGO2_SIG_BLOCK || CONFIG_TANGO2_XENV) */+ DBG_PRINT_INOUT_FUNC("END");+ return 0;+}++/* Setting up MAC address of ethernet PHY and device data */+static int em86xx_set_mac(struct net_device *dev)+{+ unsigned long hi_mac, low_mac;++ DBG_PRINT_INOUT_FUNC("START");+ /* Set up device mac address */+ if (em86xx_get_macaddr(dev->dev_addr))+ return(-EIO);++ if (!is_valid_ether_addr(dev->dev_addr))+ MSG_PRINT("%s: bogus mac address detected.\n", dev->name);++ hi_mac = (dev->dev_addr[5] << 8) | dev->dev_addr[4];+ low_mac = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | + (dev->dev_addr[1] << 8) | dev->dev_addr[0];++ /* Set up MAC address */+ em86xx_write_reg(EM86XX_MACAHR_REG, hi_mac);+ em86xx_write_reg(EM86XX_MACALR_REG, low_mac);++ DBG_PRINT_INOUT_FUNC("END");+ return 0;+}++#ifndef BOOTLOADER+/* Setting customized mac address */+static int em86xx_eth_set_macaddr(struct net_device *dev, void *addr)+{+ unsigned long hi_mac, low_mac;++ DBG_PRINT_INOUT_FUNC("START");+ /* Check if given address is valid ethernet MAC address */+ if (!is_valid_ether_addr(addr))+ return(-EIO);++ /* Turn off IRQ and stop receive/transmit */+ em86xx_write_reg(EM86XX_CR_REG, 0);+ em86xx_write_reg(EM86XX_IER_REG, 0);++ netif_carrier_off(dev); /* Shutdown interface */++ /* Save the customize mac address */+ memcpy(dev->dev_addr, addr, 6);+ hi_mac = (dev->dev_addr[5] << 8) | dev->dev_addr[4];+ low_mac = (dev->dev_addr[3] << 24)| (dev->dev_addr[2] << 16) | + (dev->dev_addr[1] << 8) | dev->dev_addr[0];++ def_mac_hi = hi_mac;+ def_mac_lo = low_mac;++ /* Set up MAC address */+ em86xx_write_reg(EM86XX_MACAHR_REG, hi_mac );+ em86xx_write_reg(EM86XX_MACALR_REG, low_mac );++ netif_carrier_off(dev);++ DBG_PRINT_INOUT_FUNC("END");+ return 0;+}+#endif /* BOOTLOADER */++/* RTL8201BL is a single-port PHY with an MII/SNI. The MAC layer device can + control a maximum of 31 devices, configured with different PHY addresses+ (00001b to 11111b). We need to find out which PHY address is using in + order to obtain the mode status after the auto-neotiation is completed.++ There is a module parameter phy_address to be used to override this probe,+ to set PHY address if one already knew it.+*/+static int em86xx_phy_probe(void)+{++ int phy_addr = 0;+ u16 phy_id = 0;+ u16 phy_status = 0;++ DBG_PRINT_INOUT_FUNC("START");+ if (phy_address < 0) {+ /* search for total of 31 possible mii phy addresses */+ for (phy_addr = 1; phy_addr < 32; phy_addr++) {+ phy_status = em86xx_mii_read(phy_addr,GEN_sts);++ if (phy_status != 0xffff && phy_status != 0x0000)+ break;+ }+ } else {+ phy_addr = phy_address;+ phy_status = em86xx_mii_read(phy_addr,GEN_sts);+ }+ phy_id = em86xx_mii_read(phy_addr,GEN_id_lo);+ MSG_PRINT("Found PHY %04x at Addr = %d Status=0x%x\n", phy_id, phy_addr, phy_status);+ + DBG_PRINT_INOUT_FUNC("END");+ return phy_addr;+}++/* Initialize the ethernet link status, mac, and flow control */+static int em86xx_link_config(struct net_device *dev)+{+ EM86XX_ETH_PRIV *private = (EM86XX_ETH_PRIV *)dev->priv;+ struct mii_if_info *mii = &(private->mii_if);+ unsigned long word = 0;++ DBG_PRINT_INOUT_FUNC("START");++ // Turn off IRQ and stop receive/transmit + em86xx_write_reg(EM86XX_CR_REG, 0);+ em86xx_write_reg(EM86XX_IER_REG, 0);++ setup_phy(mii);++ /* set the descriptor base address */+ em86xx_write_reg(EM86XX_RLBAR_REG, PHYSADDR((u32)private->rxdsc) );+ em86xx_write_reg(EM86XX_TLBAR_REG, PHYSADDR((u32)private->txdsc));++ /* set bus mode: burst length = 32 | BLE | ~DBO */+ word = (32 << 8) /*| (1 << 7) | (1 << 20)*/ ;+ em86xx_write_reg(EM86XX_BMR_REG, word); ++ /* enable MAC flow ctrl */+ word = (1 << 1);+ em86xx_write_reg(EM86XX_FCR_REG, word); ++ /* configure MAC ctrller */+ word = ETH_MAC_FLAGS;+ word |= MacLoopbackOff; + if (mii->full_duplex)+ word |= MacFullDuplex;+ else+ word &= ~MacFullDuplex;+ em86xx_write_reg(EM86XX_MACCR_REG, word);++ /* Turn on the IRQ and start receive/transmit */+ em86xx_write_reg(EM86XX_IER_REG, ETH_IRQ_FLAGS);+ em86xx_write_reg(EM86XX_CR_REG, ETH_RXTX_FLAGS); ++ netif_carrier_on(dev);++ DBG_PRINT_INOUT_FUNC("END");+ return 0;+}++/* Ethernet hardware initialization */+static int em86xx_eth_hw_init(struct net_device *dev)+{+ EM86XX_ETH_PRIV *private = (EM86XX_ETH_PRIV *)dev->priv;+ int rc;++ DBG_PRINT_INOUT_FUNC("START");++ /* Turn off IRQ and stop receive/transmit */+ em86xx_write_reg(EM86XX_CR_REG, 0);+ em86xx_write_reg(EM86XX_IER_REG, 0);++ /* reset dma engine*/+ em86xx_write_reg(EM86XX_BMR_REG, DmaResetOn);+ em86xx_write_reg(EM86XX_BMR_REG, DmaResetOff);++ if (em86xx_set_mac(dev))+ return(-EIO);++ /* stop MAC engine */+ em86xx_write_reg(EM86XX_CR_REG, 0x0); +#ifndef USE_HW_FILTERING+ /* set up multicast hash table to MCHTHR MCHTLR */+ /* set multicast hash table to accept all */+ em86xx_write_reg(EM86XX_MCHTHR_REG, 0xffffffff); + em86xx_write_reg(EM86XX_MCHTLR_REG, 0xffffffff); +#else+ /* clear hash table */+ em86xx_write_reg( EM86XX_MCHTHR_REG, 0 );+ em86xx_write_reg( EM86XX_MCHTLR_REG, 0 );++ em86xx_eth_set_multicast_list(dev);+#endif++ /* resetting descriptors */+#ifdef BOOTLOADER+ if (em86xx_eth_reset_desc(dev, &private->reset_flag))+#else+ if (em86xx_eth_reset_desc(&em86xx_eth_dev, &private->reset_flag))+#endif+ return(-EIO);++ /* configure PHY and speed */+ rc = em86xx_link_config(dev);+ DBG_PRINT_INOUT_FUNC("END");+ return rc;+}++#ifndef BOOTLOADER+/* Monitor the status of link, re-do link initialization if necessary. */+#ifdef USE_KERNEL_TIMER+static void em86xx_eth_link_monitor(unsigned long dummy)+#else+static int em86xx_eth_link_monitor(void *dummy)+#endif+{+ struct net_device *dev = (struct net_device *)dummy;+ EM86XX_ETH_PRIV *private = (EM86XX_ETH_PRIV *)dev->priv;+ unsigned long flags;+ int link;+ int res;++ DBG_PRINT_INOUT_FUNC("START");++#ifndef USE_KERNEL_TIMER+ strcpy(current->comm, "em86xx_eth");+ daemonize();+ reparent_to_init();++ while (private->stop_thread == 0) {+#endif+ spin_lock_irqsave(&private->lock, flags);+ link = mii_link_ok(&private->mii_if);+ spin_unlock_irqrestore(&private->lock, flags);+ + if (netif_carrier_ok(dev) && !link) { + MSG_PRINT("%s: detected link DOWN.\n", dev->name);+ netif_carrier_off(dev);+ }+ else if (!netif_carrier_ok(dev) && link) {+ MSG_PRINT("%s: detected link UP.\n", dev->name);+ res = em86xx_eth_hw_init(dev);+ netif_carrier_on(dev);+ }++#ifndef USE_KERNEL_TIMER+ set_current_state(TASK_UNINTERRUPTIBLE);+ schedule_timeout(HZ);+ }+#endif++#ifdef USE_KERNEL_TIMER+ /* Schedule for the next time */+ mod_timer(&private->eth_timer, jiffies + HZ); + DBG_PRINT_INOUT_FUNC("END (with timer)");+#else+ DBG_PRINT_INOUT_FUNC("END (IRQ)");+ return(0);+#endif+}+#endif++/* Setting rx/tx descriptors */+static void em86xx_eth_setup_desc(struct net_device *dev)+{+ register int i;+ struct em86xx_desc *desc_ptr = NULL;+ unsigned long base_addr = 0;+ EM86XX_ETH_PRIV *private = (EM86XX_ETH_PRIV *)dev->priv;++ DBG_PRINT_INOUT_FUNC("START");+ /* Setup rx descriptor */+ desc_ptr = (struct em86xx_desc *)(private->rxdsc);+ for (i = 0; i < (private->num_rxdesc - 1); i++, desc_ptr++) {+ desc_ptr->desc3 = PHYSADDR((unsigned long)(desc_ptr + 1));+ desc_ptr->desc1 = (DescChain | R_BUF_SIZE);+ desc_ptr->desc0 = DescOwnByDma; + }+ desc_ptr->desc3 = PHYSADDR((unsigned long)(private->rxdsc));+ desc_ptr->desc1 = (DescChain | DescEndOfRing | R_BUF_SIZE);+ desc_ptr->desc0 = De
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -