1.4 px30驱动移植-网卡驱动找不到网卡解决

文章目录

写在前面

移植瑞芯微px30 网卡RTL8363的时候,不能识别到网卡 日志打印No found PHY, 前面的硬件确认无误之后,调试代码 ,最后发现源码有一点小问题,结论为

int __mdiobus_register(struct mii_bus *bus, struct module *owner)
                        struct phy_device *phydev;
                    phydev <span class="token operator">=</span> <span class="token function">mdiobus_scan</span><span class="token punctuation">(</span>bus<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>

- if (IS_ERR(phydev)) {
+ // fix BUG
+ if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {
err = PTR_ERR(phydev);
goto error;
}

按以前的源码会报错直接走goto err了,我看新的kernel版本判断条件变了,更改之后,解决,相应源码分析如下

一、源码分析

当设备中匹配到相应的gmac之后,调用rk_gmac_probe函数

static const struct of_device_id rk_gmac_dwmac_match[] = {
	{ .compatible = "rockchip,px30-gmac",	.data = &px30_ops   },
	{ .compatible = "rockchip,rk1808-gmac", .data = &rk1808_ops },
	{ .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
	{ .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
	{ .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
	{ .compatible = "rockchip,rk3308-mac",  .data = &rk3308_ops },
	{ .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
	{ .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
	{ .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
	{ .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
	{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
	{ }
};
MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
static int rk_gmac_probe(struct platform_device *pdev)
{
	struct plat_stmmacenet_data *plat_dat;
	struct stmmac_resources stmmac_res;
	const struct rk_gmac_ops *data;
	int ret;
data <span class="token operator">=</span> <span class="token function">of_device_get_match_data</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>pdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>data<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">dev_err</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>pdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">,</span> <span class="token string">"no of match data provided\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>EINVAL<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

ret <span class="token operator">=</span> <span class="token function">stmmac_get_platform_resources</span><span class="token punctuation">(</span>pdev<span class="token punctuation">,</span> <span class="token operator">&amp;</span>stmmac_res<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
	<span class="token keyword">return</span> ret<span class="token punctuation">;</span>

plat_dat <span class="token operator">=</span> <span class="token function">stmmac_probe_config_dt</span><span class="token punctuation">(</span>pdev<span class="token punctuation">,</span> <span class="token operator">&amp;</span>stmmac_res<span class="token punctuation">.</span>mac<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>plat_dat<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token function">PTR_ERR</span><span class="token punctuation">(</span>plat_dat<span class="token punctuation">)</span><span class="token punctuation">;</span>

plat_dat<span class="token operator">-&gt;</span>has_gmac <span class="token operator">=</span> true<span class="token punctuation">;</span>
plat_dat<span class="token operator">-&gt;</span>fix_mac_speed <span class="token operator">=</span> rk_fix_speed<span class="token punctuation">;</span>
plat_dat<span class="token operator">-&gt;</span>get_eth_addr <span class="token operator">=</span> rk_get_eth_addr<span class="token punctuation">;</span>

plat_dat<span class="token operator">-&gt;</span>bsp_priv <span class="token operator">=</span> <span class="token function">rk_gmac_setup</span><span class="token punctuation">(</span>pdev<span class="token punctuation">,</span> plat_dat<span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>plat_dat<span class="token operator">-&gt;</span>bsp_priv<span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token function">PTR_ERR</span><span class="token punctuation">(</span>plat_dat<span class="token operator">-&gt;</span>bsp_priv<span class="token punctuation">)</span><span class="token punctuation">;</span>

ret <span class="token operator">=</span> <span class="token function">rk_gmac_clk_init</span><span class="token punctuation">(</span>plat_dat<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
	<span class="token keyword">return</span> ret<span class="token punctuation">;</span>

ret <span class="token operator">=</span> <span class="token function">rk_gmac_powerup</span><span class="token punctuation">(</span>plat_dat<span class="token operator">-&gt;</span>bsp_priv<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
	<span class="token keyword">return</span> ret<span class="token punctuation">;</span>
<span class="token comment">//探测函数</span>
ret <span class="token operator">=</span> <span class="token function">stmmac_dvr_probe</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>pdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">,</span> plat_dat<span class="token punctuation">,</span> <span class="token operator">&amp;</span>stmmac_res<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
	<span class="token keyword">goto</span> err_gmac_powerdown<span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

err_gmac_powerdown:
rk_gmac_powerdown(plat_dat->bsp_priv);

<span class="token keyword">return</span> ret<span class="token punctuation">;</span>

}

gmac驱动程序探测

int stmmac_dvr_probe(struct device *device,
		     struct plat_stmmacenet_data *plat_dat,
		     struct stmmac_resources *res)
{
	int ret = 0;
	struct net_device *ndev = NULL;
	struct stmmac_priv *priv;
ndev <span class="token operator">=</span> <span class="token function">alloc_etherdev</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">stmmac_priv</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>ndev<span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>ENOMEM<span class="token punctuation">;</span>

<span class="token function">SET_NETDEV_DEV</span><span class="token punctuation">(</span>ndev<span class="token punctuation">,</span> device<span class="token punctuation">)</span><span class="token punctuation">;</span>

priv <span class="token operator">=</span> <span class="token function">netdev_priv</span><span class="token punctuation">(</span>ndev<span class="token punctuation">)</span><span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>device <span class="token operator">=</span> device<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>dev <span class="token operator">=</span> ndev<span class="token punctuation">;</span>

<span class="token function">stmmac_set_ethtool_ops</span><span class="token punctuation">(</span>ndev<span class="token punctuation">)</span><span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>pause <span class="token operator">=</span> pause<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>plat <span class="token operator">=</span> plat_dat<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>ioaddr <span class="token operator">=</span> res<span class="token operator">-&gt;</span>addr<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>dev<span class="token operator">-&gt;</span>base_addr <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span><span class="token punctuation">)</span>res<span class="token operator">-&gt;</span>addr<span class="token punctuation">;</span>

priv<span class="token operator">-&gt;</span>dev<span class="token operator">-&gt;</span>irq <span class="token operator">=</span> res<span class="token operator">-&gt;</span>irq<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>wol_irq <span class="token operator">=</span> res<span class="token operator">-&gt;</span>wol_irq<span class="token punctuation">;</span>
priv<span class="token operator">-&gt;</span>lpi_irq <span class="token operator">=</span> res<span class="token operator">-&gt;</span>lpi_irq<span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token operator">-&gt;</span>mac<span class="token punctuation">)</span>
	<span class="token function">memcpy</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>dev<span class="token operator">-&gt;</span>dev_addr<span class="token punctuation">,</span> res<span class="token operator">-&gt;</span>mac<span class="token punctuation">,</span> ETH_ALEN<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">dev_set_drvdata</span><span class="token punctuation">(</span>device<span class="token punctuation">,</span> priv<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Verify driver arguments */</span>
<span class="token function">stmmac_verify_args</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Override with kernel parameters if supplied XXX CRS XXX
 * this needs to have multiple instances
 */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>phyaddr <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>phyaddr <span class="token operator">&lt;=</span> <span class="token number">31</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>phy_addr <span class="token operator">=</span> phyaddr<span class="token punctuation">;</span>

priv<span class="token operator">-&gt;</span>stmmac_clk <span class="token operator">=</span> <span class="token function">devm_clk_get</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>device<span class="token punctuation">,</span> STMMAC_RESOURCE_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_clk<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">dev_warn</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>device<span class="token punctuation">,</span> <span class="token string">"%s: warning: cannot get CSR clock\n"</span><span class="token punctuation">,</span>
		 <span class="token constant">__func__</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">/* If failed to obtain stmmac_clk and specific clk_csr value
	 * is NOT passed from the platform, probe fail.
	 */</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>clk_csr<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		ret <span class="token operator">=</span> <span class="token function">PTR_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_clk<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">goto</span> error_clk_get<span class="token punctuation">;</span>
	<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
		priv<span class="token operator">-&gt;</span>stmmac_clk <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token function">clk_prepare_enable</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_clk<span class="token punctuation">)</span><span class="token punctuation">;</span>

priv<span class="token operator">-&gt;</span>pclk <span class="token operator">=</span> <span class="token function">devm_clk_get</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>device<span class="token punctuation">,</span> <span class="token string">"pclk_mac"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>pclk<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">PTR_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>pclk<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span>EPROBE_DEFER<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		ret <span class="token operator">=</span> <span class="token operator">-</span>EPROBE_DEFER<span class="token punctuation">;</span>
		<span class="token keyword">goto</span> error_pclk_get<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	priv<span class="token operator">-&gt;</span>pclk <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">clk_prepare_enable</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>pclk<span class="token punctuation">)</span><span class="token punctuation">;</span>

priv<span class="token operator">-&gt;</span>stmmac_rst <span class="token operator">=</span> <span class="token function">devm_reset_control_get</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>device<span class="token punctuation">,</span>
					  STMMAC_RESOURCE_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_rst<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">PTR_ERR</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_rst<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span>EPROBE_DEFER<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		ret <span class="token operator">=</span> <span class="token operator">-</span>EPROBE_DEFER<span class="token punctuation">;</span>
		<span class="token keyword">goto</span> error_hw_init<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token function">dev_info</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>device<span class="token punctuation">,</span> <span class="token string">"no reset control found\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	priv<span class="token operator">-&gt;</span>stmmac_rst <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_rst<span class="token punctuation">)</span>
	<span class="token function">reset_control_deassert</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>stmmac_rst<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* Init MAC and get the capabilities */</span>
ret <span class="token operator">=</span> <span class="token function">stmmac_hw_init</span><span class="token punctuation">(</span>priv<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span>
	<span class="token keyword">goto</span> error_hw_init<span class="token punctuation">;</span>

ndev<span class="token operator">-&gt;</span>netdev_ops <span class="token operator">=</span> <span class="token operator">&amp;</span>stmmac_netdev_ops<span class="token punctuation">;</span>

ndev<span class="token operator">-&gt;</span>hw_features <span class="token operator">=</span> NETIF_F_SG <span class="token operator">|</span> NETIF_F_IP_CSUM <span class="token operator">|</span> NETIF_F_IPV6_CSUM <span class="token operator">|</span>
		    NETIF_F_RXCSUM<span class="token punctuation">;</span>
ndev<span class="token operator">-&gt;</span>features <span class="token operator">|=</span> ndev<span class="token operator">-&gt;</span>hw_features <span class="token operator">|</span> NETIF_F_HIGHDMA<span class="token punctuation">;</span>
ndev<span class="token operator">-&gt;</span>watchdog_timeo <span class="token operator">=</span> <span class="token function">msecs_to_jiffies</span><span class="token punctuation">(</span>watchdog<span class="token punctuation">)</span><span class="token punctuation">;</span>

#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);

<span class="token keyword">if</span> <span class="token punctuation">(</span>flow_ctrl<span class="token punctuation">)</span>
	priv<span class="token operator">-&gt;</span>flow_ctrl <span class="token operator">=</span> FLOW_AUTO<span class="token punctuation">;</span>	<span class="token comment">/* RX/TX pause on */</span>

<span class="token comment">/* Rx Watchdog is available in the COREs newer than the 3.40.
 * In some case, for example on bugged HW this feature
 * has to be disable and this can be done by passing the
 * riwt_off field from the platform.
 */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>synopsys_id <span class="token operator">&gt;=</span> DWMAC_CORE_3_50<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span><span class="token operator">!</span>priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>riwt_off<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	priv<span class="token operator">-&gt;</span>use_riwt <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
	<span class="token function">pr_info</span><span class="token punctuation">(</span><span class="token string">" Enable RX Mitigation via HW Watchdog Timer\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">netif_napi_add</span><span class="token punctuation">(</span>ndev<span class="token punctuation">,</span> <span class="token operator">&amp;</span>priv<span class="token operator">-&gt;</span>napi<span class="token punctuation">,</span> stmmac_poll<span class="token punctuation">,</span> <span class="token number">64</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">mutex_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>priv<span class="token operator">-&gt;</span>lock<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">spin_lock_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>priv<span class="token operator">-&gt;</span>tx_lock<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">/* If a specific clk_csr value is passed from the platform
 * this means that the CSR Clock Range selection cannot be
 * changed at run-time and it is fixed. Viceversa the driver'll try to
 * set the MDC clock dynamically according to the csr actual
 * clock input.
 */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>clk_csr<span class="token punctuation">)</span>
	<span class="token function">stmmac_clk_csr_set</span><span class="token punctuation">(</span>priv<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
	priv<span class="token operator">-&gt;</span>clk_csr <span class="token operator">=</span> priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>clk_csr<span class="token punctuation">;</span>

<span class="token function">stmmac_check_pcs_mode</span><span class="token punctuation">(</span>priv<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>pcs <span class="token operator">!=</span> STMMAC_PCS_RGMII <span class="token operator">&amp;&amp;</span> priv<span class="token operator">-&gt;</span>pcs <span class="token operator">!=</span> STMMAC_PCS_TBI <span class="token operator">&amp;&amp;</span>
    priv<span class="token operator">-&gt;</span>pcs <span class="token operator">!=</span> STMMAC_PCS_RTBI<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token comment">/* MDIO bus Registration */</span>
	<span class="token comment">//注册mdio总线</span>
	ret <span class="token operator">=</span> <span class="token function">stmmac_mdio_register</span><span class="token punctuation">(</span>ndev<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">//rtk_switch_reg1b03();</span>

	<span class="token keyword">if</span> <span class="token punctuation">(</span>ret <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token function">pr_debug</span><span class="token punctuation">(</span><span class="token string">"%s: MDIO bus (id: %d) registration failed"</span><span class="token punctuation">,</span>
			 <span class="token constant">__func__</span><span class="token punctuation">,</span> priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>bus_id<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">goto</span> error_mdio_register<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

ret <span class="token operator">=</span> <span class="token function">register_netdev</span><span class="token punctuation">(</span>ndev<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">netdev_err</span><span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>dev<span class="token punctuation">,</span> <span class="token string">"%s: ERROR %i registering the device\n"</span><span class="token punctuation">,</span>
		   <span class="token constant">__func__</span><span class="token punctuation">,</span> ret<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">goto</span> error_netdev_register<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> ret<span class="token punctuation">;</span>

error_netdev_register:
if (priv->pcs != STMMAC_PCS_RGMII &&
priv->pcs != STMMAC_PCS_TBI &&
priv->pcs != STMMAC_PCS_RTBI)
stmmac_mdio_unregister(ndev);
error_mdio_register:
netif_napi_del(&priv->napi);
error_hw_init:
clk_disable_unprepare(priv->pclk);
error_pclk_get:
clk_disable_unprepare(priv->stmmac_clk);
error_clk_get:
free_netdev(ndev);

<span class="token keyword">return</span> ret<span class="token punctuation">;</span>

}
EXPORT_SYMBOL_GPL(stmmac_dvr_probe);

mdio总线注册函数

int stmmac_mdio_register(struct net_device *ndev)
{
	int err = 0;
	struct mii_bus *new_bus;
	int *irqlist;
	struct stmmac_priv *priv = netdev_priv(ndev);
	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
	int addr, found;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mdio_bus_data<span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

rtl8761_bus<span class="token operator">=</span>new_bus<span class="token punctuation">;</span>

new_bus <span class="token operator">=</span> <span class="token function">mdiobus_alloc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>new_bus <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>ENOMEM<span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>mdio_bus_data<span class="token operator">-&gt;</span>irqs<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	irqlist <span class="token operator">=</span> mdio_bus_data<span class="token operator">-&gt;</span>irqs<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span>addr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> addr <span class="token operator">&lt;</span> PHY_MAX_ADDR<span class="token punctuation">;</span> addr<span class="token operator">++</span><span class="token punctuation">)</span>
		priv<span class="token operator">-&gt;</span>mii_irq<span class="token punctuation">[</span>addr<span class="token punctuation">]</span> <span class="token operator">=</span> PHY_POLL<span class="token punctuation">;</span>
	irqlist <span class="token operator">=</span> priv<span class="token operator">-&gt;</span>mii_irq<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

#ifdef CONFIG_OF
if (priv->device->of_node)
mdio_bus_data->reset_gpio = -1;
#endif

new_bus<span class="token operator">-&gt;</span>name <span class="token operator">=</span> <span class="token string">"stmmac"</span><span class="token punctuation">;</span>
<span class="token comment">//mdio的读写函数</span>
new_bus<span class="token operator">-&gt;</span>read <span class="token operator">=</span> <span class="token operator">&amp;</span>stmmac_mdio_read<span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>write <span class="token operator">=</span> <span class="token operator">&amp;</span>stmmac_mdio_write<span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>reset <span class="token operator">=</span> <span class="token operator">&amp;</span>stmmac_mdio_reset<span class="token punctuation">;</span>
<span class="token function">snprintf</span><span class="token punctuation">(</span>new_bus<span class="token operator">-&gt;</span>id<span class="token punctuation">,</span> MII_BUS_ID_SIZE<span class="token punctuation">,</span> <span class="token string">"%s-%x"</span><span class="token punctuation">,</span>
	 new_bus<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>bus_id<span class="token punctuation">)</span><span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>priv <span class="token operator">=</span> ndev<span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>irq <span class="token operator">=</span> irqlist<span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>phy_mask <span class="token operator">=</span> mdio_bus_data<span class="token operator">-&gt;</span>phy_mask<span class="token punctuation">;</span>
new_bus<span class="token operator">-&gt;</span>parent <span class="token operator">=</span> priv<span class="token operator">-&gt;</span>device<span class="token punctuation">;</span>	
<span class="token comment">//注册mdio总线</span>
err <span class="token operator">=</span> <span class="token function">mdiobus_register</span><span class="token punctuation">(</span>new_bus<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>err <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">pr_err</span><span class="token punctuation">(</span><span class="token string">"%s: Cannot register as MDIO bus\n"</span><span class="token punctuation">,</span> new_bus<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">goto</span> bus_register_fail<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

found <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>addr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> addr <span class="token operator">&lt;</span> PHY_MAX_ADDR<span class="token punctuation">;</span> addr<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token keyword">struct</span> <span class="token class-name">phy_device</span> <span class="token operator">*</span>phydev <span class="token operator">=</span> new_bus<span class="token operator">-&gt;</span>phy_map<span class="token punctuation">[</span>addr<span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>phydev<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">int</span> act <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
		<span class="token keyword">char</span> irq_num<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
		<span class="token keyword">char</span> <span class="token operator">*</span>irq_str<span class="token punctuation">;</span>

		<span class="token comment">/*
		 * If an IRQ was provided to be assigned after
		 * the bus probe, do it here.
		 */</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>mdio_bus_data<span class="token operator">-&gt;</span>irqs <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
		    <span class="token punctuation">(</span>mdio_bus_data<span class="token operator">-&gt;</span>probed_phy_irq <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			irqlist<span class="token punctuation">[</span>addr<span class="token punctuation">]</span> <span class="token operator">=</span> mdio_bus_data<span class="token operator">-&gt;</span>probed_phy_irq<span class="token punctuation">;</span>
			phydev<span class="token operator">-&gt;</span>irq <span class="token operator">=</span> mdio_bus_data<span class="token operator">-&gt;</span>probed_phy_irq<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>

		<span class="token comment">/*
		 * If we're going to bind the MAC to this PHY bus,
		 * and no PHY number was provided to the MAC,
		 * use the one probed here.
		 */</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>phy_addr <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
			priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>phy_addr <span class="token operator">=</span> addr<span class="token punctuation">;</span>

		act <span class="token operator">=</span> <span class="token punctuation">(</span>priv<span class="token operator">-&gt;</span>plat<span class="token operator">-&gt;</span>phy_addr <span class="token operator">==</span> addr<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">switch</span> <span class="token punctuation">(</span>phydev<span class="token operator">-&gt;</span>irq<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">case</span> PHY_POLL<span class="token operator">:</span>
			irq_str <span class="token operator">=</span> <span class="token string">"POLL"</span><span class="token punctuation">;</span>
			<span class="token keyword">break</span><span class="token punctuation">;</span>
		<span class="token keyword">case</span> PHY_IGNORE_INTERRUPT<span class="token operator">:</span>
			irq_str <span class="token operator">=</span> <span class="token string">"IGNORE"</span><span class="token punctuation">;</span>
			<span class="token keyword">break</span><span class="token punctuation">;</span>
		<span class="token keyword">default</span><span class="token operator">:</span>
			<span class="token function">sprintf</span><span class="token punctuation">(</span>irq_num<span class="token punctuation">,</span> <span class="token string">"%d"</span><span class="token punctuation">,</span> phydev<span class="token operator">-&gt;</span>irq<span class="token punctuation">)</span><span class="token punctuation">;</span>
			irq_str <span class="token operator">=</span> irq_num<span class="token punctuation">;</span>
			<span class="token keyword">break</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token function">pr_info</span><span class="token punctuation">(</span><span class="token string">"%s: PHY ID %08x at %d IRQ %s (%s)%s\n"</span><span class="token punctuation">,</span>
			ndev<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> phydev<span class="token operator">-&gt;</span>phy_id<span class="token punctuation">,</span> addr<span class="token punctuation">,</span>
			irq_str<span class="token punctuation">,</span> <span class="token function">dev_name</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>phydev<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">,</span>
			act <span class="token operator">?</span> <span class="token string">" active"</span> <span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		found <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>found<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">pr_warn</span><span class="token punctuation">(</span><span class="token string">"%s: No PHY found\n"</span><span class="token punctuation">,</span> ndev<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">mdiobus_unregister</span><span class="token punctuation">(</span>new_bus<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">mdiobus_free</span><span class="token punctuation">(</span>new_bus<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>ENODEV<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

priv<span class="token operator">-&gt;</span>mii <span class="token operator">=</span> new_bus<span class="token punctuation">;</span>
rtl8761_bus<span class="token operator">=</span>new_bus<span class="token punctuation">;</span> 
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

bus_register_fail:
mdiobus_free(new_bus);
return err;
}

#define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE)

  
  
  • 1

主要是将扫描到的设备加入到mdio_bus上做管理

int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
	int i, err;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">NULL</span> <span class="token operator">==</span> bus <span class="token operator">||</span> <span class="token constant">NULL</span> <span class="token operator">==</span> bus<span class="token operator">-&gt;</span>name <span class="token operator">||</span>
    <span class="token constant">NULL</span> <span class="token operator">==</span> bus<span class="token operator">-&gt;</span>read <span class="token operator">||</span> <span class="token constant">NULL</span> <span class="token operator">==</span> bus<span class="token operator">-&gt;</span>write<span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>EINVAL<span class="token punctuation">;</span>

<span class="token function">BUG_ON</span><span class="token punctuation">(</span>bus<span class="token operator">-&gt;</span>state <span class="token operator">!=</span> MDIOBUS_ALLOCATED <span class="token operator">&amp;&amp;</span>
       bus<span class="token operator">-&gt;</span>state <span class="token operator">!=</span> MDIOBUS_UNREGISTERED<span class="token punctuation">)</span><span class="token punctuation">;</span>

bus<span class="token operator">-&gt;</span>owner <span class="token operator">=</span> owner<span class="token punctuation">;</span>
bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">.</span>parent <span class="token operator">=</span> bus<span class="token operator">-&gt;</span>parent<span class="token punctuation">;</span>
bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">.</span>class <span class="token operator">=</span> <span class="token operator">&amp;</span>mdio_bus_class<span class="token punctuation">;</span>
bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">.</span>groups <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token function">dev_set_name</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">,</span> <span class="token string">"%s"</span><span class="token punctuation">,</span> bus<span class="token operator">-&gt;</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>

err <span class="token operator">=</span> <span class="token function">device_register</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token function">pr_err</span><span class="token punctuation">(</span><span class="token string">"mii_bus %s failed to register\n"</span><span class="token punctuation">,</span> bus<span class="token operator">-&gt;</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">put_device</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>bus<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token operator">-</span>EINVAL<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">mutex_init</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>bus<span class="token operator">-&gt;</span>mdio_lock<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>bus<span class="token operator">-&gt;</span>reset<span class="token punctuation">)</span>
	bus<span class="token operator">-&gt;</span><span class="token function">reset</span><span class="token punctuation">(</span>bus<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> PHY_MAX_ADDR<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>bus<span class="token operator">-&gt;</span>phy_mask <span class="token operator">&amp;</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">&lt;&lt;</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
		<span class="token keyword">struct</span> <span class="token class-name">phy_device</span> <span class="token operator">*</span>phydev<span class="token punctuation">;</span>
		<span class="token comment">//扫描设备,将扫描到的设备加入到phy_map</span>
		phydev <span class="token operator">=</span> <span class="token function">mdiobus_scan</span><span class="token punctuation">(</span>bus<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">IS_ERR</span><span class="token punctuation">(</span>phydev<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span><span class="token function">PTR_ERR</span><span class="token punctuation">(</span>phydev<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token operator">-</span>ENODEV<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
			err <span class="token operator">=</span> <span class="token function">PTR_ERR</span><span class="token punctuation">(</span>phydev<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">goto</span> error<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

bus<span class="token operator">-&gt;</span>state <span class="token operator">=</span> MDIOBUS_REGISTERED<span class="token punctuation">;</span>
<span class="token function">pr_info</span><span class="token punctuation">(</span><span class="token string">"%s: probed\n"</span><span class="token punctuation">,</span> bus<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

error:
while (i >= 0) {
struct phy_device *phydev = bus->phy_map[i];
if (phydev) {
phy_device_remove(phydev);
phy_device_free(phydev);
}
}
device_del(&bus->dev);
return err;
}

通过mdio总线得到phy设备id

struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{
	struct phy_c45_device_ids c45_ids = {0};
	u32 phy_id = 0;
	int r;
   //通过mdio接口读取硬件的phy id ,判断掩码有没有设置忽略.
	r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
	if (r)
		return ERR_PTR(r);
<span class="token comment">/* If the phy_id is mostly Fs, there is no device there */</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>phy_id <span class="token operator">&amp;</span> <span class="token number">0x1fffffff</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0x1fffffff</span><span class="token punctuation">)</span>
	<span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>ENODEV<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">phy_device_create</span><span class="token punctuation">(</span>bus<span class="token punctuation">,</span> addr<span class="token punctuation">,</span> phy_id<span class="token punctuation">,</span> is_c45<span class="token punctuation">,</span> <span class="token operator">&amp;</span>c45_ids<span class="token punctuation">)</span><span class="token punctuation">;</span>

}
EXPORT_SYMBOL(get_phy_device);

static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
		      bool is_c45, struct phy_c45_device_ids *c45_ids)
{
	int phy_reg;
	if (is_c45)
		return get_phy_c45_ids(bus, addr, phy_id, c45_ids);
	/* Grab the bits from PHYIR1, and put them in the upper half */
	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
	if (phy_reg < 0)
		return -EIO;

*phy_id = (phy_reg & 0xffff) << 16;

<span class="token comment">/* Grab the bits from PHYIR2, and put them in the lower half */</span>

// 通过mdio总线读取设备id
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
return -EIO;

<span class="token operator">*</span>phy_id <span class="token operator">|=</span> <span class="token punctuation">(</span>phy_reg <span class="token operator">&amp;</span> <span class="token number">0xffff</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

最终还是使用mdio_bus提供的函数去读取PHY芯片寄存器地址

int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{
	int retval;
	BUG_ON(in_interrupt());
	mutex_lock(&bus->mdio_lock);
	retval = bus->read(bus, addr, regnum);
	mutex_unlock(&bus->mdio_lock);

return retval;
}
EXPORT_SYMBOL(mdiobus_read);

            </div><div data-report-view="{&quot;mod&quot;:&quot;1585297308_001&quot;,&quot;spm&quot;:&quot;1001.2101.3001.6548&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/weixin_34799243/article/details/123953920&quot;,&quot;extend1&quot;:&quot;pc&quot;,&quot;ab&quot;:&quot;new&quot;}"><div></div></div>
            <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-22a2fefd3b.css" rel="stylesheet">
            <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-4f8fbf9108.css" rel="stylesheet">
    </div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值