zoukankan      html  css  js  c++  java
  • OK335xS 网络连接打印信息 hacking

    /***********************************************************************
     *                 OK335xS 网络连接打印信息 hacking
     * 说明:
     *     当我们插入网线的时候,经常会看到对应的网卡已连接,当前属于10M、
     * 100M网卡工作状态等等信息,那么这些信息是如何被输出的,工作机制是什么,
     * 网卡的速度是由phy决定的还是由mac决定的,是不是在phy对应的中断里处理,
     * 等等,这些内容都需要去确认。
     *
     *                                      2016-2-2 深圳 南山平山村 曾剑锋
     **********************************************************************/
    
    /**
     * 参考文章:
     *     Linux PHY几个状态的跟踪
     *         http://www.latelee.org/programming-under-linux/linux-phy-state.html
     */
    
    static const struct dev_pm_ops cpsw_pm_ops = {   <------+
        .suspend    = cpsw_suspend,                         |
        .resume        = cpsw_resume,                -----------+
    };                                                      |   |
                                                            |   |
    static struct platform_driver cpsw_driver = {       <---|-+ |
        .driver = {                                         | | |
            .name     = "cpsw",                             | | |
            .owner     = THIS_MODULE,                       | | |
            .pm     = &cpsw_pm_ops,               ----------+ | |
        },                                                    | |
        .probe = cpsw_probe,                                  | |
        .remove = __devexit_p(cpsw_remove),                   | |
    };                                                        | |
                                                              | |
    static int __init cpsw_init(void)                         | |
    {                                                         | |
        return platform_driver_register(&cpsw_driver);   -----+ |
    }                                                           |
    late_initcall(cpsw_init);                                   |
                                                                |
    static void __exit cpsw_exit(void)                          |
    {                                                           |
        platform_driver_unregister(&cpsw_driver);               |
    }                                                           |
    module_exit(cpsw_exit);                                     |
                                                                |
    MODULE_LICENSE("GPL");                                      |
    MODULE_DESCRIPTION("TI CPSW Ethernet driver");              |
                                                                |
                                                                |
                                                                |
    static int cpsw_resume(struct device *dev)       <----------+
    {
        struct platform_device    *pdev = to_platform_device(dev);
        struct net_device    *ndev = platform_get_drvdata(pdev);
    
        pm_runtime_get_sync(&pdev->dev);
        cpsw_start_slaves_interface(ndev); ----+
                                               |
        return 0;                              |
    }                                          |
                                               |
                                               V
    static inline void cpsw_start_slaves_interface(struct net_device *ndev)
    {
        struct cpsw_priv *priv = netdev_priv(ndev);
        u32 i = 0;
    
        for (i = 0; i < priv->data.slaves; i++) {
            ndev = cpsw_get_slave_ndev(priv, i);
            if (netif_running(ndev))
                cpsw_ndo_open(ndev);           ----------+
        }                                                |
    }                                                    |
                                                         |
                                                         |
    static int cpsw_ndo_open(struct net_device *ndev) <--+
    {
        struct cpsw_priv *priv = netdev_priv(ndev);
        int i, ret;
        u32 reg;
    
        if (!cpsw_common_res_usage_state(priv))
            cpsw_intr_disable(priv);
        netif_carrier_off(ndev);
    
        if (priv->data.phy_control)
            (*priv->data.phy_control)(true);
    
        reg = __raw_readl(&priv->regs->id_ver);
        priv->version = reg;
    
        msg(info, ifup, "initializing cpsw version %d.%d (%d)
    ",
            (reg >> 8 & 0x7), reg & 0xff, (reg >> 11) & 0x1f);
    
        /* initialize host and slave ports */
        if (!cpsw_common_res_usage_state(priv))
            cpsw_init_host_port(priv);
        for_each_slave(priv, cpsw_slave_open, priv);          -----------+
                                                                         |
        /* Add default VLAN */                                           |
        cpsw_add_default_vlan(priv);                                     |
                                                                         |
        if (!cpsw_common_res_usage_state(priv)) {                        |
            ret = device_create_file(&ndev->dev, &dev_attr_hw_stats);    |
            if (ret < 0) {                                               |
                dev_err(priv->dev, "unable to add device attr
    ");       |
                return ret;                                              |
            }                                                            |
                                                                         |
            /* setup tx dma to fixed prio and zero offset */             |
            cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);        |
            cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);     |
                                                                         |
            /* disable priority elevation and enable statistics */       |
            /* on all ports */                                           |
            writel(0, &priv->regs->ptype);                               |
            writel(0x7, &priv->regs->stat_port_en);                      |
                                                                         |
            if (WARN_ON(!priv->data.rx_descs))                           |
                priv->data.rx_descs = 128;                               |
                                                                         |
            for (i = 0; i < priv->data.rx_descs; i++) {                  |
                struct sk_buff *skb;                                     |
                                                                         |
                ret = -ENOMEM;                                           |
                skb = netdev_alloc_skb_ip_align(priv->ndev,              |
                                priv->rx_packet_max);                    |
                if (!skb)                                                |
                    break;                                               |
                ret = cpdma_chan_submit(priv->rxch, skb, skb->data,      |
                        skb_tailroom(skb), 0, GFP_KERNEL);               |
                if (WARN_ON(ret < 0)) {                                  |
                    dev_kfree_skb_any(skb);                              |
                    break;                                               |
                }                                                        |
            }                                                            |
            /*                                                           |
             * continue even if we didn't manage to submit all           |
             * receive descs                                             |
             */                                                          |
            msg(info, ifup, "submitted %d rx descriptors
    ", i);         |
                                                                         |
            if (cpts_register(&priv->pdev->dev, priv->cpts,              |
                      priv->data.cpts_clock_mult,                        |
                      priv->data.cpts_clock_shift))                      |
                dev_err(priv->dev, "error registering cpts device
    ");   |
        }                                                                |
                                                                         |
        /* Enable Interrupt pacing if configured */                      |
        if (priv->coal_intvl != 0) {                                     |
            struct ethtool_coalesce coal;                                |
                                                                         |
            coal.rx_coalesce_usecs = (priv->coal_intvl << 4);            |
            cpsw_set_coalesce(ndev, &coal);                              |
        }                                                                |
                                                                         |
        /* Enable Timer for capturing cpsw rx interrupts */              |
        omap_dm_timer_set_int_enable(dmtimer_rx, OMAP_TIMER_INT_CAPTURE);|
        omap_dm_timer_set_capture(dmtimer_rx, 1, 0, 0);                  |
        omap_dm_timer_enable(dmtimer_rx);                                |
                                                                         |
        /* Enable Timer for capturing cpsw tx interrupts */              |
        omap_dm_timer_set_int_enable(dmtimer_tx, OMAP_TIMER_INT_CAPTURE);|
        omap_dm_timer_set_capture(dmtimer_tx, 1, 0, 0);                  |
        omap_dm_timer_enable(dmtimer_tx);                                |
                                                                         |
        cpdma_ctlr_start(priv->dma);                                     |
        cpsw_intr_enable(priv);                                          |
        napi_enable(&priv->napi);                                        |
        cpdma_ctlr_eoi(priv->dma);                                       |
                                                                         |
        cpsw_update_slave_open_state(priv, true)                         |
                                                                         |
        return 0;        +-----------------------------------------------+
    }                    |
                         |
                         V
    static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
    {
        char name[32];
        u32 slave_port;
    
        sprintf(name, "slave-%d", slave->slave_num);
    
        soft_reset(name, &slave->sliver->soft_reset);
    
        /* setup priority mapping */
        writel(0x76543210, &slave->sliver->rx_pri_map);
        if (priv->version == CPSW_VERSION1)
            slave_write(slave, 0x33221100, CPSW1_TX_PRI_MAP);
        else
            slave_write(slave, 0x33221100, CPSW2_TX_PRI_MAP);
    
        /* setup max packet size, and mac address */
        __raw_writel(priv->rx_packet_max, &slave->sliver->rx_maxlen);
        cpsw_set_slave_mac(slave, priv);
    
        slave->mac_control = 0;    /* no link yet */
    
        slave_port = cpsw_get_slave_port(priv, slave->slave_num);
    
        cpsw_add_dual_emac_mode_default_ale_entries(priv, slave, slave_port);
        cpsw_add_switch_mode_bcast_ale_entries(priv, slave_port);
        priv->port_state[slave_port] = ALE_PORT_STATE_FORWARD;
    
        slave->phy = phy_connect(priv->ndev, slave->data->phy_id,   ------+
                     &cpsw_adjust_link, 0, slave->data->phy_if);    ------*--------+
        if (IS_ERR(slave->phy)) {                                         |        |
            msg(err, ifup, "phy %s not found on slave %d
    ",              |        |
                slave->data->phy_id, slave->slave_num);                   |        |
            slave->phy = NULL;                                            |        |
        } else {                                                          |        |
            dev_info(priv->dev, "CPSW phy found : id is : 0x%x
    ",        |        |
                slave->phy->phy_id);                                      |        |
            cpsw_set_phy_config(priv, slave->phy);                        |        |
            phy_start(slave->phy);                                        |        |
        }                     +-------------------------------------------+        |
    }                         |                                                    |
                              |                                                    |
                              V                                                    |
    struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,    |
            void (*handler)(struct net_device *), u32 flags,                       |
            phy_interface_t interface)                                             |
    {                                                                              |
        struct phy_device *phydev;                                                 |
        struct device *d;                                                          |
        int rc;                                                                    |
                                                                                   |
        /* Search the list of PHY devices on the mdio bus for the                  |
         * PHY with the requested name */                                          |
        d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);                 |
        if (!d) {                                                                  |
            pr_err("PHY %s not found
    ", bus_id);                                  |
            return ERR_PTR(-ENODEV);                                               |
        }                                                                          |
        phydev = to_phy_device(d);                                                 |
                                                                                   |
        rc = phy_connect_direct(dev, phydev, handler, flags, interface); ----+     |
        if (rc)                                                              |     |
            return ERR_PTR(rc);                                              |     |
                                                                             |     |
        return phydev;                                                       |     |
    }                                                                        |     |
    EXPORT_SYMBOL(phy_connect);                                              |     |
                  +----------------------------------------------------------+     |
                  V                                                                |
    int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,      |
                   void (*handler)(struct net_device *), u32 flags,                |
                   phy_interface_t interface)                                      |
    {                                                                              |
        int rc;                                                                    |
                                                                                   |
        rc = phy_attach_direct(dev, phydev, flags, interface);                     |
        if (rc)                                                                    |
            return rc;                                                             |
                                                                                   |
        phy_prepare_link(phydev, handler);         ----------------+               |
        phy_start_machine(phydev, NULL);      ---------------------*--------+      |
        if (phydev->irq > 0)                                       |        |      |
            phy_start_interrupts(phydev);                          |        |      |
                                                                   |        |      |
        return 0;                                                  |        |      |
    }                                                              |        |      |
    EXPORT_SYMBOL(phy_connect_direct);                             |        |      |
                                                                   |        |      |
                                                                   |        |      |
    static void phy_prepare_link(struct phy_device *phydev,  <-----+        |      |
            void (*handler)(struct net_device *))                           |      |
    {                                                                       |      |
        phydev->adjust_link = handler;                                      |      |
    }                                                                       |      |
                                                                            |      |
                                                                            |      |
    /**                                                                     |      |
     * phy_start_machine - start PHY state machine tracking                 |      |
     * @phydev: the phy_device struct                                       |      |
     * @handler: callback function for state change notifications           |      |
     *                                                                      |      |
     * Description: The PHY infrastructure can run a state machine          |      |
     *   which tracks whether the PHY is starting up, negotiating,          |      |
     *   etc.  This function starts the timer which tracks the state        |      |
     *   of the PHY.  If you want to be notified when the state changes,    |      |
     *   pass in the callback @handler, otherwise, pass NULL.  If you       |      |
     *   want to maintain your own state machine, do not call this          |      |
     *   function.                                                          |      |
     */                                                                     |      |
    void phy_start_machine(struct phy_device *phydev,        <--------------+      |
            void (*handler)(struct net_device *))                                  |
    {                                                                              |
        phydev->adjust_state = handler;                                            |
                                                                                   |
        schedule_delayed_work(&phydev->state_queue, HZ);                           |
    }                                                                              |
                                                                                   |
                                                                                   |
    static void cpsw_adjust_link(struct net_device *ndev)       <------------------+
    {
        struct cpsw_priv    *priv = netdev_priv(ndev);
        bool            link = false;
    
        for_each_slave(priv, _cpsw_adjust_link, priv, &link);   ----------+
                                                                          |
        if (link) {                                                       |
            netif_carrier_on(ndev);                                       |
            if (netif_running(ndev))                                      |
                netif_wake_queue(ndev);                                   |
        } else {                                                          |
            netif_carrier_off(ndev);                                      |
            netif_stop_queue(ndev);                                       |
        }                                                                 |
    }                                                                     |
                                                                          |
                                                                          |
    static void _cpsw_adjust_link(struct cpsw_slave *slave,      <--------+
                      struct cpsw_priv *priv, bool *link)
    {
        struct phy_device    *phy = slave->phy;
        u32            mac_control = 0;
        u32            slave_port;
    
        if (!phy)
            return;
    
        slave_port = cpsw_get_slave_port(priv, slave->slave_num);
    
        if (phy->link) {
            /* enable forwarding */
            cpsw_ale_control_set(priv->ale, slave_port,
                ALE_PORT_STATE, priv->port_state[slave_port]);
    
            mac_control = priv->data.mac_control;
            if (phy->speed == 10)
                mac_control |= BIT(18); /* In Band mode */
            if (phy->speed == 1000) {
                mac_control |= BIT(7);    /* Enable gigabit mode */
            }
            if (phy->speed == 100)
                mac_control |= BIT(15);
            if (phy->duplex)
                mac_control |= BIT(0);    /* FULLDUPLEXEN    */
            if (phy->interface == PHY_INTERFACE_MODE_RGMII) /* RGMII */
                mac_control |= (BIT(15)|BIT(16));
            *link = true;
        } else {
            cpsw_ale_control_set(priv->ale, slave_port,
                     ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
            mac_control = 0;
        }
    
        if (mac_control != slave->mac_control) {
            phy_print_status(phy);                                    ---------------+
            __raw_writel(mac_control, &slave->sliver->mac_control);                  |
        }                                                                            |
                                                                                     |
        slave->mac_control = mac_control;                                            |
    }                                                                                |
                                                                                     |
    /**                                                                              |
     * phy_print_status - Convenience function to print out the current phy status   |
     * @phydev: the phy_device struct                                                |
     */                                                                              |
    void phy_print_status(struct phy_device *phydev)                   <-------------+
    {
        pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
                phydev->link ? "Up" : "Down");
        if (phydev->link)
            printk(KERN_CONT " - %d/%s", phydev->speed,
                    DUPLEX_FULL == phydev->duplex ?
                    "Full" : "Half");
    
        printk(KERN_CONT "
    ");
    }
    EXPORT_SYMBOL(phy_print_status);
    
    
    /* 
     * 1. LAN8710A/LAN8710Ai datasheet
     *     1. http://ww1.microchip.com/downloads/en/DeviceDoc/8710a.pdf
     *     2. 1.2 General Description
     *         ......
     *         The LAN8710A/LAN8710Ai supports communication with an Ethernet MAC via a standard MII (IEEE 802.3u)/RMII interface. It contains a full-duplex 10-BASE-T/100BASE-TX transceiver and supports 10Mbps (10BASE-T) and 100Mbps (100BASE-TX) operation. The LAN8710A/LAN8710Ai implements auto-negotiation to automatically determine the best possible speed and duplex mode of operation. HP Auto-MDIX support allows the use of direct connect or cross-over LAN cables.
     *         ......
     * 2. 由上面可知,决定网卡的工作速度的是phy自动决定。
     */
  • 相关阅读:
    C# 中的var关键字
    sql中去掉换行符和回车符
    Linq之旅:Linq入门详解(Linq to Objects)
    c# for 和 foreach
    c# Dictionary
    ASP.NET Web.config学习
    c# 装箱与拆箱的概念
    c# List集合学习
    Index was out of range
    C# double保留四位小数
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/5176753.html
Copyright © 2011-2022 走看看