• I.MX6 千兆网卡设置跟踪


    /************************************************************************************
     *                           I.MX6 千兆网卡设置跟踪
     * 说明:
     *     设备只能识别到百兆网卡,跟一下源代码,找一下原因,结果是默认被注释了。
     *                                                  2017-4-5 深圳  南山平山村 曾剑锋
     ***********************************************************************************/
    
    // 1. Linux内核网络部分控制流
    //     http://longerzone.blog.51cto.com/6081195/1154807
    // 2. linux 内核网络,数据发送流程图
    //     http://blog.csdn.net/echoisland/article/details/6993756
    
    
    DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
        /*
         * i.MX6Q/DL maps system memory at 0x10000000 (offset 256MiB), and
         * GPU has a limit on physical address that it accesses, which must
         * be below 2GiB.
         */
        .dma_zone_size    = (SZ_2G - SZ_256M),
        .smp        = smp_ops(imx_smp_ops),
        .map_io        = imx6q_map_io,
        .init_irq    = imx6q_init_irq,
        .init_machine    = imx6q_init_machine,   ----------------+
        .init_late      = imx6q_init_late,                       |
        .dt_compat     = imx6q_dt_compat,                        |
        .reserve     = imx6q_reserve,                            |
        .restart    = mxc_restart,                               |
    MACHINE_END                                                  |
                                                                 |
    static void __init imx6q_init_machine(void)      <-----------+
    {
        struct device *parent;
    
        if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)
            imx_print_silicon_rev("i.MX6QP", IMX_CHIP_REVISION_1_0);
        else
            imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
                     imx_get_soc_revision());
    
        mxc_arch_reset_init_dt();
    
        parent = imx_soc_device_init();
        if (parent == NULL)
            pr_warn("failed to initialize soc device
    ");
    
        of_platform_populate(NULL, of_default_bus_match_table,
                        imx6q_auxdata_lookup, parent);
    
        imx6q_enet_init();                           ------------+
        imx_anatop_init();                                       |
        imx6q_csi_mux_init();                                    |
        cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();    |
        imx6q_mini_pcie_init();                                  |
    }                                                            |
                                                                 |
    static inline void imx6q_enet_init(void)         <-----------+
    {
        imx6_enet_mac_init("fsl,imx6q-fec");         ---------------------------+---------------------+
        imx6q_enet_phy_init();                       ---------------------------*-------------------+ |
        imx6q_1588_init();                                                      |                   | |
        if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)  |                   | |
            imx6q_enet_clk_sel();                                               |                   | |
        imx6q_enet_plt_init();                                                  |                   | |
    }                                                                           |                   | |
                                                                                |                   | |
    void __init imx6_enet_mac_init(const char *compatible)        <-------------+                   | |
    {                                                                                               | |
        struct device_node *ocotp_np, *enet_np, *from = NULL;                                       | |
        void __iomem *base;                                                                         | |
        struct property *newmac;                                                                    | |
        u32 macaddr_low;                                                                            | |
        u32 macaddr_high = 0;                                                                       | |
        u32 macaddr1_high = 0;                                                                      | |
        u8 *macaddr;                                                                                | |
        int i;                                                                                      | |
                                                                                                    | |
        for (i = 0; i < 2; i++) {                                                                   | |
            enet_np = of_find_compatible_node(from, NULL, compatible);                              | |
            if (!enet_np)                                                                           | |
                return;                                                                             | |
                                                                                                    | |
            from = enet_np;                                                                         | |
                                                                                                    | |
            if (of_get_mac_address(enet_np))                                                        | |
                goto put_enet_node;                                                                 | |
                                                                                                    | |
            ocotp_np = of_find_compatible_node(NULL,              --------+                         | |
                NULL, "fsl,imx6q-ocotp");                                 |                         | |
            if (!ocotp_np) {                                              |                         | |
                pr_warn("failed to find ocotp node
    ");                   |                         | |
                goto put_enet_node;                                       |                         | |
            }                                                             |                         | |
                                                                          |                         | |
            base = of_iomap(ocotp_np, 0);                                 |                         | |
            if (!base) {                                                  |                         | |
                pr_warn("failed to map ocotp
    ");                         |                         | |
                goto put_ocotp_node;                                      |                         | |
            }                                                             |                         | |
                                                                          |                         | |
            macaddr_low = readl_relaxed(base + OCOTP_MACn(1));            |                         | |
            if (i)                                                        |                         | |
                macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));      |                         | |
            else                                                          |                         | |
                macaddr_high = readl_relaxed(base + OCOTP_MACn(0));       |                         | |
                                                                          |                         | |
            newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);            |                         | |
            if (!newmac)                                                  |                         | |
                goto put_ocotp_node;                                      |                         | |
                                                                          |                         | |
            newmac->value = newmac + 1;                                   |                         | |
            newmac->length = 6;                                           |                         | |
            newmac->name = kstrdup("local-mac-address", GFP_KERNEL);      |                         | |
            if (!newmac->name) {                                          |                         | |
                kfree(newmac);                                            |                         | |
                goto put_ocotp_node;                                      |                         | |
            }                                                             |                         | |
                                                                          |                         | |
            macaddr = newmac->value;                                      |                         | |
            if (i) {                                                      |                         | |
                macaddr[5] = (macaddr_low >> 16) & 0xff;                  |                         | |
                macaddr[4] = (macaddr_low >> 24) & 0xff;                  |                         | |
                macaddr[3] = macaddr1_high & 0xff;                        |                         | |
                macaddr[2] = (macaddr1_high >> 8) & 0xff;                 |                         | |
                macaddr[1] = (macaddr1_high >> 16) & 0xff;                |                         | |
                macaddr[0] = (macaddr1_high >> 24) & 0xff;                |                         | |
            } else {                                                      |                         | |
                macaddr[5] = macaddr_high & 0xff;                         |                         | |
                macaddr[4] = (macaddr_high >> 8) & 0xff;                  |                         | |
                macaddr[3] = (macaddr_high >> 16) & 0xff;                 |                         | |
                macaddr[2] = (macaddr_high >> 24) & 0xff;                 |                         | |
                macaddr[1] = macaddr_low & 0xff;                          |                         | |
                macaddr[0] = (macaddr_low >> 8) & 0xff;                   |                         | |
            }                                                             |                         | |
                                                                          |                         | |
            of_update_property(enet_np, newmac);                          |                         | |
                                                                          |                         | |
    put_ocotp_node:                                                       |                         | |
        of_node_put(ocotp_np);                                            |                         | |
    put_enet_node:                                                        |                         | |
        of_node_put(enet_np);                                             |                         | |
        }                                                                 |                         | |
    }                             +---------------------------------------+                         | |
                                  V                                                                 | |
    struct device_node *of_find_compatible_node(struct device_node *from,                           | |
        const char *type, const char *compatible)                                                   | |
    {                                                                                               | |
        struct device_node *np;                                                                     | |
        unsigned long flags;                                                                        | |
                                                                                                    | |
        raw_spin_lock_irqsave(&devtree_lock, flags);                                                | |
        np = from ? from->allnext : of_allnodes;        -------------------+                        | |
        for (; np; np = np->allnext) {                                     |                        | |
            if (__of_device_is_compatible(np, compatible, type, NULL) &&   |                        | |
                of_node_get(np))                                           |                        | |
                break;                                                     |                        | |
        }                                                                  |                        | |
        of_node_put(from);                                                 |                        | |
        raw_spin_unlock_irqrestore(&devtree_lock, flags);                  |                        | |
        return np;                                                         |                        | |
    }                                                                      |                        | |
    EXPORT_SYMBOL(of_find_compatible_node);                                |                        | |
                                                                           |                        | |
    struct device_node *of_allnodes;           <---------------------------+                        | |
    EXPORT_SYMBOL(of_allnodes);                ------------+                                        | |
                                                           |                                        | |
    void __init unflatten_device_tree(void)                |                                        | |
    {                                                      V                                        | |
        __unflatten_device_tree(initial_boot_params, &of_allnodes,    ---------+                    | |
                    early_init_dt_alloc_memory_arch);                 ---------*-+                  | |
                                                                               | |                  | |
        /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ | |                  | |
        of_alias_scan(early_init_dt_alloc_memory_arch);               ---------*-*-+                | |
    }                                                                          | | |                | |
                                                                               | | |                | |
    static void __unflatten_device_tree(struct boot_param_header *blob,  <-----+ | |                | |
                     struct device_node **mynodes,                               | |                | |
                     void * (*dt_alloc)(u64 size, u64 align))                    | |                | |
    {                                                                            | |                | |
        unsigned long size;                                                      | |                | |
        int start;                                                               | |                | |
        void *mem;                                                               | |                | |
        struct device_node **allnextp = mynodes;                                 | |                | |
                                                                                 | |                | |
        pr_debug(" -> unflatten_device_tree()
    ");                               | |                | |
                                                                                 | |                | |
        if (!blob) {                                                             | |                | |
            pr_debug("No device tree pointer
    ");                                | |                | |
            return;                                                              | |                | |
        }                                                                        | |                | |
                                                                                 | |                | |
        pr_debug("Unflattening device tree:
    ");                                 | |                | |
        pr_debug("magic: %08x
    ", be32_to_cpu(blob->magic));                     | |                | |
        pr_debug("size: %08x
    ", be32_to_cpu(blob->totalsize));                  | |                | |
        pr_debug("version: %08x
    ", be32_to_cpu(blob->version));                 | |                | |
                                                                                 | |                | |
        if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {                          | |                | |
            pr_err("Invalid device tree blob header
    ");                         | |                | |
            return;                                                              | |                | |
        }                                                                        | |                | |
                                                                                 | |                | |
        /* First pass, scan for size */                                          | |                | |
        start = 0;                                                               | |                | |
        size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); | |                | |
        size = ALIGN(size, 4);                                                   | |                | |
                                                                                 | |                | |
        pr_debug("  size is %lx, allocating...
    ", size);                        | |                | |
                                                                                 | |                | |
        /* Allocate memory for the expanded device tree */                       | |                | |
        mem = dt_alloc(size + 4, __alignof__(struct device_node));               | |                | |
        memset(mem, 0, size);                                                    | |                | |
                                                                                 | |                | |
        *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);                       | |                | |
                                                                                 | |                | |
        pr_debug("  unflattening %p...
    ", mem);                                 | |                | |
                                                                                 | |                | |
        /* Second pass, do actual unflattening */                                | |                | |
        start = 0;                                                               | |                | |
        unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);                | |                | |
        if (be32_to_cpup(mem + size) != 0xdeadbeef)                              | |                | |
            pr_warning("End of tree marker overwritten: %08x
    ",                 | |                | |
                   be32_to_cpup(mem + size));                                    | |                | |
        *allnextp = NULL;                                                        | |                | |
                                                                                 | |                | |
        pr_debug(" <- unflatten_device_tree()
    ");                               | |                | |
    }                                                                            | |                | |
                                                                                 | |                | |
    void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)  <--------+ |                | |
    {                                                                              |                | |
        return memblock_virt_alloc(size, align);                                   |                | |
    }                                                                              |                | |
                                                                                   |                | |
    static inline void * __init memblock_virt_alloc(               <---------------+                | |
                        phys_addr_t size,  phys_addr_t align)                                       | |
    {                                                                                               | |
        return memblock_virt_alloc_try_nid(size, align, BOOTMEM_LOW_LIMIT, -----+                   | |
                            BOOTMEM_ALLOC_ACCESSIBLE,                           |                   | |
                            NUMA_NO_NODE);                                      |                   | |
    }                                                                           |                   | |
                                                                                |                   | |
    void * __init memblock_virt_alloc_try_nid(                      <-----------+                   | |
                phys_addr_t size, phys_addr_t align,                                                | |
                phys_addr_t min_addr, phys_addr_t max_addr,                                         | |
                int nid)                                                                            | |
    {                                                                                               | |
        void *ptr;                                                                                  | |
                                                                                                    | |
        memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF
    ",        | |
                 __func__, (u64)size, (u64)align, nid, (u64)min_addr,                               | |
                 (u64)max_addr, (void *)_RET_IP_);                                                  | |
        ptr = memblock_virt_alloc_internal(size, align,                                             | |
                           min_addr, max_addr, nid);                                                | |
        if (ptr)                                                                                    | |
            return ptr;                                                                             | |
                                                                                                    | |
        panic("%s: Failed to allocate %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx
    ",| |
              __func__, (u64)size, (u64)align, nid, (u64)min_addr,                                  | |
              (u64)max_addr);                                                                       | |
        return NULL;                                                                                | |
    }                                                                                               | |
                                                                                                    | |
    static void __init imx6q_enet_phy_init(void)         <------------------------------------------+ |
    {                                                                                                 |
        if (IS_BUILTIN(CONFIG_PHYLIB)) {                                                              |
            phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,                            |
                    ksz9021rn_phy_fixup);                                                             |
            phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,                            |
                    ksz9031rn_phy_fixup);                                                             |
            phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,                                     |
                    ar8031_phy_fixup);                                                                |
            phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,                                     |
                    ar8035_phy_fixup);                                                                |
        }                                                                                             |
    }                                                                                                 |
                                                                                                      |
    static struct platform_driver fec_driver = {                                                      |
            .driver = {                                                                               |
                    .name   = DRIVER_NAME,                                                            |
                    .owner  = THIS_MODULE,                                                            |
                    .pm     = &fec_pm_ops,                                                            |
                    .of_match_table = fec_dt_ids,                                                     |
            },                                                                                        |
            .id_table = fec_devtype,              -------------+                                      |
            .probe  = fec_probe,                  -------------*------------------+                   |
            .remove = fec_drv_remove,                          |                  |                   |
    };                                                         |                  |                   |
                                                               |                  |                   |
    module_platform_driver(fec_driver);                        |                  |                   |
                                                               |                  |                   |
    static struct platform_device_id fec_devtype[] = {  <------+                  |                   |
        {                                                                         |                   |
            /* keep it for coldfire */                                            |                   |
            .name = DRIVER_NAME,                                                  |                   |
            .driver_data = 0,                                                     |                   |
        }, {                                                                      |                   |
            .name = "imx25-fec",                                                  |                   |
            .driver_data = FEC_QUIRK_USE_GASKET,                                  |                   |
        }, {                                                                      |                   |
            .name = "imx27-fec",                                                  |                   |
            .driver_data = 0,                                                     |                   |
        }, {                                                                      |                   |
            .name = "imx28-fec",                                                  |                   |
            .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,             |                   |
        }, {                                                                      |                   |
            .name = "imx6q-fec",                                       <----------*-------------------+
            .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |   -----------*------+
                    FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |               |      |
                    FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |                    |      |
                    FEC_QUIRK_BUG_WAITMODE,                                       |      |
        }, {                                                                      |      |
            .name = "mvf600-fec",                                                 |      |
            .driver_data = FEC_QUIRK_ENET_MAC,                                    |      |
        }, {                                                                      |      |
            .name = "imx6sx-fec",                                                 |      |
            .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |              |      |
                    FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |               |      |
                    FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |                      |      |
                    FEC_QUIRK_ERR007885 | FEC_QUIRK_TKT210590,                    |      |
        }, {                                                                      |      |
            .name = "imx6ul-fec",                                                 |      |
            .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |              |      |
                    FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |               |      |
                    FEC_QUIRK_HAS_VLAN,                                           |      |
        }, {                                                                      |      |
            /* sentinel */                                                        |      |
        }                                                                         |      |
    };                                                                            |      |
    MODULE_DEVICE_TABLE(platform, fec_devtype);                                   |      |
                                                                                  |      |
    static int                                                                    |      |
    fec_probe(struct platform_device *pdev)         <-----------------------------+      |
    {                                                                                    |
        struct fec_enet_private *fep;                                                    |
        struct fec_platform_data *pdata;                                                 |
        struct net_device *ndev;                                                         |
        int i, irq, ret = 0;                                                             |
        struct resource *r;                                                              |
        const struct of_device_id *of_id;                                                |
        static int dev_id;                                                               |
        struct device_node *np = pdev->dev.of_node, *phy_node;                           |
        int num_tx_qs;                                                                   |
        int num_rx_qs;                                                                   |
                                                                                         |
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);                            |
                                                                                         |
        /* Init network device */                                                        |
        ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),                       |
                      num_tx_qs, num_rx_qs);                                             |
        if (!ndev)                                                                       |
            return -ENOMEM;                                                              |
                                                                                         |
        SET_NETDEV_DEV(ndev, &pdev->dev);                                                |
                                                                                         |
        /* setup board info structure */                                                 |
        fep = netdev_priv(ndev);                                                         |
                                                                                         |
        of_id = of_match_device(fec_dt_ids, &pdev->dev);                                 |
        if (of_id)                                                                       |
            pdev->id_entry = of_id->data;                                                |
        fep->quirks = pdev->id_entry->driver_data;                                       |
                                                                                         |
        fep->netdev = ndev;                                                              |
        fep->num_rx_queues = num_rx_qs;                                                  |
        fep->num_tx_queues = num_tx_qs;                                                  |
                                                                                         |
    #if !defined(CONFIG_M5272)                                                           |
        /* default enable pause frame auto negotiation */                                |
        if (fep->quirks & FEC_QUIRK_HAS_GBIT)                                            |
            fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;                                   |
    #endif                                                                               |
                                                                                         |
        /* Select default pin state */                                                   |
        pinctrl_pm_select_default_state(&pdev->dev);                                     |
                                                                                         |
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);                              |
        fep->hwp = devm_ioremap_resource(&pdev->dev, r);                                 |
        if (IS_ERR(fep->hwp)) {                                                          |
            ret = PTR_ERR(fep->hwp);                                                     |
            goto failed_ioremap;                                                         |
        }                                                                                |
                                                                                         |
        fep->pdev = pdev;                                                                |
        fep->dev_id = dev_id++;                                                          |
                                                                                         |
        platform_set_drvdata(pdev, ndev);                                                |
                                                                                         |
        fec_enet_of_parse_stop_mode(pdev);                                               |
                                                                                         |
        if (of_get_property(np, "fsl,magic-packet", NULL))                               |
            fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;                                   |
                                                                                         |
        phy_node = of_parse_phandle(np, "phy-handle", 0);                                |
        if (!phy_node && of_phy_is_fixed_link(np)) {                                     |
            ret = of_phy_register_fixed_link(np);                                        |
            if (ret < 0) {                                                               |
                dev_err(&pdev->dev,                                                      |
                    "broken fixed-link specification
    ");                                |
                goto failed_phy;                                                         |
            }                                                                            |
            phy_node = of_node_get(np);                                                  |
        }                                                                                |
        fep->phy_node = phy_node;                                                        |
                                                                                         |
        ret = of_get_phy_mode(pdev->dev.of_node);                                        |
        if (ret < 0) {                                                                   |
            pdata = dev_get_platdata(&pdev->dev);                                        |
            if (pdata)                                                                   |
                fep->phy_interface = pdata->phy;                                         |
            else                                                                         |
                fep->phy_interface = PHY_INTERFACE_MODE_MII;                             |
        } else {                                                                         |
            fep->phy_interface = ret;                                                    |
        }                                                                                |
                                                                                         |
        fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");                                  |
        if (IS_ERR(fep->clk_ipg)) {                                                      |
            ret = PTR_ERR(fep->clk_ipg);                                                 |
            goto failed_clk;                                                             |
        }                                                                                |
                                                                                         |
        fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb");                                  |
        if (IS_ERR(fep->clk_ahb)) {                                                      |
            ret = PTR_ERR(fep->clk_ahb);                                                 |
            goto failed_clk;                                                             |
        }                                                                                |
                                                                                         |
        fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);                                  |
                                                                                         |
        /* enet_out is optional, depends on board */                                     |
        fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");                        |
        if (IS_ERR(fep->clk_enet_out))                                                   |
            fep->clk_enet_out = NULL;                                                    |
                                                                                         |
        fep->ptp_clk_on = false;                                                         |
        mutex_init(&fep->ptp_clk_mutex);                                                 |
                                                                                         |
        /* clk_ref is optional, depends on board */                                      |
        fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");                         |
        if (IS_ERR(fep->clk_ref))                                                        |
            fep->clk_ref = NULL;                                                         |
                                                                                         |
        fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;                        |
        fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");                                  |
        if (IS_ERR(fep->clk_ptp)) {                                                      |
            fep->clk_ptp = NULL;                                                         |
            fep->bufdesc_ex = false;                                                     |
        }                                                                                |
                                                                                         |
        pm_runtime_enable(&pdev->dev);                                                   |
        ret = fec_enet_clk_enable(ndev, true);                                           |
        if (ret)                                                                         |
            goto failed_clk;                                                             |
                                                                                         |
        fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");                            |
        if (!IS_ERR(fep->reg_phy)) {                                                     |
            ret = regulator_enable(fep->reg_phy);                                        |
            if (ret) {                                                                   |
                dev_err(&pdev->dev,                                                      |
                    "Failed to enable phy regulator: %d
    ", ret);                        |
                goto failed_regulator;                                                   |
            }                                                                            |
        } else {                                                                         |
            fep->reg_phy = NULL;                                                         |
        }                                                                                |
                                                                                         |
        fec_reset_phy(pdev);                                                             |
                                                                                         |
        if (fep->bufdesc_ex)                                                             |
            fec_ptp_init(pdev);                                                          |
                                                                                         |
        ret = fec_enet_init(ndev);                      -------------------+             |
        if (ret)                                                           |             |
            goto failed_init;                                              |             |
                                                                           |             |
        for (i = 0; i < FEC_IRQ_NUM; i++) {                                |             |
            irq = platform_get_irq(pdev, i);                               |             |
            if (irq < 0) {                                                 |             |
                if (i)                                                     |             |
                    break;                                                 |             |
                ret = irq;                                                 |             |
                goto failed_irq;                                           |             |
            }                                                              |             |
            ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,    |             |
                           0, pdev->name, ndev);                           |             |
            if (ret)                                                       |             |
                goto failed_irq;                                           |             |
                                                                           |             |
            fep->irq[i] = irq;                                             |             |
        }                                                                  |             |
                                                                           |             |
        ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);            |             |
        if (!ret && irq < FEC_IRQ_NUM)                                     |             |
            fep->wake_irq = fep->irq[irq];                                 |             |
        else                                                               |             |
            fep->wake_irq = fep->irq[0];                                   |             |
                                                                           |             |
        init_completion(&fep->mdio_done);                                  |             |
        ret = fec_enet_mii_init(pdev);                            ---------*-------------*-----+
        if (ret)                                                           |             |     |
            goto failed_mii_init;                                          |             |     |
                                                                           |             |     |
        /* Carrier starts down, phylib will bring it up */                 |             |     |
        netif_carrier_off(ndev);                                           |             |     |
        fec_enet_clk_enable(ndev, false);                                  |             |     |
        pinctrl_pm_select_sleep_state(&pdev->dev);                         |             |     |
                                                                           |             |     |
        ret = register_netdev(ndev);                                       |             |     |
        if (ret)                                                           |             |     |
            goto failed_register;                                          |             |     |
                                                                           |             |     |
        device_init_wakeup(&ndev->dev, fep->wol_flag &                     |             |     |
                   FEC_WOL_HAS_MAGIC_PACKET);                              |             |     |
                                                                           |             |     |
        if (fep->bufdesc_ex && fep->ptp_clock)                             |             |     |
            netdev_info(ndev, "registered PHC device %d
    ", fep->dev_id);  |             |     |
                                                                           |             |     |
        fep->rx_copybreak = COPYBREAK_DEFAULT;                             |             |     |
        INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);           |             |     |
        return 0;                                                          |             |     |
                                                                           |             |     |
    failed_register:                                                       |             |     |
        fec_enet_mii_remove(fep);                                          |             |     |
    failed_mii_init:                                                       |             |     |
    failed_irq:                                                            |             |     |
    failed_init:                                                           |             |     |
        if (fep->reg_phy)                                                  |             |     |
            regulator_disable(fep->reg_phy);                               |             |     |
    failed_regulator:                                                      |             |     |
        fec_enet_clk_enable(ndev, false);                                  |             |     |
    failed_clk:                                                            |             |     |
    failed_phy:                                                            |             |     |
        of_node_put(phy_node);                                             |             |     |
    failed_ioremap:                                                        |             |     |
        free_netdev(ndev);                                                 |             |     |
                                                                           |             |     |
        return ret;                                                        |             |     |
    }                                                                      |             |     |
                                                                           |             |     |
    static int fec_enet_init(struct net_device *ndev)          <-----------+             |     |
    {                                                                                    |     |
        struct fec_enet_private *fep = netdev_priv(ndev);                                |     |
        struct fec_enet_priv_tx_q *txq;                                                  |     |
        struct fec_enet_priv_rx_q *rxq;                                                  |     |
        struct bufdesc *cbd_base;                                                        |     |
        dma_addr_t bd_dma;                                                               |     |
        int bd_size;                                                                     |     |
        unsigned int i;                                                                  |     |
                                                                                         |     |
    #if defined(CONFIG_ARM)                                                              |     |
        fep->rx_align = 0xf;                                                             |     |
        fep->tx_align = 0xf;                                                             |     |
    #else                                                                                |     |
        fep->rx_align = 0x3;                                                             |     |
        fep->tx_align = 0x3;                                                             |     |
    #endif                                                                               |     |
                                                                                         |     |
        fec_enet_alloc_queue(ndev);                                                      |     |
                                                                                         |     |
        if (fep->bufdesc_ex)                                                             |     |
            fep->bufdesc_size = sizeof(struct bufdesc_ex);                               |     |
        else                                                                             |     |
            fep->bufdesc_size = sizeof(struct bufdesc);                                  |     |
        bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *                  |     |
                fep->bufdesc_size;                                                       |     |
                                                                                         |     |
        /* Allocate memory for buffer descriptors. */                                    |     |
        cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,                            |     |
                          GFP_KERNEL);                                                   |     |
        if (!cbd_base) {                                                                 |     |
            return -ENOMEM;                                                              |     |
        }                                                                                |     |
                                                                                         |     |
        memset(cbd_base, 0, bd_size);                                                    |     |
                                                                                         |     |
        /* Get the Ethernet address */                                                   |     |
        fec_get_mac(ndev);                                                               |     |
        /* make sure MAC we just acquired is programmed into the hw */                   |     |
        fec_set_mac_address(ndev, NULL);                                                 |     |
                                                                                         |     |
        /* Set receive and transmit descriptor base. */                                  |     |
        for (i = 0; i < fep->num_rx_queues; i++) {                                       |     |
            rxq = fep->rx_queue[i];                                                      |     |
            rxq->index = i;                                                              |     |
            rxq->rx_bd_base = (struct bufdesc *)cbd_base;                                |     |
            rxq->bd_dma = bd_dma;                                                        |     |
            if (fep->bufdesc_ex) {                                                       |     |
                bd_dma += sizeof(struct bufdesc_ex) * rxq->rx_ring_size;                 |     |
                cbd_base = (struct bufdesc *)                                            |     |
                    (((struct bufdesc_ex *)cbd_base) + rxq->rx_ring_size);               |     |
            } else {                                                                     |     |
                bd_dma += sizeof(struct bufdesc) * rxq->rx_ring_size;                    |     |
                cbd_base += rxq->rx_ring_size;                                           |     |
            }                                                                            |     |
        }                                                                                |     |
                                                                                         |     |
        for (i = 0; i < fep->num_tx_queues; i++) {                                       |     |
            txq = fep->tx_queue[i];                                                      |     |
            txq->index = i;                                                              |     |
            txq->tx_bd_base = (struct bufdesc *)cbd_base;                                |     |
            txq->bd_dma = bd_dma;                                                        |     |
            if (fep->bufdesc_ex) {                                                       |     |
                bd_dma += sizeof(struct bufdesc_ex) * txq->tx_ring_size;                 |     |
                cbd_base = (struct bufdesc *)                                            |     |
                 (((struct bufdesc_ex *)cbd_base) + txq->tx_ring_size);                  |     |
            } else {                                                                     |     |
                bd_dma += sizeof(struct bufdesc) * txq->tx_ring_size;                    |     |
                cbd_base += txq->tx_ring_size;                                           |     |
            }                                                                            |     |
        }                                                                                |     |
                                                                                         |     |
                                                                                         |     |
        /* The FEC Ethernet specific entries in the device structure */                  |     |
        ndev->watchdog_timeo = TX_TIMEOUT;                                               |     |
        ndev->netdev_ops = &fec_netdev_ops;               ----------------------+        |     |
        ndev->ethtool_ops = &fec_enet_ethtool_ops;                              |        |     |
                                                                                |        |     |
        writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);                    |        |     |
        netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);   |        |     |
                                                                                |        |     |
        if (fep->quirks & FEC_QUIRK_HAS_VLAN)                                   |        |     |
            /* enable hw VLAN support */                                        |        |     |
            ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;                          |        |     |
                                                                                |        |     |
        if (fep->quirks & FEC_QUIRK_HAS_CSUM) {                                 |        |     |
            ndev->gso_max_segs = FEC_MAX_TSO_SEGS;                              |        |     |
                                                                                |        |     |
            /* enable hw accelerator */                                         |        |     |
            ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM              |        |     |
                    | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO);               |        |     |
            fep->csum_flags |= FLAG_RX_CSUM_ENABLED;                            |        |     |
        }                                                                       |        |     |
                                                                                |        |     |
        if (fep->quirks & FEC_QUIRK_HAS_AVB) {                                  |        |     |
            fep->tx_align = 0;                                                  |        |     |
            fep->rx_align = 0x3f;                                               |        |     |
        }                                                                       |        |     |
                                                                                |        |     |
        ndev->hw_features = ndev->features;                                     |        |     |
                                                                                |        |     |
        fec_restart(ndev);                                                      |        |     |
                                                                                |        |     |
        return 0;                                                               |        |     |
    }                                                                           |        |     |
                                                                                |        |     |
    static const struct net_device_ops fec_netdev_ops = {         <-------------+        |     |
        .ndo_open        = fec_enet_open,                         --------------+        |     |
        .ndo_stop        = fec_enet_close,                                      |        |     |
        .ndo_start_xmit        = fec_enet_start_xmit,                           |        |     |
        .ndo_select_queue       = fec_enet_select_queue,                        |        |     |
        .ndo_set_rx_mode    = set_multicast_list,                               |        |     |
        .ndo_change_mtu        = eth_change_mtu,                                |        |     |
        .ndo_validate_addr    = eth_validate_addr,                              |        |     |
        .ndo_tx_timeout        = fec_timeout,                                   |        |     |
        .ndo_set_mac_address    = fec_set_mac_address,                          |        |     |
        .ndo_do_ioctl        = fec_enet_ioctl,                                  |        |     |
    #ifdef CONFIG_NET_POLL_CONTROLLER                                           |        |     |
        .ndo_poll_controller    = fec_poll_controller,                          |        |     |
    #endif                                                                      |        |     |
        .ndo_set_features    = fec_set_features,                                |        |     |
    };                                                                          |        |     |
                                                                                |        |     |
    static int                                                                  |        |     |
    fec_enet_open(struct net_device *ndev)                       <--------------+        |     |
    {                                                                                    |     |
        struct fec_enet_private *fep = netdev_priv(ndev);                                |     |
        const struct platform_device_id *id_entry =                                      |     |
                    platform_get_device_id(fep->pdev);                                   |     |
        int ret;                                                                         |     |
                                                                                         |     |
        pinctrl_pm_select_default_state(&fep->pdev->dev);                                |     |
        ret = fec_enet_clk_enable(ndev, true);                                           |     |
        if (ret)                                                                         |     |
            return ret;                                                                  |     |
                                                                                         |     |
        /* I should reset the ring buffers here, but I don't yet know                    |     |
         * a simple way to do that.                                                      |     |
         */                                                                              |     |
                                                                                         |     |
        ret = fec_enet_alloc_buffers(ndev);                                              |     |
        if (ret)                                                                         |     |
            goto err_enet_alloc;                                                         |     |
                                                                                         |     |
        /* Init MAC firstly for suspend/resume with megafix off case */                  |     |
        fec_restart(ndev);                                                               |     |
                                                                                         |     |
        /* Probe and connect to PHY when open the interface */                           |     |
        ret = fec_enet_mii_probe(ndev);                  ---------------------+          |     |
        if (ret)                                                              |          |     |
            goto err_enet_mii_probe;                                          |          |     |
                                                                              |          |     |
        napi_enable(&fep->napi);                                              |          |     |
        phy_start(fep->phy_dev);                                              |          |     |
        netif_tx_start_all_queues(ndev);                                      |          |     |
                                                                              |          |     |
        pm_runtime_get_sync(ndev->dev.parent);                                |          |     |
        if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) &&               |          |     |
            !fec_enet_irq_workaround(fep))                                    |          |     |
            pm_qos_add_request(&ndev->pm_qos_req,                             |          |     |
                       PM_QOS_CPU_DMA_LATENCY,                                |          |     |
                       0);                                                    |          |     |
        else                                                                  |          |     |
            pm_qos_add_request(&ndev->pm_qos_req,                             |          |     |
                       PM_QOS_CPU_DMA_LATENCY,                                |          |     |
                       PM_QOS_DEFAULT_VALUE);                                 |          |     |
                                                                              |          |     |
        device_set_wakeup_enable(&ndev->dev, fep->wol_flag &                  |          |     |
                     FEC_WOL_FLAG_ENABLE);                                    |          |     |
        fep->miibus_up_failed = false;                                        |          |     |
                                                                              |          |     |
        return 0;                                                             |          |     |
                                                                              |          |     |
    err_enet_mii_probe:                                                       |          |     |
        fec_enet_free_buffers(ndev);                                          |          |     |
    err_enet_alloc:                                                           |          |     |
        fep->miibus_up_failed = true;                                         |          |     |
        if (!fep->mii_bus_share)                                              |          |     |
            pinctrl_pm_select_sleep_state(&fep->pdev->dev);                   |          |     |
        return ret;                                                           |          |     |
    }                                                                         |          |     |
                                                                              |          |     |
    static int fec_enet_mii_probe(struct net_device *ndev)         <----------+          |     |
    {                                                                                    |     |
        struct fec_enet_private *fep = netdev_priv(ndev);                                |     |
        struct phy_device *phy_dev = NULL;                                               |     |
        char mdio_bus_id[MII_BUS_ID_SIZE];                                               |     |
        char phy_name[MII_BUS_ID_SIZE + 3];                                              |     |
        int phy_id;                                                                      |     |
        int dev_id = fep->dev_id;                                                        |     |
                                                                                         |     |
        fep->phy_dev = NULL;                                                             |     |
                                                                                         |     |
        if (fep->phy_node) {                                                             |     |
            phy_dev = of_phy_connect(ndev, fep->phy_node,                                |     |
                         &fec_enet_adjust_link, 0,                                       |     |
                         fep->phy_interface);                                            |     |
            if (!phy_dev)                                                                |     |
                return -ENODEV;                                                          |     |
        } else {                                                                         |     |
            /* check for attached phy */                                                 |     |
            for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {                        |     |
                if ((fep->mii_bus->phy_mask & (1 << phy_id)))                            |     |
                    continue;                                                            |     |
                if (fep->mii_bus->phy_map[phy_id] == NULL)                               |     |
                    continue;                                                            |     |
                if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)                          |     |
                    continue;                                                            |     |
                if (dev_id--)                                                            |     |
                    continue;                                                            |     |
                strlcpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);                 |     |
                break;                                                                   |     |
            }                                                                            |     |
                                                                                         |     |
            if (phy_id >= PHY_MAX_ADDR) {                                                |     |
                netdev_info(ndev, "no PHY, assuming direct connection to switch
    ");     |     |
                strlcpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);                        |     |
                phy_id = 0;                                                              |     |
            }                                                                            |     |
                                                                                         |     |
            snprintf(phy_name, sizeof(phy_name),                                         |     |
                 PHY_ID_FMT, mdio_bus_id, phy_id);                                       |     |
            phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,                 |     |
                          fep->phy_interface);                                           |     |
        }                                                                                |     |
                                                                                         |     |
        if (IS_ERR(phy_dev)) {                                                           |     |
            netdev_err(ndev, "could not attach to PHY
    ");                               |     |
            return PTR_ERR(phy_dev);                                                     |     |
        }                                                                                |     |
                                                                                         |     |
        /* mask with MAC supported features */                                           |     |
        //if (fep->quirks & FEC_QUIRK_HAS_GBIT) {             <--------------------------+     |
            //phy_dev->supported &= PHY_GBIT_FEATURES;                                         |
            //phy_dev->supported &= ~SUPPORTED_1000baseT_Half;                                 |
            //printk("FEC_QUIRK_HAS_GBIT
    ");                                                  |
    #if !defined(CONFIG_M5272)                                                                 |
            //phy_dev->supported |= SUPPORTED_Pause;                                           |
    #endif                                                                                     |
        //}                                                                                    |
        //else                                                                                 |
        {                                                                                      |
            printk("PHY_BASIC_FEATURES
    ");                                                    |
            phy_dev->supported &= PHY_BASIC_FEATURES;                                          |
        }                                                                                      |
        phy_dev->advertising = phy_dev->supported;                                             |
                                                                                               |
        fep->phy_dev = phy_dev;                                                                |
        fep->link = 0;                                                                         |
        fep->full_duplex = 0;                                                                  |
                                                                                               |
        netdev_info(ndev, "Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)
    ",     |
                fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),                         |
                fep->phy_dev->irq);                                                            |
                                                                                               |
        return 0;                                                                              |
    }                                                                                          |
                                                                                               |
    static int fec_enet_mii_init(struct platform_device *pdev)              <------------------+
    {
        static struct mii_bus *fec0_mii_bus;
        static int *fec_mii_bus_share;
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct device_node *node;
        int err = -ENXIO, i;
        u32 mii_speed, holdtime;
    
        /*
         * The dual fec interfaces are not equivalent with enet-mac.
         * Here are the differences:
         *
         *  - fec0 supports MII & RMII modes while fec1 only supports RMII
         *  - fec0 acts as the 1588 time master while fec1 is slave
         *  - external phys can only be configured by fec0
         *
         * That is to say fec1 can not work independently. It only works
         * when fec0 is working. The reason behind this design is that the
         * second interface is added primarily for Switch mode.
         *
         * Because of the last point above, both phys are attached on fec0
         * mdio interface in board design, and need to be configured by
         * fec0 mii_bus.
         */
        if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
            /* fec1 uses fec0 mii_bus */
            if (mii_cnt && fec0_mii_bus) {
                fep->mii_bus = fec0_mii_bus;
                *fec_mii_bus_share = FEC0_MII_BUS_SHARE_TRUE;
                mii_cnt++;
                return 0;
            }
            return -ENOENT;
        }
    
        fep->mii_timeout = 0;
    
        /*
         * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
         *
         * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
         * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'.  The i.MX28
         * Reference Manual has an error on this, and gets fixed on i.MX6Q
         * document.
         */
        mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
        if (fep->quirks & FEC_QUIRK_ENET_MAC)
            mii_speed--;
        if (mii_speed > 63) {
            dev_err(&pdev->dev,
                "fec clock (%lu) to fast to get right mii speed
    ",
                clk_get_rate(fep->clk_ipg));
            err = -EINVAL;
            goto err_out;
        }
    
        /*
         * The i.MX28 and i.MX6 types have another filed in the MSCR (aka
         * MII_SPEED) register that defines the MDIO output hold time. Earlier
         * versions are RAZ there, so just ignore the difference and write the
         * register always.
         * The minimal hold time according to IEE802.3 (clause 22) is 10 ns.
         * HOLDTIME + 1 is the number of clk cycles the fec is holding the
         * output.
         * The HOLDTIME bitfield takes values between 0 and 7 (inclusive).
         * Given that ceil(clkrate / 5000000) <= 64, the calculation for
         * holdtime cannot result in a value greater than 3.
         */
        holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
    
        fep->phy_speed = mii_speed << 1 | holdtime << 8;
    
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
    
        fep->mii_bus = mdiobus_alloc();
        if (fep->mii_bus == NULL) {
            err = -ENOMEM;
            goto err_out;
        }
    
        fep->mii_bus->name = "fec_enet_mii_bus";
        fep->mii_bus->read = fec_enet_mdio_read;
        fep->mii_bus->write = fec_enet_mdio_write;
        snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
            pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
        fep->mii_bus->parent = &pdev->dev;
    
        fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
        if (!fep->mii_bus->irq) {
            err = -ENOMEM;
            goto err_out_free_mdiobus;
        }
    
        for (i = 0; i < PHY_MAX_ADDR; i++)
            fep->mii_bus->irq[i] = PHY_POLL;
    
        node = of_get_child_by_name(pdev->dev.of_node, "mdio");
        if (node) {
            err = of_mdiobus_register(fep->mii_bus, node);
            of_node_put(node);
        } else {
            err = mdiobus_register(fep->mii_bus);
        }
    
        if (err)
            goto err_out_free_mdio_irq;
    
        mii_cnt++;
    
        /* save fec0 mii_bus */
        if (fep->quirks & FEC_QUIRK_ENET_MAC) {
            fec0_mii_bus = fep->mii_bus;
            fec_mii_bus_share = &fep->mii_bus_share;
        }
    
        return 0;
    
    err_out_free_mdio_irq:
        kfree(fep->mii_bus->irq);
    err_out_free_mdiobus:
        mdiobus_free(fep->mii_bus);
    err_out:
        return err;
    }
  • 相关阅读:
    gym 101064 G.The Declaration of Independence (主席树)
    hdu 4348 To the moon (主席树 区间更新)
    bzoj 4552 [Tjoi2016&Heoi2016]排序 (二分答案 线段树)
    ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)
    hdu 4417 Super Mario (主席树)
    poj 2236 Wireless Network (并查集)
    查看 scala 中的变量数据类型
    彻底搞定Maven
    Spark :【error】System memory 259522560 must be at least 471859200 Error initializing SparkContext.
    ip地址、子网掩码、网关与网卡、DNS的区别及用处
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/6670618.html
Copyright © 2020-2023  润新知